import Image
from xml.dom import minidom
import os
import math

def _open_xml(path):
    file = open(path, "r")
    font_doc = minidom.parse(file)
    del file
    return font_doc


class point:
    def __init__(self, x, y):
        self.dx = x
        self.dy = y
        
    def distSq(self):
        return self.dx * self.dx + self.dy * self.dy
        
    def copy(self):
        return point(self.dx, self.dy)

def compare(g, p, x, y, offsetX, offsetY):
    other = g.get(x + offsetX, y + offsetY)
    other.dx += offsetX
    other.dy += offsetY
    
    if other.distSq() < p.distSq():
        return other
    
    return p

    
class grid:
    def __init__(self, w, h):
        self.data = [None for x in range(w) for y in range(h)]
        self.w = w
        self.h = h

    def put(self, x, y, val):
        self.data[x + y * self.w] = val#.copy()
        
    def get(self, x, y):
        if x < 0 or y < 0:
            return point(9999, 9999)
        if x >= self.w or y >= self.h:
            return point(9999, 9999)
        return self.data[x + y * self.w].copy()

def generateSD_pass(g):
    print("generateSD_pass...")
    get = g.get
    put = g.put
    
    w = g.w
    h = g.h
    cmp = compare
    
    xr = xrange
    
    for y in xr(h):
        for x in xr(w):    
            p = get(x, y)
            p = cmp(g, p, x, y, -1, 0)
            p = cmp(g, p, x, y, 0, -1)
            p = cmp(g, p, x, y, -1, -1)
            p = cmp(g, p, x, y, 1, -1)
            
            put(x, y, p)
            
        for x in xr(w - 1, -1, -1):
            p = get(x, y)
            p = cmp(g, p, x, y, 1, 0)
            put(x, y, p)
            
    for y in xr(h - 1, -1, -1):
        for x in xr(w-1, -1, -1):    
            p = get(x, y)
            p = cmp(g, p, x, y, 1, 0)
            p = cmp(g, p, x, y, 0, 1)
            p = cmp(g, p, x, y, -1, 1)
            p = cmp(g, p, x, y, 1, 1)
            
            put(x, y, p)
            
        for x in xr(w):
            p = get(x, y)
            p = cmp(g, p, x, y, 1, 0)
            put(x, y, p)    

def generateSD(image):
    w = image.size[0]
    h = image.size[1]
    g = grid(w, h)

    grid1 = grid(w, h)
    grid2 = grid(w, h)

    data = image.load()
    getpixel = image.im.getpixel
    g1put = grid1.put
    g2put = grid2.put

    pZero = point(0,0)
    pInf = point(9999,9999)
    
    for y in range(h):
        for x in range(w):
            alpha = getpixel((x, y))[3]
            if alpha < 128:
                g1put(x, y, pZero)
                g2put(x, y, pInf)
            else:
                g1put(x, y, pInf)
                g2put(x, y, pZero)
                
                
    generateSD_pass(grid1)
    generateSD_pass(grid2)
    
    
    sd_image = Image.new("L", (w, h))
    data = sd_image.getdata()
    
    putpixel = sd_image.im.putpixel
    
    for y in range(h):
        for x in range(w):    
            dist1 = int(math.sqrt(grid1.get(x, y).distSq()))
            dist2 = int(math.sqrt(grid2.get(x, y).distSq()))
            dist = dist1 - dist2
            dist = dist * 10
            dist += 128
            #dist = dist * 3 + 128
            if dist < 0:
                dist = 0
            if dist > 255:
                dist = 255
            putpixel((x,y), dist)
            
    return sd_image

def downscaleAttr(el, attr, ds):
    v = el.getAttribute(attr)
    el.setAttribute(attr, str(int(v)/ds))
    
def convert(args):
    xml_doc = _open_xml(args.bmfont)
    xml = xml_doc.documentElement
    
    folder, file = os.path.split(args.bmfont)
    if folder:
        folder += "/"
    pages = xml.getElementsByTagName("pages")[0].getElementsByTagName("page")

    downscale = args.scale
    for page in pages:
    
        image_file_name = page.getAttribute("file")            
    
        image = Image.open(folder + image_file_name)
        image.load()    
        
        #image = image.crop((0,0, 256, 256))
        
        w = image.size[0]
        h = image.size[1]
        
        sd_image = generateSD(image)
        sd_image = sd_image.resize((w/downscale, h/downscale), Image.ANTIALIAS)
        
        sd_image_name = "sd_" + image_file_name
        sd_image.save(folder + sd_image_name, "PNG")    
        
        page.setAttribute("file", sd_image_name)
        
    info_el = xml.getElementsByTagName("info")[0]
    downscaleAttr(info_el, "size", downscale)
    common_el = xml.getElementsByTagName("common")[0]
    downscaleAttr(common_el, "lineHeight", downscale)
    downscaleAttr(common_el, "base", downscale)
    downscaleAttr(common_el, "scaleW", downscale)
    downscaleAttr(common_el, "scaleH", downscale)
        
    new_font_xml = folder + "sd_" + file
    fileh= open(new_font_xml, "w")
    xml_doc.writexml(fileh)
    
    

if __name__ == "__main__": 
    import os   
    import sys
    
    folder = os.path.split(os.path.abspath(__file__))[0] + "\\src"  
    sys.path.append(folder)
    
    #print sys.path
    
    import argparse	
    parser = argparse.ArgumentParser(description="convert xml bmfont to signed distance font")
    
    parser.add_argument("bmfont", help="src font")
    parser.add_argument("-s", "--scale", help = "scale factor", type=int, default = 1)
    
    
    import xml_processor

    args = parser.parse_args()
    convert(args)
    #p = xml_processor.XmlProcessor(args)
    #p.process()
    
    