# ImgDk2Game.py
# IMG_DK* file to GAME convert
import re
import os
import time
import Image
import ImageOps
import ImageDraw
import ImageFont

# support libraries
import _util
from satname import satname, satfulname

# PIL font dir (This may vary)
fntdir = '/Users/tkikuchi/lib/pilfonts/'
ttfdir = '/Users/tkikuchi/lib/ttfonts/'

# Utility functions for IMG file header
def skipheader(fi):
    while 1:
        a = fi.read(1)
        b = ord(fi.read(1))*256 + ord(fi.read(1))
        c = fi.read(b-3)
        if ord(a) == 132:
            break

def readtype(fi):
    type = ord(fi.read(1))
    bytes = ord(fi.read(1))*256 + ord(fi.read(1))
    content = fi.read(bytes-3)
    return type, bytes, content

def int4(s):
    x = 0
    for i in s:
        x = x * 256 + ord(i)
    return x

# create credit image
def credit(text, 
           font=('Lucida Sans Demibold Roman.ttf', 11),
           textcolor=(255,255,63), bgcolor=(0,0,95)):
    if type(font) == type(tuple()):
        font_path = os.path.join(ttfdir, font[0])
        imgfnt = ImageFont.truetype(font_path, font[1])
    else:
        font_path = os.path.join(fntdir, font)
        imgfnt = ImageFont.load_path(font_path)
    size = imgfnt.getsize(text)
    size = size[0] + 4, size[1] + 4
    img = Image.new('RGB',size , bgcolor)
    drw = ImageDraw.Draw(img)
    drw.text((2,2), text, font=imgfnt, fill= textcolor)
    return img

def datecredit(text):
    return credit(text, font=('Lucida Sans Demibold Roman.ttf', 11),
                  textcolor=(0,0,0), bgcolor=(255,255,255))

# add color by uv
def add_color(bwimg, uvimg, gamma=1.0):
    uvdata = uvimg.tostring()
    bwdata = bwimg.tostring()
    cldata = _util.adduv(bwdata, uvdata, gamma)
    climg = Image.fromstring('RGB', bwimg.size, cldata)
    return climg


class ImgDk2Game:

    def __init__(self, imgdkfname):
        self.files = [f for f in os.listdir('.') if f.startswith(imgdkfname)]
        self.gmt = time.strptime(imgdkfname[12:22], '%Y%m%d%H')
        self.obstart = time.mktime(self.gmt) + 9*60*60
        self.nomtime = time.gmtime(self.obstart + 3600) # 1hour
        self.nomjtime = time.localtime(self.obstart + 3600)
        self.nomjst  = time.strftime('%y%m%d%H', 
                           time.localtime(self.obstart + 3600))
        self.ch = imgdkfname[8:11]
        # self.ch holds IRx or VIS
        if self.ch == 'VIS':
            self.lines = 11000
            self.block = 1100
        else:
            self.lines = 2750
            self.block = 275
        self.prep()



    def getnav(self, fi):
        # skip #0,#1 header
        type, bytes, content = readtype(fi)
        type, bytes, content = readtype(fi)
        type, bytes, content = readtype(fi)
        assert type == 2
        sub_lon = re.match(r'GEOS\((.*)\)', content).group(1)
        self.sub_lon = float(sub_lon)
        self.CFAC = float(int4(content[32:36]))/(2**16)
        self.LFAC = float(int4(content[36:40]))/(2**16)
        self.COFF = int4(content[40:44])
        self.LOFF = int4(content[44:48])
        sl = int(round(self.sub_lon))
        if sl == 140:
            self.satname = 'MT1R'
            self.satfulname = 'MTSAT-1R'
        elif sl == 145:
            self.satname = 'MTS2'
            self.satfulname = 'MTSAT-2'
        else:
            self.satname = 'XNON'
            self.satfulname = 'XNONAME'

    def toraw8(self):
        # convert 10bit data to 8bit
        filebase = self.files[0][:-2]
        rawdata = []
        for i in range(10):
            try:
                fi = file(filebase + '%02d' % (i+1))
                skipheader(fi)
                origdata = fi.read(self.lines*self.block*2)
                data = _util.ten2eight(origdata)
            except:
                if self.ch == 'VIS':
                    data = '\0' * (self.lines*self.block)
                else:
                    data = '\xff' * (self.lines*self.block)
            rawdata.append(data)
        self.rawdata = ''.join(rawdata)
        #print len(self.rawdata)


    def geotransraw(self, box, size):
        # GEOS conversion (see Data Spec ... JMA, CGMS)
        lon_tl, lat_tl, lon_br, lat_br = box
        width, height = size
        #print lon_tl, lat_tl, lon_br, lat_br, width, height,
        #print self.COFF, self.LOFF, self.CFAC, self.LFAC, self.sub_lon
        oimgdata = _util.geotrans(self.rawdata, self.lines,
                      lon_tl, lat_tl, lon_br, lat_br,
                      width, height,
                      self.COFF, self.LOFF, self.CFAC, self.LFAC,
                      self.sub_lon)
        oimg = Image.new('L', size)
        oimg.putdata(oimgdata)
        return oimg

    def poltransraw(self, offset, size, lambda_0, mag):
        # invert x, y coordinate here. <-- CAUTION!
        y_offset, x_offset = offset
        o_height, o_width  = size
        pimgdata = _util.poltrans(self.rawdata, self.lines,
                       x_offset, y_offset, o_width, o_height,
                       lambda_0, mag,
                       self.COFF, self.LOFF, self.CFAC, self.LFAC, self.sub_lon)
        pimg = Image.new('L', size)
        pimg.putdata(pimgdata)
        return pimg

    def writegame(self, img, box, size):
        # We need add special comments for PGM format file
        lon_tl, lat_tl, lon_br, lat_br = box
        width, height = size
        lat_inc = float(lat_br - lat_tl)/height
        lon_inc = float(lon_br - lon_tl)/width
        fname = self.satname +\
            time.strftime('%y%m%d%H', self.nomtime) +\
            '%s.pgm' % self.ch
        fo = file(fname, 'w')
        print >> fo, """\
P5
#N%dN%dE%dE%d %5.3f %5.3f
%d %d
255""" % (lat_tl, lat_br, lon_tl, lon_br, -lat_inc, lon_inc, size[0], size[1])
        imgdata = list(img.getdata())
        imgstr = ''.join(
                    [chr(imgdata[i]) for i in xrange(img.size[0]*img.size[1])])
        fo.write(imgstr)
        fo.close()
        return fname


    def prep(self):
        # preparation to get raw data
        self.getnav(file(self.files[0]))
        self.toraw8()

    def game(self):
        # Generate GAME data and save
        gameimg = self.geotransraw((70,70,160,-20), (1800,1800))
        return self.writegame(gameimg, (70,70,160,-20), (1800,1800))

    def all(self):
        # Generate ALL data and save
        allimg = self.geotransraw((70,70,210,-70), (560,560))
        return self.writegame(allimg, (70,70,210,-70), (560,560))

    def quicklook(self):
        # create quick look image and save in ql.JST.jpg
        img = Image.new('L', (self.lines, self.lines))
        img.putdata(self.rawdata)
        img = img.resize((550, 550), Image.ANTIALIAS)
        img = ImageOps.expand(img, border=13, fill=255)
        imgdata = img.tostring()
        # get UV
        uvimg = Image.open('qlbg-%d.ppm' % self.sub_lon)
        uvimgdata = uvimg.tostring()
        cldata = _util.adduv(imgdata, uvimgdata, 1.0)
        qlimg = Image.new('RGB', img.size)
        qlimg.fromstring(cldata)
        qlcredit = '%s %s %sJST Kochi Univ' % (
                                       self.satfulname, self.ch, self.nomjst)
        qlimg.paste(credit(qlcredit,
                        font=('Lucida Sans Demibold Roman.ttf', 12),
                        textcolor=(0,0,0), bgcolor=(255,255,255)),
                    (2,2))
        qlname = 'ql.%s.jpg' % self.nomjst
        qlimg.save(qlname)
        return qlname

def untarjmbsc(srcdir, datestr, ch):
    " extract IMG_DK files from jmbsc tar file "
    srcbase = 'Z__C_RJTD_%s????_OBS_SAT_Pir%s_R%%sh_image.tar.gz'
    srcfilename = srcbase % (datestr, ch)
    cmd = 'tar xvzf %s 2>&1' % os.path.join(srcdir, srcfilename % 'n')
    t = os.popen(cmd)
    files1 = t.read().splitlines()
    cmd = 'tar xvzf %s 2>&1' % os.path.join(srcdir, srcfilename % 's')
    t = os.popen(cmd)
    files2 = t.read().splitlines()
    files = [x.split()[-1] for x in files1 + files2]
    return files

if __name__ == '__main__':
    import sys
    files = untarjmbsc('/Users/tkikuchi/work/jmbsc/mtsat/20090217',
                       '2009021723', 3)
    #print files
    g = ImgDk2Game(files[0])
    #g.prep()
    #g.all()
    g.quicklook()

