from lcapy.domains import domains
from lcapy.quantities import quantities


units_mapping = {
    '': 'S.One',
    'V': 'uu.volt', 'A': 'uu.ampere',
    'V/Hz': 'uu.volt / uu.Hz',
    'A/Hz': 'uu.ampere / uu.Hz',
    'V/sqrt(Hz)': 'uu.volt / sqrt(uu.Hz)',
    'A/sqrt(Hz)': 'uu.ampere / sqrt(uu.Hz)',
    'ohm': 'uu.ohm',
    'S': 'uu.siemens',
    'ohm/s': 'uu.ohm / uu.s',
    'S/s': 'uu.siemens / uu.s',
    'ohm^2/s^2': '(uu.ohm / uu.s)**2',
    'S^2/s^2': '(uu.siemens / uu.s)**2',
    'V^2': 'uu.volt**2',
    'A^2': 'uu.ampere**2',
    'V^2/Hz^2': '(uu.volt / uu.Hz)**2',
    'A^2/Hz^2': '(uu.ampere / uu.Hz)**2',
    'ohm^2': 'uu.ohm**2', 'S^2': 'uu.siemens**2',
    'W': 'uu.watt', '/s': '1 / uu.s'}


class ClassesMake:

    def __init__(self, domains, quantities, kind):

        self.domains = domains
        self.quantities = quantities
        self.classes = []
        self.all = []
        self.cdict = {}
        # expr or seq
        self.kind = kind

        self.class_suffix = 'Sequence' if kind == 'seq' else ''
        self.baseclass_suffix = 'Sequence' if kind == 'seq' else 'Expression'

    def make(self):

        for domain in self.domains.values():

            if domain.is_superposition_domain:
                continue

            self.cdict[domain.domain] = {}

            self.cdict[domain.domain]['undefined'] = domain.__name__ + \
                self.baseclass_suffix

            for quantity in self.quantities.values():

                class_maker = ClassMake(domain, quantity)

                name, s = class_maker.make(self.class_suffix,
                                           self.baseclass_suffix)
                self.all.append(name)
                self.classes.append(s)

                self.cdict[domain.domain][quantity.quantity] = name

    def write(self):

        filename = self.kind + 'classes.py'
        var = self.kind + 'classes'

        s = '''
# This file is automatically generated by makeclasses.py

from .units import units, u as uu
from .voltagemixin import VoltageMixin
from .currentmixin import CurrentMixin
from .admittancemixin import AdmittanceMixin
from .impedancemixin import ImpedanceMixin
from .transfermixin import TransferMixin
from .voltagesquaredmixin import VoltageSquaredMixin
from .currentsquaredmixin import CurrentSquaredMixin
from .admittancesquaredmixin import AdmittanceSquaredMixin
from .impedancesquaredmixin import ImpedanceSquaredMixin
from .powermixin import PowerMixin
from sympy import sqrt, S'''

        if self.kind == 'expr':
            s += '''
from .cexpr import ConstantDomainExpression
from .cexpr import ConstantTimeDomainExpression
from .cexpr import ConstantFrequencyResponseDomainExpression
from .fexpr import FourierDomainExpression
from .jfexpr import FrequencyResponseDomainExpression
from .jomegaexpr import AngularFrequencyResponseDomainExpression
from .kexpr import DiscreteFourierDomainExpression
from .nexpr import DiscreteTimeDomainExpression
from .noisefexpr import FourierNoiseDomainExpression
from .noiseomegaexpr import AngularFourierNoiseDomainExpression
from .normfexpr import NormFourierDomainExpression
from .normomegaexpr import NormAngularFourierDomainExpression
from .omegaexpr import AngularFourierDomainExpression
from .phasor import PhasorDomainExpression, PhasorRatioDomainExpression
from .sexpr import LaplaceDomainExpression
from .texpr import TimeDomainExpression
from .uexpr import UndefinedDomainExpression
from .zexpr import ZDomainExpression
'''

        if self.kind == 'seq':
            s += '''
from .kseq import DiscreteFourierDomainSequence
from .nseq import DiscreteTimeDomainSequence
from .zseq import ZDomainSequence
'''

        s += '\n__all__ = (' + ', '.join(["'" + name +
                                          "'" for name in self.all]) + ')' + '\n'

        s += ''.join(self.classes)

        s += '\n\n%s = {' % var

        for d, dv in self.cdict.items():
            s += "'" + d + "': {"
            for q, qv in dv.items():
                s += "'" + q + "': " + qv + ',\n'
            s += '}\n,'
        s += '}\n'

        with open(filename, 'wt') as outfile:
            print(s, file=outfile)


class ClassMake:

    def __init__(self, domain, quantity):

        self.domain = domain
        self.quantity = quantity

    def make(self, class_suffix, baseclass_suffix):

        quantity = self.quantity
        domain = self.domain

        quantityunits = quantity.quantity_units

        unitsstring = quantityunits
        if quantity.quantity in ('voltage', 'current'):
            if (domain.is_laplace_domain or
                domain.is_fourier_domain or
                    domain.is_angular_fourier_domain):
                unitsstring = '%s/Hz' % quantityunits
        elif quantity.quantity in ('voltagesquared', 'currentsquared'):
            if (domain.is_laplace_domain or
                domain.is_fourier_domain or
                    domain.is_angular_fourier_domain):
                unitsstring = '%s/Hz^2' % quantityunits
        elif quantity.quantity in ('impedance', 'admittance', 'transfer'):
            if domain.is_time_domain:
                unitsstring = '%s/s' % quantityunits
        elif quantity.quantity in ('admittancesquared', 'impedancesquared'):
            if domain.is_time_domain:
                unitsstring = '%s/s^2' % quantityunits

        classname = domain.__name__ + quantity.quantity.capitalize() + class_suffix
        classname = classname.replace('Transfer', 'TransferFunction')

        baseclassname = domain.__name__ + baseclass_suffix

        # TODO: perhaps rename transfer function in time domain to
        # impulse response?
        docstring = '%s-domain %s (units %s).' % (domain.domain_label,
                                                  quantity.quantity,
                                                  unitsstring)

        s = '''


class %s(%s, %s):
    """%s"""

    _default_units = %s''' % (classname, quantity.__name__, baseclassname,
                              docstring,  units_mapping[unitsstring])

        return classname, s


expr_maker = ClassesMake(domains, quantities, 'expr')
expr_maker.make()
expr_maker.write()

seq_domains = {}
for domain in ['discrete time', 'discrete fourier', 'Z']:
    seq_domains[domain] = domains[domain]

seq_maker = ClassesMake(seq_domains, quantities, 'seq')
seq_maker.make()
seq_maker.write()
