"""
This module implements functions for Fuzzy Logical Relationship generation
"""

import numpy as np
from pyFTS.common import FuzzySet


class FLR(object):
    """
    Fuzzy Logical Relationship

    Represents a temporal transition of the fuzzy set LHS on time t for the fuzzy set RHS on time t+1.
    """
    def __init__(self, LHS, RHS):
        """
        Creates a Fuzzy Logical Relationship
        """
        self.LHS = LHS
        """Left Hand Side fuzzy set"""
        self.RHS = RHS
        """Right Hand Side fuzzy set"""

    def __str__(self):
        return str(self.LHS) + " -> " + str(self.RHS)


class IndexedFLR(FLR):
    """Season Indexed Fuzzy Logical Relationship"""
    def __init__(self, index, LHS, RHS):
        """
        Create a Season Indexed Fuzzy Logical Relationship
        """
        super(IndexedFLR, self).__init__(LHS, RHS)
        self.index = index
        """seasonal index"""

    def __str__(self):
        return str(self.index) + ": "+ str(self.LHS) + " -> " + str(self.RHS)


def generate_high_order_recurrent_flr(fuzzyData):
    """
    Create a ordered FLR set from a list of fuzzy sets with recurrence

    :param fuzzyData: ordered list of fuzzy sets
    :return: ordered list of FLR
    """
    flrs = []
    for i in np.arange(1,len(fuzzyData)):
        lhs = fuzzyData[i - 1]
        rhs = fuzzyData[i]
        if isinstance(lhs, list) and isinstance(rhs, list):
            for l in lhs:
                for r in rhs:
                    tmp = FLR(l, r)
                    flrs.append(tmp)
        else:
            tmp = FLR(lhs,rhs)
            flrs.append(tmp)
    return flrs


def generate_recurrent_flrs(fuzzyData, steps = 1):
    """
    Create a ordered FLR set from a list of fuzzy sets with recurrence

    :param fuzzyData: ordered list of fuzzy sets
    :param steps: the number of steps ahead on the right side of FLR
    :return: ordered list of FLR
    """
    _tmp_steps = steps - 1
    flrs = []
    for i in np.arange(1,len(fuzzyData) - _tmp_steps):
        lhs = [fuzzyData[i - 1]]
        rhs = [fuzzyData[i+_tmp_steps]]
        for l in np.array(lhs).flatten():
            for r in np.array(rhs).flatten():
                tmp = FLR(l, r)
                flrs.append(tmp)
    return flrs


def generate_non_recurrent_flrs(fuzzyData, steps = 1):
    """
    Create a ordered FLR set from a list of fuzzy sets without recurrence

    :param fuzzyData: ordered list of fuzzy sets
    :return: ordered list of FLR
    """
    flrs = generate_recurrent_flrs(fuzzyData, steps=steps)
    tmp = {}
    for flr in flrs: tmp[str(flr)] = flr
    ret = [value for key, value in tmp.items()]
    return ret


def generate_indexed_flrs(sets, indexer, data, transformation=None, alpha_cut=0.0):
    """
    Create a season-indexed ordered FLR set from a list of fuzzy sets with recurrence

    :param sets: fuzzy sets
    :param indexer: seasonality indexer 
    :param data: original data
    :return: ordered list of FLR 
    """
    flrs = []
    index = indexer.get_season_of_data(data)
    ndata = indexer.get_data(data)
    if transformation is not None:
        ndata = transformation.apply(ndata)
    for k in np.arange(1,len(ndata)):
        lhs = FuzzySet.fuzzyfy_series([ndata[k - 1]], sets, method='fuzzy',alpha_cut=alpha_cut)
        rhs = FuzzySet.fuzzyfy_series([ndata[k]], sets, method='fuzzy',alpha_cut=alpha_cut)
        season = index[k]
        for _l in np.array(lhs).flatten():
            for _r in np.array(rhs).flatten():
                flr = IndexedFLR(season,_l,_r)
                flrs.append(flr)
    return flrs
