import sys
import os
import re
import numpy as np
from galry import log_info, log_debug
import re

"""Font atlas tools for loading files generated by AngelCode Bitmap Font
Generator 1.13.

The link is: http://www.angelcode.com/products/bmfont/


"""

__all__ = ["load_png", "load_fnt", "get_text_map", "load_font"]

def find_best_size(font="segoe", size=32):
    """Find the closest font size in the existing font files."""
    filename = font + str(size)
    path = os.path.dirname(os.path.realpath(__file__))
    fnt = os.path.join(path, "%s.fnt" % filename)
    if os.path.exists(fnt):
        return size
    else:
        # we go through all .fnt files
        files = [file for file in os.listdir(path) if file.startswith(font) \
            and file.endswith('.fnt')]
        files.sort()
        # we take the largest existing size that is smaller to the requested
        # size
        newsize = 0
        for file in files:
            m = re.match(font + "([0-9]+)", file)
            if m:
                if int(m.group(1)) > size:
                    break
                newsize = int(m.group(1))
        log_debug("font %s %d does not exist, loading size %d instead" % \
            (font, size, newsize))
        return newsize

def get_font_filenames(font="segoe", size=32):
    """Return the texture and FNT file names."""
    size = find_best_size(font, size)
    filename = font + str(size)
    path = os.path.dirname(os.path.realpath(__file__))
    fnt = os.path.join(path, "%s.fnt" % filename)
    png = os.path.join(path, "%s_0.png" % filename)
    return png, fnt

def load_png(filename):
    """Load a PNG texture."""
    import matplotlib.pyplot as plt
    return plt.imread(filename)
    
def load_fnt(filename):
    """Load a bitmap font file.
    
    Returns:
      * M: an array where each line contains:
            charid, x, y, w, h
        x and y are the top-left coordinates
        w and h are the width and height of the character
    
    """
    pattern = "char id=([0-9]+)[ ]+x=([0-9]+)[ ]+y=([0-9]+)[ ]+width=([0-9]+)[ ]+height=([0-9]+)"

    f = open(filename, "r")

    # look for coordinates and sizes of all characters, along with the 
    # character ASCII indices
    values = []
    for line in f:
        if line.startswith("char "):
            m = re.search(pattern, line)
            if m:
                values.append(m.group(*xrange(1,6)))
    f.close()
    M0 = np.array(values, dtype=np.int32)
    M = np.zeros((M0[:,0].max() + 1, M0.shape[1]), dtype=np.int32)
    M[M0[:,0],:] = M0
    return M

def load_font(font=None, size=None):
    """Load a font and return the texture and map getter function.
    
    Arguments:
      * font: the font name
      * size: the size (if the size does not exist in the font files, a close
        size will be used)
        
    Returns:
      * tex: the texture as a NxMx4 image
      * get_map: a function that takes a string and returns the text map, i.e.
        a matrix where line i contains the position and size of character i in
        that string.
        
    """
    png, fnt = get_font_filenames(font, size)
    matrix = load_fnt(fnt)
    tex = load_png(png)
    texsize = tex.shape[:2]
    get_map = lambda text: get_text_map(text, matrix=matrix)
    # normalize the matrix so that coordinates are in [0,1]
    size = np.array(np.tile(texsize, (1, 2)), dtype=np.float32)
    matrix = np.array(matrix, dtype=np.float32)
    matrix[:,1:] /= size
    return tex, matrix, get_map
    
def get_text_map(text, matrix):#, texsize=None):#, font=None, size=None):
    """Return the text map of a string.
    
    Arguments:
      * text: the text string
      * matrix: the font matrix
      * texsize: the texture size
    
    Returns:
      * matrix: a matrix where line i contains the position and size of
        character i in that string.
    
    """
    chars = map(ord, (text))
    return matrix[chars,1:]
    
