from modelflow import Node, Input
from .dynamicsorn import make_sorn, NullRecorder, RepeatingPatterns
from .bases import NetworkModelMixin
from .network import Network
import logging
logger = logging.getLogger("SORN")


class SORN(NetworkModelMixin, Node):
    """
    Self-organizing recurrent neural network.

    It has the additional parameters

    :param eta_stdp: float
        Learning rate for STDP.
    :param eta_intrinsic: float
        Learning rate for intrinsic plasticity.

    :param nr_patterns: int
        For nr_patterns == -1,  the number of patterns is infinite.


    Notes
    -----

    This implementation is efficiently realized in Cython and parallelized with OpenMP.
    """
    eta_stdp = Input()
    eta_intrinsic = Input()
    nr_patterns = Input(-1)
    NR_TIME_STEPS = 10_000

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.recorder = NullRecorder()

    def run(self):
        kwargs = {}
        if self.nr_patterns != -1:
            kwargs["input_generator"] = RepeatingPatterns(
                nr_patterns=self.nr_patterns,
                sparsity=1)

        adjacency_matrix = make_sorn(nr_exc=self.nr_exc,
                                     nr_inh=self.nr_inh,
                                     nr_time_steps=self.NR_TIME_STEPS,
                                     p_exc=self.p_exc,
                                     p_inh=self.p_inh,
                                     history_recorder=self.recorder,
                                     eta_equal=self.eta_stdp,
                                     eta_plus=self.eta_stdp,
                                     eta_minus=-self.eta_stdp,
                                     eta_intrinsic=self.eta_intrinsic,
                                     **kwargs)
        return Network(adjacency_matrix, nr_exc=self.nr_exc, nr_inh=self.nr_inh)
