#! /usr/bin/env python

"""
Use python's string.Template to substitute values in various
templated C++ wrappers, as Cython has no support for templates (and fused
types are currently useless).

TODO: is the situation better now?
"""

from string import Template
try:
    from itertools import izip as zip
except ImportError:
    pass
from os.path import join
import os, sys
import errno

def product(*args, **kwds):
    # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
    # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
    pools = list(map(tuple, args)) * kwds.get('repeat', 1)
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    for prod in result:
        yield tuple(prod)

GENERATED_HEADER = Template(
"""\
#################################################
#############       WARNING      ################
#################################################
# This file has been automatically generated.
# Any changes you make here will get overridden.
# Instead, make your changes in ${filename}.pyx
#################################################
""")

def make_templates(full_filename, *args, **kwargs):
    individuals = args or [dict(zip(kwargs, line))
                           for line in product(*kwargs.values())]

    f = open(full_filename)
    template = Template(f.read())
    f.close()

    filename = os.path.basename(full_filename)[:-4]

    plain_name = filename
    for i in individuals[0]:
        plain_name = plain_name.replace(i, '')
    plain_name = plain_name.rstrip('_')
    #print plain_name

    try:
        os.makedirs("include/generated")
    except OSError as exc: # Python >2.5
        if exc.errno != errno.EEXIST or not os.path.isdir("include/generated"):
            raise

    includes = []
    for a in individuals:
        newname = filename
        for i, j in a.items():
            newname = newname.replace(i, j)

        out_filename = join("generated", newname + '.pyx')
        f = open(join("include", out_filename), 'w')
        f.write(GENERATED_HEADER.substitute(filename=filename))
        f.write(template.substitute(**a))
        f.close()
        includes.append(out_filename)

        inc_filename = join("include", plain_name + '.pxi')
        f = open(inc_filename, 'w')
        f.write(GENERATED_HEADER.substitute(filename=filename))
        f.write("\n".join('include "%s"' % i for i in includes))
        f.close()

##############

# fragile, depends on Makefile.am order
bin1d_dbn, bin2d_dbn, axis1d_bin1d_dbn, axis2d_bin2d_dbn = sys.argv[1:]

## Make instantiations of Cython mapping templates for axes with different DBN types
make_templates(bin1d_dbn, DBN=('Dbn1D', 'Dbn2D'))
make_templates(bin2d_dbn, DBN=('Dbn2D', 'Dbn3D'))
make_templates(axis1d_bin1d_dbn, dict(DBN='Dbn1D', BIN1D='HistoBin1D'))
make_templates(axis1d_bin1d_dbn, dict(DBN='Dbn2D', BIN1D='ProfileBin1D'))
make_templates(axis2d_bin2d_dbn, dict(DBN='Dbn2D', BIN2D='HistoBin2D'))
make_templates(axis2d_bin2d_dbn, dict(DBN='Dbn3D', BIN2D='ProfileBin2D'))
