# -*- coding: utf-8 -*-

from ....Functions.Electrical.coordinate_transformation import dq2n
from ....Functions.Winding.gen_phase_list import gen_name

from numpy import array, pi, real, imag, tile
from scipy.linalg import solve
from SciDataTool import Data1D, DataTime


def solve_EEC(self, output):
    """Compute the parameters dict for the equivalent electrical circuit
    TODO find ref. to cite
    cf "Title"
    Autor, Publisher

                  --->                     ---->
     -----Rs------XsIs---- --- -----Rr'----Xr'Ir'----
    |                     |   |                       |
    |                     Rfe Xm                      Rr'*(s-1)/s
    |                     |   |                       |
     ---------Is---------- --- ---------Ir------------

             --->
              Us

    Parameters
    ----------
    self : EEC_SCIM
        an EEC_SCIM object
    output : Output
        an Output object
    """
    Rs = self.parameters["Rs"]
    Rr = self.parameters["Rr_norm"]
    Rfe = self.parameters["Rfe"]
    Ls = self.parameters["Ls"]
    Lr = self.parameters["Lr_norm"]
    Lm = self.parameters["Lm"]
    norm = self.parameters["norm"]

    slip = self.parameters["slip"]

    felec = output.elec.felec
    ws = 2 * pi * felec

    Xs = ws * Ls
    Xm = ws * Lm
    Xr = ws * Lr

    Rr_s = Rr / slip if slip != 0 else 1e16  # TODO modify system instead

    # Prepare linear system

    # Solve system
    if "Ud" in self.parameters:
        Us = self.parameters["Ud"] + 1j * self.parameters["Uq"]
        # input vector
        b = array([real(Us), imag(Us), 0, 0, 0, 0, 0, 0, 0, 0])
        # system matrix (unknowns order: Um, Is, Im, Ir', Ife each real and imagine parts)
        # TODO simplify system for less unknows (only calculate them afterwards, e.g. Um, Im, Ife)
        # fmt: off
        A = array(
            [ 
                # sum of (real and imagine) voltages equals the input voltage Us
                [ 1,  0, Rs, -Xs,  0,   0,    0,    0,   0,   0, ], 
                [ 0,  1, Xs,  Rs,  0,   0,    0,    0,   0,   0, ], 
                # sum of (real and imagine) currents are zeros
                [ 0,  0, -1,   0,  1,   0,    1,    0,   1,   0, ], 
                [ 0,  0,  0,  -1,  0,   1,    0,    1,   0,   1, ], 
                # j*Xm*Im = Um
                [-1,  0,  0,   0,  0, -Xm,    0,    0,   0,   0, ], 
                [ 0, -1,  0,   0, Xm,   0,    0,    0,   0,   0, ],
                # (Rr'/s + j*Xr')*Ir' = Um
                [-1,  0,  0,   0,  0,   0, Rr_s,  -Xr,   0,   0, ], 
                [ 0, -1,  0,   0,  0,   0,   Xr, Rr_s,   0,   0, ],
                # Rfe*Ife = Um
                [-1,  0,  0,   0,  0,   0,    0,    0, Rfe,   0, ], 
                [ 0, -1,  0,   0,  0,   0,    0,    0,   0, Rfe, ],
            ]
        ) 
        # fmt: on
        # delete last row and column if Rfe is None
        if Rfe is None:
            A = A[:-2, :-2]
            b = b[:-2]

        # print(b)
        # print(A)
        X = solve(A.astype(float), b.astype(float))

        Ir_norm = array([X[6], X[7]])

        # TODO use logger for output of some quantities

        output.elec.Id_ref = X[2]  # use Id_ref / Iq_ref for now
        output.elec.Iq_ref = X[3]
    else:
        pass
        # TODO

    # Compute stator currents
    output.elec.Is = None
    output.elec.Is = output.elec.get_Is()

    # Compute stator voltage
    output.elec.Us = None
    output.elec.Us = output.elec.get_Us()

    # Compute rotor currents
    time = output.elec.Time.get_values(is_oneperiod=True)
    Nt = time.size
    qsr = output.simu.machine.rotor.winding.qs
    sym = output.simu.machine.comp_periodicity()[0]

    Ir_ = tile(Ir_norm, (Nt, 1)) * norm

    w_slip = ws * slip

    # Get rotation direction
    rot_dir = output.get_rot_dir()

    # compute actual rotor bar currents
    # TODO fix: initial rotor pos. is disregarded for now
    Ir = dq2n(Ir_, w_slip * time, n=qsr // sym, rot_dir=rot_dir, is_n_rms=False)
    Ir = tile(Ir, (1, sym))

    Phase = Data1D(
        name="phase",
        unit="",
        values=gen_name(qsr),
        is_components=True,
    )
    output.elec.Ir = DataTime(
        name="Rotor current",
        unit="A",
        symbol="Ir",
        axes=[Phase, output.elec.Time.copy()],
        values=Ir.T,
    )
