"""

Parameters A:
    Cells:           Simple integrate and fire cells
    Chem Synapses:   Event based, ohmic; one rise & one decay constant
    Gap junctions:   NOT REAL GJs: using event based synapses, generally set to zero conductance

ASSESSMENT:
    Not very useful in longer term; tendency for cells to over excite; difficult to tune networks


We are very aware that:

    C elegans neurons do NOT behave like Integrate & Fire neurons
    Their synapses are NOT like double exponential, conductance based synapses
    Electrical synapses are very different from event triggered, conductance based synapses

The values below are a FIRST APPROXIMATION of neurons for use in a network to
investigate the synaptic connectivity of C elegans

"""

from neuroml import IafCell
from neuroml import ExpTwoSynapse
from neuroml import PulseGenerator

from c302.bioparameters import c302ModelPrototype


class ParameterisedModel(c302ModelPrototype):
    def __init__(self):
        super(ParameterisedModel, self).__init__()
        self.level = "A"
        self.custom_component_types_definitions = None
        self.set_default_bioparameters()

    def set_default_bioparameters(self):
        self.add_bioparameter("neuron_iaf_leak_reversal", "-50mV", "BlindGuess", "0.1")
        self.add_bioparameter("neuron_iaf_reset", "-50mV", "BlindGuess", "0.1")
        self.add_bioparameter("neuron_iaf_thresh", "-30mV", "BlindGuess", "0.1")
        self.add_bioparameter("neuron_iaf_C", "3pF", "BlindGuess", "0.1")
        self.add_bioparameter("neuron_iaf_conductance", "0.1nS", "BlindGuess", "0.1")

        self.add_bioparameter(
            "muscle_iaf_leak_reversal",
            self.get_bioparameter("neuron_iaf_leak_reversal").value,
            "BlindGuess",
            "0.1",
        )
        self.add_bioparameter(
            "muscle_iaf_reset",
            self.get_bioparameter("neuron_iaf_reset").value,
            "BlindGuess",
            "0.1",
        )
        self.add_bioparameter(
            "muscle_iaf_thresh",
            self.get_bioparameter("neuron_iaf_thresh").value,
            "BlindGuess",
            "0.1",
        )
        self.add_bioparameter(
            "muscle_iaf_C",
            self.get_bioparameter("neuron_iaf_C").value,
            "BlindGuess",
            "0.1",
        )
        self.add_bioparameter(
            "muscle_iaf_conductance",
            self.get_bioparameter("neuron_iaf_conductance").value,
            "BlindGuess",
            "0.1",
        )

        self.add_bioparameter(
            "neuron_to_neuron_chem_exc_syn_gbase", "0.01nS", "BlindGuess", "0.1"
        )
        self.add_bioparameter(
            "neuron_to_muscle_chem_exc_syn_gbase", "0.01nS", "BlindGuess", "0.1"
        )

        self.add_bioparameter("chem_exc_syn_erev", "0mV", "BlindGuess", "0.1")
        self.add_bioparameter("chem_exc_syn_rise", "3ms", "BlindGuess", "0.1")
        self.add_bioparameter("chem_exc_syn_decay", "10ms", "BlindGuess", "0.1")

        self.add_bioparameter(
            "neuron_to_neuron_chem_inh_syn_gbase", "0.01nS", "BlindGuess", "0.1"
        )
        self.add_bioparameter(
            "neuron_to_muscle_chem_inh_syn_gbase", "0.01nS", "BlindGuess", "0.1"
        )

        self.add_bioparameter("chem_inh_syn_erev", "-80mV", "BlindGuess", "0.1")
        self.add_bioparameter("chem_inh_syn_rise", "3ms", "BlindGuess", "0.1")
        self.add_bioparameter("chem_inh_syn_decay", "10ms", "BlindGuess", "0.1")

        self.add_bioparameter(
            "neuron_to_neuron_elec_syn_gbase", "0nS", "BlindGuess", "0.1"
        )
        self.add_bioparameter(
            "neuron_to_muscle_elec_syn_gbase", "0nS", "BlindGuess", "0.1"
        )

        self.add_bioparameter("elec_syn_erev", "0mV", "BlindGuess", "0.1")
        self.add_bioparameter("elec_syn_rise", "3ms", "BlindGuess", "0.1")
        self.add_bioparameter("elec_syn_decay", "10ms", "BlindGuess", "0.1")

        self.add_bioparameter(
            "unphysiological_offset_current", "0pA", "KnownError", "0"
        )  # Can be activated later
        self.add_bioparameter(
            "unphysiological_offset_current_del", "0ms", "KnownError", "0"
        )
        self.add_bioparameter(
            "unphysiological_offset_current_dur", "200ms", "KnownError", "0"
        )

    def create_generic_muscle_cell(self):
        self.generic_muscle_cell = IafCell(
            id="generic_muscle_iaf_cell",
            C=self.get_bioparameter("muscle_iaf_C").value,
            thresh=self.get_bioparameter("muscle_iaf_thresh").value,
            reset=self.get_bioparameter("muscle_iaf_reset").value,
            leak_conductance=self.get_bioparameter("muscle_iaf_conductance").value,
            leak_reversal=self.get_bioparameter("muscle_iaf_leak_reversal").value,
        )

    def create_generic_neuron_cell(self):
        self.generic_neuron_cell = IafCell(
            id="generic_neuron_iaf_cell",
            C=self.get_bioparameter("neuron_iaf_C").value,
            thresh=self.get_bioparameter("neuron_iaf_thresh").value,
            reset=self.get_bioparameter("neuron_iaf_reset").value,
            leak_conductance=self.get_bioparameter("neuron_iaf_conductance").value,
            leak_reversal=self.get_bioparameter("neuron_iaf_leak_reversal").value,
        )

    def create_offset(self):
        self.offset_current = PulseGenerator(
            id="offset_current",
            delay=self.get_bioparameter("unphysiological_offset_current_del").value,
            duration=self.get_bioparameter("unphysiological_offset_current_dur").value,
            amplitude=self.get_bioparameter("unphysiological_offset_current").value,
        )

    def create_neuron_to_neuron_syn(self):
        self.neuron_to_neuron_exc_syn = ExpTwoSynapse(
            id="neuron_to_neuron_exc_syn",
            gbase=self.get_bioparameter("neuron_to_neuron_chem_exc_syn_gbase").value,
            erev=self.get_bioparameter("chem_exc_syn_erev").value,
            tau_decay=self.get_bioparameter("chem_exc_syn_decay").value,
            tau_rise=self.get_bioparameter("chem_exc_syn_rise").value,
        )

        self.neuron_to_neuron_inh_syn = ExpTwoSynapse(
            id="neuron_to_neuron_inh_syn",
            gbase=self.get_bioparameter("neuron_to_neuron_chem_inh_syn_gbase").value,
            erev=self.get_bioparameter("chem_inh_syn_erev").value,
            tau_decay=self.get_bioparameter("chem_inh_syn_decay").value,
            tau_rise=self.get_bioparameter("chem_inh_syn_rise").value,
        )

        self.neuron_to_neuron_elec_syn = ExpTwoSynapse(
            id="neuron_to_neuron_elec_syn",
            gbase=self.get_bioparameter("neuron_to_neuron_elec_syn_gbase").value,
            erev=self.get_bioparameter("elec_syn_erev").value,
            tau_decay=self.get_bioparameter("elec_syn_decay").value,
            tau_rise=self.get_bioparameter("elec_syn_rise").value,
        )

    def create_neuron_to_muscle_syn(self):
        self.neuron_to_muscle_exc_syn = ExpTwoSynapse(
            id="neuron_to_muscle_exc_syn",
            gbase=self.get_bioparameter("neuron_to_muscle_chem_exc_syn_gbase").value,
            erev=self.get_bioparameter("chem_exc_syn_erev").value,
            tau_decay=self.get_bioparameter("chem_exc_syn_decay").value,
            tau_rise=self.get_bioparameter("chem_exc_syn_rise").value,
        )

        self.neuron_to_muscle_inh_syn = ExpTwoSynapse(
            id="neuron_to_muscle_inh_syn",
            gbase=self.get_bioparameter("neuron_to_muscle_chem_inh_syn_gbase").value,
            erev=self.get_bioparameter("chem_inh_syn_erev").value,
            tau_decay=self.get_bioparameter("chem_inh_syn_decay").value,
            tau_rise=self.get_bioparameter("chem_inh_syn_rise").value,
        )

        self.neuron_to_muscle_elec_syn = ExpTwoSynapse(
            id="neuron_to_muscle_elec_syn",
            gbase=self.get_bioparameter("neuron_to_muscle_elec_syn_gbase").value,
            erev=self.get_bioparameter("elec_syn_erev").value,
            tau_decay=self.get_bioparameter("elec_syn_decay").value,
            tau_rise=self.get_bioparameter("elec_syn_rise").value,
        )

    def create_models(self):
        self.create_generic_muscle_cell()
        self.create_generic_neuron_cell()
        self.create_offset()
        self.create_neuron_to_muscle_syn()
        self.create_neuron_to_neuron_syn()

    def get_elec_syn(self, pre_cell, post_cell, type):
        self.found_specific_param = False
        if type == "neuron_to_neuron":
            gbase = self.get_conn_param(
                pre_cell,
                post_cell,
                "%s_to_%s_elec_syn_%s",
                "neuron_to_neuron_elec_syn_%s",
                "gbase",
            )
            erev = self.get_conn_param(
                pre_cell, post_cell, "%s_to_%s_elec_syn_%s", "elec_syn_%s", "erev"
            )
            decay = self.get_conn_param(
                pre_cell, post_cell, "%s_to_%s_elec_syn_%s", "elec_syn_%s", "decay"
            )
            rise = self.get_conn_param(
                pre_cell, post_cell, "%s_to_%s_elec_syn_%s", "elec_syn_%s", "rise"
            )
            conn_id = "neuron_to_neuron_elec_syn"
        elif type == "neuron_to_muscle":
            gbase = self.get_conn_param(
                pre_cell,
                post_cell,
                "%s_to_%s_elec_syn_%s",
                "neuron_to_muscle_elec_syn_%s",
                "gbase",
            )
            erev = self.get_conn_param(
                pre_cell, post_cell, "%s_to_%s_elec_syn_%s", "elec_syn_%s", "erev"
            )
            decay = self.get_conn_param(
                pre_cell, post_cell, "%s_to_%s_elec_syn_%s", "elec_syn_%s", "decay"
            )
            rise = self.get_conn_param(
                pre_cell, post_cell, "%s_to_%s_elec_syn_%s", "elec_syn_%s", "rise"
            )
            conn_id = "neuron_to_muscle_elec_syn"
        elif type == "muscle_to_muscle":
            gbase = self.get_conn_param(
                pre_cell,
                post_cell,
                "%s_to_%s_elec_syn_%s",
                "muscle_to_muscle_elec_syn_%s",
                "gbase",
            )
            erev = self.get_conn_param(
                pre_cell, post_cell, "%s_to_%s_elec_syn_%s", "elec_syn_%s", "erev"
            )
            decay = self.get_conn_param(
                pre_cell, post_cell, "%s_to_%s_elec_syn_%s", "elec_syn_%s", "decay"
            )
            rise = self.get_conn_param(
                pre_cell, post_cell, "%s_to_%s_elec_syn_%s", "elec_syn_%s", "rise"
            )
            conn_id = "muscle_to_muscle_elec_syn"

        if self.found_specific_param:
            conn_id = "%s_to_%s_elec_syn" % (pre_cell, post_cell)

        return ExpTwoSynapse(
            id=conn_id, gbase=gbase, erev=erev, tau_decay=decay, tau_rise=rise
        )

    def get_exc_syn(self, pre_cell, post_cell, type):
        self.found_specific_param = False

        specific_param_template = "%s_to_%s_chem_exc_syn_%s"
        if type == "neuron_to_neuron":
            gbase = self.get_conn_param(
                pre_cell,
                post_cell,
                specific_param_template,
                "neuron_to_neuron_chem_exc_syn_%s",
                "gbase",
            )
            erev = self.get_conn_param(
                pre_cell, post_cell, specific_param_template, "chem_exc_syn_%s", "erev"
            )
            decay = self.get_conn_param(
                pre_cell, post_cell, specific_param_template, "chem_exc_syn_%s", "decay"
            )
            rise = self.get_conn_param(
                pre_cell, post_cell, specific_param_template, "chem_exc_syn_%s", "rise"
            )

            conn_id = "neuron_to_neuron_exc_syn"

        elif type == "neuron_to_muscle":
            gbase = self.get_conn_param(
                pre_cell,
                post_cell,
                specific_param_template,
                "neuron_to_muscle_chem_exc_syn_%s",
                "gbase",
            )
            erev = self.get_conn_param(
                pre_cell, post_cell, specific_param_template, "chem_exc_syn_%s", "erev"
            )
            decay = self.get_conn_param(
                pre_cell, post_cell, specific_param_template, "chem_exc_syn_%s", "decay"
            )
            rise = self.get_conn_param(
                pre_cell, post_cell, specific_param_template, "chem_exc_syn_%s", "rise"
            )
            conn_id = "neuron_to_muscle_exc_syn"

        if self.found_specific_param:
            conn_id = "%s_to_%s_exc_syn" % (pre_cell, post_cell)

        return ExpTwoSynapse(
            id=conn_id, gbase=gbase, erev=erev, tau_decay=decay, tau_rise=rise
        )

    def get_inh_syn(self, pre_cell, post_cell, type):
        self.found_specific_param = False

        specific_param_template = "%s_to_%s_chem_inh_syn_%s"
        if type == "neuron_to_neuron":
            gbase = self.get_conn_param(
                pre_cell,
                post_cell,
                specific_param_template,
                "neuron_to_neuron_chem_inh_syn_%s",
                "gbase",
            )
            erev = self.get_conn_param(
                pre_cell, post_cell, specific_param_template, "chem_inh_syn_%s", "erev"
            )
            decay = self.get_conn_param(
                pre_cell, post_cell, specific_param_template, "chem_inh_syn_%s", "decay"
            )
            rise = self.get_conn_param(
                pre_cell, post_cell, specific_param_template, "chem_inh_syn_%s", "rise"
            )

            conn_id = "neuron_to_neuron_inh_syn"

        elif type == "neuron_to_muscle":
            gbase = self.get_conn_param(
                pre_cell,
                post_cell,
                specific_param_template,
                "neuron_to_muscle_chem_inh_syn_%s",
                "gbase",
            )
            erev = self.get_conn_param(
                pre_cell, post_cell, specific_param_template, "chem_inh_syn_%s", "erev"
            )
            decay = self.get_conn_param(
                pre_cell, post_cell, specific_param_template, "chem_inh_syn_%s", "decay"
            )
            rise = self.get_conn_param(
                pre_cell, post_cell, specific_param_template, "chem_inh_syn_%s", "rise"
            )
            conn_id = "neuron_to_muscle_inh_syn"

        if self.found_specific_param:
            conn_id = "%s_to_%s_inh_syn" % (pre_cell, post_cell)

        return ExpTwoSynapse(
            id=conn_id, gbase=gbase, erev=erev, tau_decay=decay, tau_rise=rise
        )
