# this file is part of mftrace - a tool to generate scalable fonts from bitmaps  
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc.,
#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 

# Copyright (c)  2001--2006 by
#  Han-Wen Nienhuys, Jan Nieuwenhuizen

import sys

def compose_tfm_number (seq):
    shift = (len (seq)-1)*8

    cs = 0
    for b in seq:
        cs = cs  + (int (b) << shift)
        shift = shift - 8
    return cs

#
#
# Read params, ligatures, kernings. 
#
#
class Tfm_reader:
    def get_string (self):
        b = self.left[0]
        s = (self.left[1:1 + b]).decode('ascii')
        self.left = self.left[1+b:]
        
        return s
    def get_byte (self):
        b = self.left [0]
        self.left= self.left[1:]
        return b

    def extract_fixps (self, count):
        fs = [0.0] * count
        
        for c in range (0,count):
            fs[c]  = self.get_fixp_number ()

        return fs

    def extract_chars (self):
        count = self.end_code - self.start_code + 1
        fs = [None] * count
        
        for c in range (0,count):
            w = self.get_byte()
            b = self.get_byte()
            h = (b & 0xf0) >> 4
            d = (b & 0x0f)

            b = self.get_byte ()
            i = (b & 0xfc) >> 2
            tag = (b & 0x3)

            rem = self.get_byte ()

            # rem is used as index for the ligature table.
            # TODO.
            lig = None
            
            fs[c] = (w, h, d, i, lig)
            
        return fs

    def get_ligatures(self):
        return None
    def get_kern_program (self):
        return None
    
    def __init__ (self, f):
        self.left = f

        self.file_length = self.get_number (2);
        self.head_length = self.get_number (2);
        self.start_code =  self.get_number (2);
        self.end_code =  self.get_number (2);
        self.width_count = self.get_number (2);
        self.height_count =self.get_number(2);
        self.depth_count = self.get_number (2);
        self.italic_corr_count = self.get_number(2);
        self.ligature_kern_count = self.get_number (2);
        self.kern_count = self.get_number (2)
        self.extensible_word_count =self.get_number (2);
        self.parameter_count =self.get_number (2);
        
        self.checksum = self.get_number (4)
        self.design_size = self.get_fixp_number ()
        if self.head_length > 2:
            self.coding = self.get_string ()
        else:
            self.coding = 'UNKNOWN'

        self.left =f[(6 + self.head_length) * 4:]
        self.chars = self.extract_chars ()
        self.widths = self.extract_fixps (self.width_count)
        self.heights = self.extract_fixps (self.height_count)
        self.depths = self.extract_fixps (self.depth_count)
        self.italic_corrections = self.extract_fixps (self.italic_corr_count)
        self.ligatures = self.get_ligatures ()
        self.kern_program = self.get_kern_program()

        del self.left

    def get_number (self, len):
        n = compose_tfm_number (self.left [0:len])
        self.left = self.left[len:]
        return n

    def get_fixp_number (self):
        n = self.get_number (4)
        n = n /16.0 / (1<<16);
        
        return n

    def get_tfm (self):
        keys  = ['start_code', 'end_code', 'checksum', 'design_size', 'coding', 'chars', 'widths', 'heights', 'depths', 'italic_corrections', 'ligatures', 'kern_program']
        tfm = Tex_font_metric ()
        for k in keys:
            tfm.__dict__[k] = self.__dict__[k]
        return tfm



class Char_metric:
    def __init__(self, tfm, tup):
        (w, h, d, i, lig) = tup
        ds = tfm.design_size
        self.width = tfm.widths[w] *ds 
        self.height = tfm.heights[h] *ds
        self.depth = tfm.depths [d] * ds
        self.italic_correction = tfm.italic_corrections[i]*ds
        
        

class Tex_font_metric:
    """
    Bare bones wrapper around the TFM format.
    """
    
    
    def __init__ (self):
        pass
    
    def has_char (self, code):
        if code < self.start_code or code > self.end_code:
            return 0
        
        tup = self.chars[code - self.start_code]
        return tup[0] != 0
    
    def get_char (self,code):
        tup = self.chars[code - self.start_code]
        return Char_metric (self, tup)

    def __str__ (self):
        return r"""#<TFM file
char: %d, %d
checksum: %d
design_size: %f
coding: %s>""" % (self.start_code, self.end_code,
        self.checksum, self.design_size, self.coding)



def read_tfm_file (fn):
    reader =Tfm_reader (open (fn, 'rb').read ())
    return reader.get_tfm ()

if __name__=='__main__':
    t = read_tfm_file  (sys.argv[1])
    print(t, t.design_size,  t.coding)

