#!/usr/bin/python
#
# Console fonts for Urwid BigText
#    Copyright (C) 2007  Florian Festi
#
#    This library is free software; you can redistribute it and/or
#    modify it under the terms of the GNU Lesser General Public
#    License as published by the Free Software Foundation; either
#    version 2.1 of the License, or (at your option) any later version.
#
#    This library 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
#    Lesser General Public License for more details.
#
#    You should have received a copy of the GNU Lesser General Public
#    License along with this library; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Urwid web site: http://excess.org/urwid/

import gzip
import sys
sys.path[0:0] = ['/home/str/ffesti/CVS/urwid/trunk']

from urwid.util import apply_target_encoding
from urwid.canvas import Canvas

# see http://www.win.tue.nl/~aeb/linux/kbd/font-formats.html

class Font:

    # mirrored - currently unused
    halfblocks2 = (u" " # empty
                  u"\u2596" # up left
                  u"\u259D" # up right
                  u"\u2580" # up
                  u"\u2596" # down left
                  u"\u258C" # left
                  u"\u259E" # down left, up right
                  u"\u259B" # up, down left
                  u"\u2597" # down right
                  u"\u259A" # up left, down right                  
                  u"\u2590" # right                  
                  u"\u259C" # up, down right
                  u"\u2584" # down
                  u"\u2599" # down, up left
                  u"\u259F" # down, up right
                  u"\u2588" # full
                  )

    halfblocks = (u" " # empty
                  u"\u259D" # up right
                  u"\u2598" # up left
                  u"\u2580" # up
                  u"\u2597" # down right
                  u"\u2590" # right    
                  u"\u259A" # up left, down right
                  u"\u259C" # up, down right
                  u"\u2596" # down left
                  u"\u259E" # down left, up right
                  u"\u258C" # left
                  u"\u259B" # up, down left
                  u"\u2584" # down
                  u"\u259F" # down, up right                  
                  u"\u2599" # down, up left
                  u"\u2588" # full
                  )

    # ascii replacements for quarter blocks/ currently in a bad shape...
    halfblocks_ascii = (
                  u" " # empty
                  u"'" # up right
                  u"'" # up left
                  u"\"" # up
                  u"," # down right
                  u")" # right    
                  u"\\" # up left, down right
                  u"9" # up, down right
                  u"," # down left
                  u"/" # down left, up right
                  u"l" # left
                  u"P" # up, down left
                  u"m" # down
                  u"d" # down, up right
                  u"b" # down, up left
                  u"M" # full
                  )

    modenames = ("256 characters, no directory",
                 "512 characters, no directory",
                 "256 characters, Unicode directory",
                 "512 characters, Unicode directory",)

    def __init__(self, filename, mode='half', ascii=False):
        """Load linux console font for use as text graphic
        Does currently only support PSF 1 (.psfu.gz). Font files
        without unicode map are still untested
        mode : 'full', 'half', 'quarter'
        """

        if filename.endswith('.gz'):
            self.content = gzip.open(filename).read()
        else:
            self.content = open(filename).read()

        if ord(self.content[0]) != 0x36 or \
               ord(self.content[1]) != 0x04:
            print ord(self.content[0]), ord(self.content[1])
            raise ValueError, "Not a PFS 1 file"

        if ascii:
            self.halfblocks = self.halfblocks_ascii

        self.utf8_required = not ascii

        self.mode = ord(self.content[2])
        if (self.mode & 1):
            self.length = 512
        else:
            self.length = 256

        self.height = ord(self.content[3])

        self._generateChars(mode)

        if (self.mode & 0x2):
            self._generateUnicodeMap()
        else:
            self._generateCharMap()

        if mode in ('half', 'quarter'):
            self.height = (self.height+1) / 2
        
    def __str__(self):
        return "<%s %s, 8x%d>" % (self.__class__.__name__,
                                 self.modenames[self.mode],
                                 self.height)

    def characters(self):
        chars = self.chars.keys()
        chars.sort()
        return "".join(chars)

    def char_width(self, c):
        if self.chars.has_key(c):
            return len(self.chars[c][0])
        return 0                                    

    def char_data(self, c):
        return self.chars[c]

    def render(self, c):
        l = self.chars[c]
        width = len(l[0])
        tl = []
        csl = []
        for d in l:
            t, cs = apply_target_encoding(d)
            tl.append(t)
            csl.append(cs)        
        return Canvas(tl, None, csl, maxcol=width, check_width=False )

    def _generateChars(self, mode):
        if mode == "half":
            mapfunc = self._getCharmap_half
        elif mode == "full":
            mapfunc = self._getCharmap_full
        elif mode == "quarter":
            mapfunc = self._getCharmap_quarter
        else:
            raise ValueError, "Unknown font mode"
            
        self.char_map = []
        for idx in range(self.length):
            self.char_map.append(mapfunc(idx))

    def _getCharmap_full(self, nr):
        start = 4 + nr*self.height
        result = []
        for idx in range(start, start+self.height):
            line = [] 
            c = ord(self.content[idx])
            for bit in range(8):
                mask = 1 << (7-bit)
                if c & mask:
                    line.append(self.halfblocks[15])
                else:
                    line.append(self.halfblocks[0])
            result.append(u''.join(line))
        return result

    def _getCharmap_half(self, nr):
        start = 4 + nr*self.height
        result = []
        for idx in range(start, start+self.height, 2):
            line = [] 
            c1 = ord(self.content[idx])
            c2 = ord(self.content[idx+1])

            for bit in range(8):
                b1 = (c1 >> (7-bit)) & 0x1
                b2 = (c2 >> (7-bit)) & 0x1
                b1 |= b1 << 1
                b2 |= b2 << 1
                char  = b1 | (b2 << 2)
                line.append(self.halfblocks[char])

            result.append(u''.join(line))
        return result
        

    def _getCharmap_quarter(self, nr):
        start = 4 + nr*self.height
        result = []
        for idx in range(start, start+self.height, 2):
            line = [] 
            c1 = ord(self.content[idx])
            c2 = ord(self.content[idx+1])

            for bit in range(4):
                b1 = (c1 >> ((3-bit)*2)) & 0x3
                b2 = (c2 >> ((3-bit)*2)) & 0x3
                char  = b1 + (b2 << 2)
                line.append(self.halfblocks[char])

            result.append(u''.join(line))
        return result
            
    def _generateUnicodeMap(self):
        self.chars = {}
        idx = 4+self.length*self.height
        cont = self.content
        char_idx = 0
        while idx < len(self.content):
            uni = ord(cont[idx]) + (ord(cont[idx+1]) << 8)
            idx += 2
            if uni == 0xFFFF:
                char_idx += 1
            elif uni == 0xFFFE:
                raise ValueError, "Don't support sequences yet"
            else:
                self.chars[unichr(uni)] = self.char_map[char_idx]

    def _generateCharMap(self):
        # untested
        self.chars = {}
        for idx in xrange(self.length):
            self.chars[chr(idx)] = self.char_map[idx]

def main():
    import codecs

    utf8 = codecs.getencoder("utf8")

    font = Font('/lib/kbd/consolefonts/lat1-12.psfu.gz', 'quarter', True)
    #font = Font('/lib/kbd/consolefonts/lat0-08.psfu.gz', 'half', True)
    #font = Font('/lib/kbd/consolefonts/latarcyrheb-sun16.psfu.gz', 'half')
    print utf8(font.characters())[0]
    #print font.characters()
    
if __name__ =='__main__':
    main()

