#!/usr/bin/env python2.7
'''
Created on Aug 25, 2011

@author: Stephen Reichling <sreichling@chegg.com>
@author: Joshua Richardson <jric@chegg.com>
'''

import fontforge
import sys
import os

PROG = "singleFont.py"

## {{{ http://code.activestate.com/recipes/577564/ (r2)
class Silence:
    def __init__(self, stdout=os.devnull, stderr=os.devnull, mode='w'):
        self.outfiles = stdout, stderr
        self.combine = (stdout == stderr)
        self.mode = mode
 
    def __enter__(self):
        import sys
        self.sys = sys
        # save previous stdout/stderr
        self.saved_streams = saved_streams = sys.__stdout__, sys.__stderr__
        self.fds = fds = [s.fileno() for s in saved_streams]
        self.saved_fds = map(os.dup, fds)
        # flush any pending output
        for s in saved_streams: s.flush()
 
        # open surrogate files
        if self.combine: 
            null_streams = [open(self.outfiles[0], self.mode, 0)] * 2
            if self.outfiles[0] != os.devnull:
                # disable buffering so output is merged immediately
                sys.stdout, sys.stderr = map(os.fdopen, fds, ['w']*2, [0]*2)
        else: null_streams = [open(f, self.mode, 0) for f in self.outfiles]
        self.null_fds = null_fds = [s.fileno() for s in null_streams]
        self.null_streams = null_streams
 
        # overwrite file objects and low-level file descriptors
        map(os.dup2, null_fds, fds)
 
    def __exit__(self, *args):
        sys = self.sys
        # flush any pending output
        for s in self.saved_streams: s.flush()
        # restore original streams and file descriptors
        map(os.dup2, self.saved_fds, self.fds)
        sys.stdout, sys.stderr = self.saved_streams
        # clean up
        for s in self.null_streams: s.close()
        return False
## end of http://code.activestate.com/recipes/577564/ }}}

#Apply Font Metrics
def importAFM(directory, name, fontFile):
    afmFilename = name + '.afm'
    if os.path.isfile(directory + afmFilename):
        with open(directory + afmFilename, 'r') as afmFile:        
            entry = afmFile.readline()
           
            while entry:
                entry = entry.strip('\n')
                nameToValue = entry.split()       
                try:  
                    if nameToValue[0] == 'Ascender':
                        pass
                        #Need to find correct ascent value to chance
                        #fontFile.hhea_ascent_add = int(nameToValue[1])
                        #fontFile.os2_winascent = int(nameToValue[1])
                    elif nameToValue[0] == 'Descender':
                        pass
                        #Need to find correct descent value to change
                        #fontFile.hhea_descent_add = int(nameToValue[1])
                        #fontFile.os2_windescent = int(nameToValue[1])
                except TypeError, IndexError:
                    print >> sys.stderr, 'Invalid Font Metric: \"' + entry + '\"'
               
                entry = afmFile.readline()
        return 0
    else:
        return 1
    
#Apply Unicode Mappings
def importNAM(directory, name, fontFile):
    namFilename = name + '.nam'
    namEmpty = 1
    if os.path.isfile(directory + namFilename):
        uniMap = {}
        with open(directory + namFilename, 'r') as namFile:                  
            entry = namFile.readline()
            while entry:
                if namEmpty:
                    namEmpty = 0
                entry = entry.strip('\n')
                unicodeToName = entry.split()
                try:
                    uniMap[unicodeToName[1]] = int(unicodeToName[0], 16)
                except IndexError, TypeError:
                    print >> sys.stderr, 'Invalid Unicode Mapping: \"' + entry + '\"'
                entry = namFile.readline()
                  
        for glyph in fontFile.glyphs():
            glyphName = glyph.glyphname
            if glyphName in uniMap:
                glyph.unicode = uniMap[glyphName]
        if namEmpty:
            return 2
        return 0
    else:
        return 1

#Generate Font Files in Web Browser compatible formats    
def generateFonts(directory, name, fontFile):
    if not os.path.isfile(directory + name + '.woff'):
        fontFile.generate(directory + name + '.woff')
#    else:
#        print >> sys.stderr, "singleFont: INFO: already exists: " + directory + name + '.woff'
    if not os.path.isfile(directory + name + '.eot'):
        fontFile.generate(directory + name + '.eot')
#    else:
#        print >> sys.stderr, "singleFont: INFO: already exists: " + directory + name + '.eot'
    if not os.path.isfile(directory + name + '.otf'):
        fontFile.generate(directory + name + '.otf')
#    else:
#        print >> sys.stderr, "singleFont: INFO: already exists: " + directory + name + '.ttf'
    if not os.path.isfile(directory + name + '.svg'):
        fontFile.generate(directory + name + '.svg')
    if not os.path.isfile(directory + name + '.ttf'):
        fontFile.generate(directory + name + '.ttf')
        
def main():
    global PROG
    fontDir = sys.argv[1]
    sourceFontsDir = sys.argv[2]
    fontName = sys.argv[3]
    fontExten = sys.argv[4]  
            
    #Allow unicode mapping in the Private Use Area in fontforge
    fontforge.setPrefs('RecognizePUANames', True)
    
    if sourceFontsDir[-1] != '/':
        sourceFontsDir += '/'
    if fontDir[-1] != '/':
        fontDir += '/'
    
    fontFile = None
    
    try:
        with Silence(): #prevent fontforge from complaining about each font's every perceived imperfection
            fontFile = fontforge.open(sourceFontsDir + fontName +  fontExten)
    except EnvironmentError:
        print >> sys.stderr, "\n" + PROG + ": ERROR: Unable to open " + \
            sourceFontsDir + fontName +  fontExten
        return 1
    

    if importAFM(sourceFontsDir, fontName, fontFile):
        print >> sys.stderr, "\n" + PROG + ": WARN: No Font Metrics found for "\
            + fontName
        
    # For 8-bit fonts, we should always have a nam file with unicode mappings
    status = importNAM(sourceFontsDir, fontName, fontFile)
    if status == 1:
        print >> sys.stderr, "\n" + PROG + \
            ": WARN: No Unicode Mappings found for " + fontName + \
            "; I pray it's a CID font"
    elif status == 2:
        print >> sys.stderr, "\n" + PROG + \
            ": ERROR: Unicode mapping table empty for " + fontName
        return 2
                  
    generateFonts(fontDir, fontName, fontFile)
    
    fontFile.close()
    
if __name__ == "__main__":
    main()
