"""Generate Matlab 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 MatlabCodeGenerator(CCG, object):

    """Generate Matlab code to interface with C code of a problem.

    This class overrides the following methods:
    generate_code: generates Matlab specific code on its own directory
    _make_destination_dir_tree: creates Matlab 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 Matlab 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_matlab_code()

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

    def _generate_matlab_code(self):
        include_path = os.path.join('matlab', 'include')
        self._generate_c_body('cvpmatlab', srcdir='matlab', destdir='matlab')
        self._replace_prefix('cvpmatlab.h', srcdir='matlab', destdir=include_path)

    def _generate_c_body(self, fname, srcdir, destdir):
        fname += '.c'
        create_prb = self._get_create_prb_c_tmpl()
        create_parameters = self._get_create_parameters_c_tmpl(self.cvp.par)
        apply_parameters = self._get_apply_parameters_c_tmpl(self.cvp.par)
        d = dict(prefix=self.prefix,
                PREFIX=self.prefix.upper(),
                create_prb=create_prb,
                create_parameters=create_parameters,
                apply_parameters=apply_parameters)
        self._replace_dict(d, self.prefix, fname, srcdir=srcdir, destdir=destdir)

    def _get_create_parameters_c_tmpl(self, terms):
        d = ''
        tab = '    '
        for name in terms:
            idx = (self.prefix+'_'+name).upper()
            assign = '%s_matlab_add_matrix(parameters, "%s", cvp->par[%s]->data,\n' % (self.prefix, name, idx)
            assign += 4*tab + 'cvp->par[%s]->rows, cvp->par[%s]->cols)' % (idx, idx)
            d += 1*tab + assign + ';\n'
        return d

    def _get_apply_parameters_c_tmpl(self, terms):
        d = ''
        tab = '    '
        for name in terms:
            idx = (self.prefix+'_'+name).upper()
            assign = '%s_matlab_read_matrix(parameters, "%s", cvp->par[%s]->data,\n' % (self.prefix, name, idx)
            assign += 4*tab + 'cvp->par[%s]->rows, cvp->par[%s]->cols)' % (idx, idx)
            d += 1*tab + assign + ';\n'
        return d

    def _get_create_prb_c_tmpl(self):
        tab = '    '
        fmt = ''
        for term_name in self.cvp._get_prb_terms():
            assign = '%s_matlab_add_matrix(prb, "%s", cvp->prb->%s->data,\n' % (
                    self.prefix, term_name, term_name)
            assign += 4*tab + 'cvp->prb->%s->rows, cvp->prb->%s->cols)' % (
                    term_name, term_name)
            fmt += 1*tab + assign + ';\n'
        return fmt
