"""Generate Cython interface for C code to form a condensed problem with vector
parameters.
"""

import os

from muaompc._ldt.codegen.former.cvp.codegen import CCodeGenerator as CCG


class CythonCodeGenerator(CCG, object):

    """Generate Cython code to interface with C code of a condensed QP.

    This class overrides the following methods:
    generate_code: generates cython specific code on its own directory
    _make_destination_dir_tree: creates cython own directory
    """

    def __init__(self, ccg):
        """Assign to self cvp, prefix, path attributes from the given C code.

        This depends on C-code already being generated by C-code
        generation class. This creates the interface to that specific code.

        :param ccg: an instance of the C code generator class for which
        a Cython interface is to be created
        :type ccg: muaompc._ldt.codegen.former.cvp.codegen.CCodeGenerator
        """
        self.cvp = ccg.cvp
        self.prefix = ccg.prefix
        self.path = ccg.path

    def generate_code(self):
        self._make_destination_dir_tree()
        self._generate_cython_code()

    def _make_destination_dir_tree(self):
        try:
            os.mkdir(os.path.join(self.path['dest'], 'cython'))
        except OSError:
            pass

    def _generate_cython_code(self):
        self._replace_prefix('cvpsetup.py', srcdir='cython')
        self._replace_prefix('cvp.pyx', srcdir='cython')
        self._write_Cpxi_file('Ccvp.pxi')
        self._write_Cpxd_file('Ccvp.pxd')
        self._write_Cpyx_file('Ccvp.pyx')

    def _get_def_flags(self):
        flags = self.cvp._get_flags()
        fmt = ''
        for name, flag in flags.items():
            fmt += 'DEF CVP_PRB_%s = %s\n' % (name.upper(), flag)
        return fmt

    def _write_Cpxi_file(self, fname):
        def_flags = self._get_def_flags()
        d = dict(prefix=self.prefix,
                PREFIX=self.prefix.upper(),
                def_flags=def_flags)
        self._replace_dict(d, self.prefix, fname, srcdir='cython')

    def _write_Cpxd_file(self, fname):
        par_inds = self._get_enum_terms_c_tmpl(self.cvp.par, ntabs=2)
        prb_terms = self._get_prb_terms_cy_tmpl()
        prb_terms += self._get_prb_socc_terms_cy_tmpl()
        d = dict(prefix=self.prefix,
                PREFIX=self.prefix.upper(),
                prb_terms=prb_terms,
                par_inds=par_inds)
        self._replace_dict(d, self.prefix, fname, srcdir='cython')

    def _write_Cpyx_file(self, fname):
        pardat_py2c = self._get_pardata_py2c()
        prb_c2py = self._get_prb_c2py()
        prb_c2py += self._get_prb_socc_c2py()
        d = dict(prefix=self.prefix,
                prb_c2py=prb_c2py,
                pardata_py2c=pardat_py2c)
        self._replace_dict(d, self.prefix, fname, srcdir='cython')

    def _get_prb_terms_cy_tmpl(self):
        ntab = 2
        tab = '    '
        tabs = ntab * tab
        fmt = ''
        for term_name in self.cvp._get_prb_terms():
            term = '%s_term *%s' % (self.prefix, term_name)
            fmt += tabs+'%s\n' % (term)
        return fmt

    def _get_prb_socc_terms_cy_tmpl(self):
        ntab = 2
        tab = '    '
        tabs = ntab * tab
        fmt = ''
        if len(self.cvp.soccs.struct['uppers']) != 0:
            fmt += tabs+'int *socc_num\n'
            fmt += tabs+'%s_cvp_prb_socc **socc;\n' % (self.prefix)
        return fmt

    def _get_pardata_py2c(self):
        def _pardata_py2c(key, name):
            tab = '    '
            t = 1 * tab
            idx = (self.prefix+'_'+name).upper()
            f = '_py2c_term(ccvp.%s[Ccvp.%s], pardata["%s"])\n' % (
                    key, idx, name)
            return t + f
        s = ''
        for name in self.cvp.par:
            s += _pardata_py2c('par', name)
        return s

    def _get_prb_c2py(self):
        tab = '    '
        tabs = 1 * tab
        fmt = ''
        for term_name in self.cvp._get_prb_terms():
            term_lhs = "prb['%s']" % (term_name)
            term_rhs = "_c2py_term(cprb.%s)\n" % (term_name)
            fmt += tabs+('%s = %s') % (term_lhs, term_rhs)
        return fmt

    def _get_prb_socc_c2py(self):
        ntab = 1
        tab = '    '
        tabs = ntab * tab
        fmt = ''
        if len(self.cvp.soccs.struct['uppers']) != 0:
            term_lhs = "prb['%s']" % ('socc')
            term_rhs = '_c2py_socc(cprb)\n'
            fmt += tabs+'%s = %s' % (term_lhs, term_rhs)
        return fmt


    def _install_module(self):
        pass


