"""This module contains a Fenton_karma_1998_BR_altered cardiac cell model

The module was autogenerated from a gotran ode file
"""
from __future__ import division
from collections import OrderedDict
import ufl

import dolfin
from cbcbeat.dolfinimport import backend
from cbcbeat.cellmodels.cardiaccellmodel import CardiacCellModel


class Fenton_karma_1998_BR_altered(CardiacCellModel):
    def __init__(self, params=None, init_conditions=None):
        """
        Create cardiac cell model

        *Arguments*
         params (dict, :py:class:`dolfin.Mesh`, optional)
           optional model parameters
         init_conditions (dict, :py:class:`dolfin.Mesh`, optional)
           optional initial conditions
        """
        CardiacCellModel.__init__(self, params, init_conditions)

    @staticmethod
    def default_parameters():
        "Set-up and return default parameters."
        params = OrderedDict(
            [
                ("u_c", 0.13),
                ("u_v", 0.04),
                ("g_fi_max", 4),
                ("tau_v1_minus", 1250),
                ("tau_v2_minus", 19.6),
                ("tau_v_plus", 3.33),
                ("tau_0", 12.5),
                ("tau_r", 33.33),
                ("k", 10),
                ("tau_si", 29),
                ("u_csi", 0.85),
                ("tau_w_minus", 41),
                ("tau_w_plus", 870),
                ("IstimAmplitude", -0.2),
                ("IstimEnd", 50000),
                ("IstimPeriod", 1000),
                ("IstimPulseDuration", 1),
                ("IstimStart", 10),
                ("Cm", 1),
                ("V_0", -85),
                ("V_fi", 15),
            ]
        )
        return params

    @staticmethod
    def default_initial_conditions():
        "Set-up and return default initial conditions."
        ic = OrderedDict([("V", -85), ("v", 1), ("w", 1)])
        return ic

    def _I(self, v, s, time):
        """
        Original gotran transmembrane current dV/dt
        """
        time = time if time else backend.Constant(0.0)

        # Assign states
        V = v
        assert len(s) == 2
        v, w = s

        # Assign parameters
        u_c = self._parameters["u_c"]
        g_fi_max = self._parameters["g_fi_max"]
        tau_0 = self._parameters["tau_0"]
        tau_r = self._parameters["tau_r"]
        k = self._parameters["k"]
        tau_si = self._parameters["tau_si"]
        u_csi = self._parameters["u_csi"]
        Cm = self._parameters["Cm"]
        V_0 = self._parameters["V_0"]
        V_fi = self._parameters["V_fi"]

        # Init return args
        current = [ufl.zero()] * 1

        # Expressions for the p component
        p = ufl.conditional(ufl.lt((-V_0 + V) / (V_fi - V_0), u_c), 0, 1)

        # Expressions for the Fast inward current component
        tau_d = Cm / g_fi_max
        J_fi = (
            -(1 - (-V_0 + V) / (V_fi - V_0))
            * (-u_c + (-V_0 + V) / (V_fi - V_0))
            * p
            * v
            / tau_d
        )

        # Expressions for the Slow outward current component
        J_so = p / tau_r + (1 - p) * (-V_0 + V) / (tau_0 * (V_fi - V_0))

        # Expressions for the Slow inward current component
        J_si = (
            -(1 + ufl.tanh(k * (-u_csi + (-V_0 + V) / (V_fi - V_0)))) * w / (2 * tau_si)
        )

        # Expressions for the Stimulus protocol component
        J_stim = 0

        # Expressions for the Membrane component
        current[0] = (V_0 - V_fi) * (J_stim + J_fi + J_si + J_so)

        # Return results
        return current[0]

    def I(self, v, s, time=None):
        """
        Transmembrane current

           I = -dV/dt

        """
        return -self._I(v, s, time)

    def F(self, v, s, time=None):
        """
        Right hand side for ODE system
        """
        time = time if time else backend.Constant(0.0)

        # Assign states
        V = v
        assert len(s) == 2
        v, w = s

        # Assign parameters
        u_c = self._parameters["u_c"]
        u_v = self._parameters["u_v"]
        tau_v1_minus = self._parameters["tau_v1_minus"]
        tau_v2_minus = self._parameters["tau_v2_minus"]
        tau_v_plus = self._parameters["tau_v_plus"]
        tau_w_minus = self._parameters["tau_w_minus"]
        tau_w_plus = self._parameters["tau_w_plus"]
        V_0 = self._parameters["V_0"]
        V_fi = self._parameters["V_fi"]

        # Init return args
        F_expressions = [ufl.zero()] * 2

        # Expressions for the p component
        p = ufl.conditional(ufl.lt((-V_0 + V) / (V_fi - V_0), u_c), 0, 1)

        # Expressions for the q component
        q = ufl.conditional(ufl.lt((-V_0 + V) / (V_fi - V_0), u_v), 0, 1)

        # Expressions for the v gate component
        tau_v_minus = tau_v1_minus * q + tau_v2_minus * (1 - q)
        F_expressions[0] = (1 - p) * (1 - v) / tau_v_minus - p * v / tau_v_plus

        # Expressions for the w gate component
        F_expressions[1] = (1 - p) * (1 - w) / tau_w_minus - p * w / tau_w_plus

        # Return results
        return dolfin.as_vector(F_expressions)

    def num_states(self):
        return 2

    def __str__(self):
        return "Fenton_karma_1998_BR_altered cardiac cell model"
