"""
Module for ModelCall.
"""

from collections import OrderedDict

from andes.shared import jac_names, jac_types


class ModelCall:
    """
    Class for storing generated function calls, Jacobian calls, and arguments.
    """

    def __init__(self):
        self.md5 = ''

        # `f` and `g` are callables generated by lambdify that take positional args
        self.f = None
        self.g = None
        self.j = dict()
        self.s = OrderedDict()
        self.sns = None

        # `f_args` and `g_args` are the arg names
        self.f_args = list()
        self.g_args = list()
        self.j_args = dict()
        self.ia = OrderedDict()
        self.ii = OrderedDict()
        self.ij = OrderedDict()
        self.s_args = OrderedDict()
        self.sns_args = list()
        self.ia_args = OrderedDict()  # assignment initialization
        self.ii_args = OrderedDict()  # iterative initialization
        self.ij_args = OrderedDict()

        self.ijac = OrderedDict()
        self.jjac = OrderedDict()
        self.vjac = OrderedDict()

    def clear_ijv(self):
        for jname in jac_names:
            for jtype in jac_types:
                self.ijac[jname + jtype] = list()
                self.jjac[jname + jtype] = list()
                self.vjac[jname + jtype] = list()

    def append_ijv(self, j_full_name, ii, jj, vv):
        if not isinstance(ii, int):
            raise ValueError("i index must be an integer")
        if not isinstance(jj, int):
            raise ValueError("j index must be an integer")
        if not isinstance(vv, (int, float)) and (not callable(vv)):
            raise ValueError("v must be a number or a callable")

        self.ijac[j_full_name].append(ii)
        self.jjac[j_full_name].append(jj)
        self.vjac[j_full_name].append(vv)

    def zip_ijv(self, j_full_name):
        """
        Return a zipped iterator for the rows, cols and vals for the specified matrix name.
        """
        return zip(self.ijac[j_full_name],
                   self.jjac[j_full_name],
                   self.vjac[j_full_name])
