'''
Created on 12-Jul-2021

@author: rishi_priyansh
'''
import inspect
import traceback
import random

from sympy import (latex, Symbol, UnevaluatedExpr as ueval,
                   Derivative, Integral, Eq,
                   )
import sympy as sp
from xv.km.util import SympyUnitSystem

# _lcr_circuit_helper
# LcrCircuitHelper

from ._base_circuit_helper import BaseCircuitHelper

class LcrCircuitHelper(BaseCircuitHelper):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        pass
    
    def get_problem_LCR_circuit(self, **kwargs):
   
        sInfo = f"""Processing {self.__class__.__name__}.{inspect.stack()[0][3]}: """
        self._log(sInfo.strip())

        index = kwargs.get('index', None)
        
        try:
            
            if index is None:
                random_choices = list(range(1, 3))
        
                identifier = f"{self.__class__.__name__}{id(self)}.{inspect.stack()[0][3]}.random_choices"
                random_choice = self.get_no_repeat_random_choice(identifier, random_choices)
            else:
                random_choice = index
            
            if random_choice == 1:
                return self._get_series_LCR_circuit(**kwargs)
    
    
            return self._get_series_LCR_circuit(**kwargs)
        
        except Exception as e:
            sError = f"""Error {self.__class__.__name__}.{inspect.stack()[0][3]}: {e}
            """
            self._log(sError)
            self._log(traceback.format_exc())
            pass
        
        return None

    def _get_series_LCR_circuit(self, **kwargs):
        L = Symbol('L')
        R = Symbol('R')
        C = Symbol('C')
        c = Symbol('c')
        V = Symbol('V')
        I = Symbol('I')
        Q = Symbol('Q')
        Q0 = Symbol(f'{latex(Q)}_0')
        Qi = Symbol(f'{latex(Q)}_i')
        Qh = Symbol(f'{latex(Q)}_h')
        t = Symbol('t')
        epsilon = Symbol(f"\\epsilon")
        epsilon_back = Symbol(f"{{{latex(epsilon)}}}_{{\\text{{back}}}} ")
        epsilon_emf = Symbol(f"{{{latex(epsilon)}}}_{{\\text{{emf}}}} ")
        epsilon_max = Symbol(f"{{{latex(epsilon)}}}_{{\\text{{max}}}} ")
        
        phi = Symbol(f"\\phi")
        phi_magnetic = Symbol(f"\\phi_m")
        
        VL = Symbol(f"{latex(V)}_L")
        VC = Symbol(f"{latex(V)}_C")
        VR = Symbol(f"{latex(V)}_R")
        
        omega = Symbol(f"\\omega")
        
        exp_emf = sp.exp(sp.I * omega * t)
        
        svg_str = self._draw_series_LCR_circuit(L, C, R, V)

        problem_s = f"""
        Derive expression for the following LCR circuit.
        {svg_str}
        """
        
        soln_stmts = []

        soln_stmt = f"""
        An inductor can be considered as an idealized solenoid, thus allowing us to
        neglect boundary effects which distinguish a real solenoid from an infinitely long
        one. Then th induced electromotive force, i.e., voltage over the inductor, 
        is the derivative of the magnetic flux. 
        """
        soln_stmts.append(soln_stmt.replace("\n", " ").strip())
        

        soln_stmt = f"""
        $\\displaystyle 
        \\begin{{aligned}}
        
        {latex(epsilon_back)}
        & = {{{latex(V)}}}_{{{latex(L)}}}
        \\\\ \\\\
        
        & = {latex(1/c)} {latex(Derivative(phi_magnetic, t))}
        \\\\ \\\\
        
        & = {latex(L)} {latex(Derivative(I, t))}
        \\qquad
        \\text{{ where the constant }}
        {latex(L)} > 0
        \\text{{ is called self inductance of the coil.  }}
        \\\\ \\\\
        
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())
        
        soln_stmt = f"""
        In accordance with Lenz’s law,
        the induced electromotive $\\displaystyle {latex(epsilon_back)}$ 
        will work against the electromotive force $\\displaystyle {latex(epsilon_emf)}$  
        which drives the circuit. 
        """
        soln_stmts.append(soln_stmt.replace("\n", " ").strip())
        
        eq_1_term1_symb = Symbol(f""" {latex(L)} {latex(Derivative(Derivative(Q, t), t))} """)
        eq_1_term2_symb = Symbol(f""" \\frac{{ {latex(Q)} }} {{ {latex(C)} }} """)
        eq_1_term3_symb = Symbol(f""" {latex(R)} {latex(Derivative(Q, t))}  """)
        eq_r_term_symb = Symbol(f""" {latex(epsilon_max)} \\; {latex(exp_emf)}  """)
        
        eq_l_term_symbs = [eq_1_term1_symb, eq_1_term2_symb, eq_1_term3_symb]
        
        eq_l_term_symb = Symbol(" + ".join([f"{latex(item)}" for item in eq_l_term_symbs]))
        
        eq_1 = Eq(eq_l_term_symb, eq_r_term_symb)

        soln_stmt = f"""
        For the given circuit:
        
        $\\displaystyle 
        \\begin{{aligned}}
        
        & {latex(epsilon_emf)} 
        = {latex(epsilon_max)} {latex(exp_emf)}
        = {latex(V)}
        = {latex(VL)} +  {latex(VC)} +  {latex(VR)}
        \\\\ \\\\
                
        \\implies
        & {latex(VL)} +  {latex(VC)} +  {latex(VR)}
        = {latex(epsilon_max)} {latex(exp_emf)}
        \\\\ \\\\
        
        \\implies
        & {latex(L)} {latex(Derivative(I, t))}
        +  \\frac{{ {latex(Q)} }} {{ {latex(C)} }} 
        +  {latex(I)} {latex(R)}
        = {latex(epsilon_max)} {latex(exp_emf)}
        \\\\ \\\\
        
        
        \\implies
        & {latex(eq_1)}
        \\qquad \\cdots \\text{{ (i) }}
        
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())
        
        soln_stmt = f"""
        The above equation has solution in two parts, 
        spacial solution $\\displaystyle {latex(Qi)} $ of the inhomogeneous equation
        and general solution $\\displaystyle {latex(Qh)} $ of the homogeneous equation. 
        Combining them, we get the general soultion of the equation:
        
        $\\displaystyle 
        {latex(Q)} = {latex(Qi)} + {latex(Qh)} 
        \\qquad \\cdots \\text{{ (ii) }}
        $
        """
        soln_stmts.append(soln_stmt.replace("\n", " ").strip())
        
        
        
        #Q0_coeff = - omega ** 2 * L - I * omega * R + 1 / C
        Q0_coeff_symb = Symbol(f""" 
        - {latex(omega ** 2)}{latex(L)}
        - {latex(I)} {latex(omega)} {latex(R)}
        + \\frac{{1}}{{ {latex(C)} }}
        """.replace("\n", " ").strip()) 
        
        Q0_symb = Symbol(f""" \\frac{{ {latex(epsilon_max)} }} {{ {latex(Q0_coeff_symb)} }}""")

        soln_stmt = f"""
        A special solution of the inhomogeneous equation is (i) is given by 

        $\\displaystyle 
        \\begin{{aligned}}
        
        & {latex(Qi)} = {latex(Q0)} {latex(exp_emf)}
        \\qquad \\cdots \\text{{ (iii) }}
        \\\\ \\\\
        
        & \\text{{Where }}
        \\\\ \\\\

        & {latex(Q0)} \\left( {latex(Q0_coeff_symb)} \\right) = {latex(epsilon_max)}
        \\\\ \\\\
        
        & \\implies
        {latex(Q0)} = {latex(Q0_symb)}
        \\qquad \\cdots \\text{{ (iv) }}
        \\\\ \\\\

        
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())
        
        alpha = Symbol(f"\\alpha")
        exp_alpha_emf = sp.exp(sp.I * alpha * t)
        
        R_by_2L = Symbol(f""" \\frac {{ {latex(R)} }} {{ {latex(2 * L)} }} """)
        
        W = Symbol("W")
        Wh = Symbol(f"{latex(W)}_h")
        
        Wh_symb = Symbol(f""" 
            \\sqrt {{
            \\frac {{ 1 }} {{ {latex(L)}{latex(C)} }}
            
            - \\frac {{ {latex(R ** 2)} }} {{ {latex(4 * L ** 2)} }}
            }}""".replace("\n", "").strip() )

        soln_stmt = f"""
        <b>The general solution of the homogeneous equation (i)</b>
        
        Let the solution be $\\displaystyle {latex(Q)} = {latex(exp_alpha_emf)} $

        Homogeneous form of equation is (i) is given by 

        $\\displaystyle 
        \\begin{{aligned}}
        
        & {latex(eq_1.lhs)} = 0
        \\\\ \\\\

        \\implies
        & - {latex(alpha ** 2)} {latex(L)} 
        + {latex(I)} {latex(alpha)}  {latex(R)}
        + \\frac {{1}}  {{ {latex(C)} }}
        = 0
        \\\\ \\\\

        \\implies
        & {latex(alpha)} 
        = {latex(sp.I)} {latex(R_by_2L)}
        \\pm 
        {latex(Wh_symb)}
        \\\\ \\\\
                
        \\implies
        & {latex(alpha)} 
        = {latex(sp.I)} {latex(R_by_2L)}
        \\pm 
        {latex(Wh)}
        \\qquad \\text{{ assume }} {latex(Wh_symb)} = {latex(Wh)}
        \\qquad \\cdots \\text{{ (v) }}
        \\\\ \\\\
                
        \\end{{aligned}}
        $
        
        """
        soln_stmts.append(soln_stmt.strip())
        

        A1 = Symbol(f"A_1")
        A2 = Symbol(f"A_2")
        
        eq6_expnent1 = Symbol(f""" - {latex(t)} {latex(R_by_2L)}  """)
        eq6_expnent2 = Symbol(f""" {latex(sp.I)} {latex(Wh)} {latex(t)} """)
        
        eq6_term1 = sp.exp(eq6_expnent1)
        eq6_term2 = sp.exp(eq6_expnent2)
        eq6_term3 = sp.exp(-eq6_expnent2)
        
        soln_stmt = f"""
        Now we can write the general solution of the homogeneous equation (i) as
        
        $\\displaystyle 
        
        {latex(Qh)} 
        = \\large {{ 
        {latex(A1)} {latex(eq6_term1)} {latex(eq6_term2)} 
        + {latex(A2)} {latex(eq6_term1)} {latex(eq6_term3)} 
        }}
        \\qquad \\cdots \\text{{ (vi) }}
        $
        
        """
        soln_stmts.append(soln_stmt.strip())
        
        soln_stmt = f"""
        Due to the exponential damping the homogeneous solution (vi) 
        dies out for most ${latex(t)}$, the solution becomes 
        
        $\\displaystyle 
        \\begin{{aligned}}
        
        {latex(Q)} 
        & = {latex(Qi)} + {latex(Qh)} 
        \\qquad \\cdots \\text{{ from (ii) }}
        \\\\ \\\\
        
        & = {latex(Qi)} 
        \\qquad \\text{{ ignored as explained above }}
        \\\\ \\\\
        
        & = {latex(Q0)} {latex(exp_emf)}
        \\qquad \\text{{ from (iii) }}
        \\\\ \\\\
        
        \\end{{aligned}}
        $
        
        """
        soln_stmts.append(soln_stmt.strip())
        
        
        soln_stmt = rf"""
        $\displaystyle
        V_{{\text {{peak }}}} \sin (\omega * t)
        = L \frac{{d I}}{{d t}}
        + R I(t) + 
        \frac{{1}}{{C}} * \int I(t) d t
        $
        
        $\displaystyle
        L \frac{{d^2 I}}{{d t^2}}
        + R \frac{{d I}}{{d t}}
        + \frac{{1}}{{C}} I(t)
        = V_{{p e a k}} \omega \cos (\omega * t)
        $
        
        Where;
        - I is the circuit current,
        - $\mathrm{{V}}$ is the Voltage output from a solar panel system 
        which will be assumed to be constant,
        - $\mathrm{{L}}$ is the inductance of the inductor in the circuit 
        measured in Henrys, $\mathrm{{H}}$
        - $\mathrm{{R}}$ is the resistance of the resistor in the circuit 
        measured in ohms, $\Omega$, and
        - $\omega$ is the angular frequency of the AC signal 
        which is also expressed as $\omega=2 \pi f$
        
        Rearranging it,

        $\displaystyle
        d^2 I / d t^2
        = -R / L * d I / d t 
        - 1 /(C * L) * I(t)
        + \frac{{ V_{{p e a k}} \omega }}{{L}} \cos (\omega * t)
        $
        
        $\displaystyle
        x^{{\prime \prime}} 
        + 2 c x^{{\prime}}
        + \omega_o^2 x
        = A \cos (\omega t)
        $
        
        where 
        
        $\displaystyle
        \omega^2
        = \frac{{1}}{{C L}}
        $
         
        To solve for the homogeneous equation, the $\mathrm{{ODE}}(1)$ must have no driving force, therefore

        $\displaystyle
        I^{{\prime \prime}}+R / L * I^{{\prime}}+1 / C L * I(t)=0
        $
        
        the characteristic roots are found;
        
        $\displaystyle
        \lambda=-\frac{{R}}{{2 L}} \pm \frac{{\sqrt{{\left( \frac{{R}}{{L}} \right)^2-\frac{{4}}{{C L}}}}}}{{2}}
        $
        
        which equate to $\lambda_1=-5.6694 \times 10^3$ and $\lambda_2=-7.6917 \times 10^7$. The homogeneous part to the general solution is now known as
        
        $\displaystyle
        I_h=C_1 e^{{\lambda_1 * t}}+C_2 e^{{\lambda_2 * t}}
        $
        
        Where $C_1$ and $C_2$ are constants.
        
        However, before solving for $C_1$ and $C_2$, a particular solution for $I(t)=I_h+$ $I_p$ must be found. The complex method laid out on page 167 of "Differential Equations With Boundary Value Problems" [5] will be used in finding the particular solution $I_p$ where
        
        $\displaystyle
        I^{{\prime \prime}}+R / L * I^{{\prime}}+1 / C L * I(t)= V_{{p e a k}} \omega / L * \cos (\omega t)
        $

        will be put in the complex form of
        
        $\displaystyle
        z^{{\prime \prime}}+R / L * z^{{\prime}}+1 / C L * z(t)= V_{{p e a k}} \omega / L * e^{{\omega i t}}
        $
        
        Where 
        $\displaystyle
        i$ is the imaginary number $\sqrt{{-1}}
        $.
        
        In order to solve for $z(t)$, a guess must be made first. Let $z(t)=a e^{{\omega i t}}$ and substitute that guess in for $z(t)$. After taking a few derivatives and some algebra,
        
        $\displaystyle
        a=\frac{{V_{{p e a k}} \left(\frac{{1}}{{C \omega}}-\omega L-i R\right)}}{{\left(\frac{{1}}{{C \omega}}-\omega L\right)^2+R^2}}
        $


        
        
        In the complex method of solving particular solutions, it is known that the final particular solution to this initial problem will be equal to the real part of the $z(t)$ solution. Therefore,

        $\displaystyle
        I_p 
        =\operatorname{{Re}}(z(t))
        = -8.4229 \times 10^{{-8}} \sin (\omega t)-0.6 \cos (\omega t)
        $
        
        $\displaystyle
        The final step to solving for the explicit solution to equation1 is to let $
        I(t)=I_h+I_p$ and solve for the initial conditions $
        C_1$ and $C_2$. 
        
        By doing so, the closed form solution to the second order ODE is equated as,
        
        $\displaystyle
        \begin{{gathered}}
        I(t)
        = C_1 e^{{\lambda_1 t}}
        + C_2 e^{{\lambda_2 t}}
        + A * \cos (\omega t)+B * \sin (\omega t) \\
        
        C_1=0.0051 \\
        
        C_2=-0.0051 \\
        
        \lambda_1=-5.6694 \times 10^3 \\
        
        \lambda_2=-7.6917 \times 10^7 \\
        
        A=-8.4229 \times 10^{{-8}} \\
        
        B=0.6000 \\
        \omega=2 \pi 105.1 \times 10^3
        \end{{gathered}}
        $
        
                               
        """
        #soln_stmts.append(soln_stmt.strip())

        soln_s = "\n\n".join(soln_stmts)
        
        answer_s = f"""
        """
        
        result = {
            'problem_s': problem_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        return result
        pass


    def _draw_series_LCR_circuit(self, L, C, R, V,  **kwargs):
 
        dot_labels = kwargs.get('dot_labels', None)
        dot_color = kwargs.get('dot_color', 'blue')
        Q_color = kwargs.get('Q_color', 'red')
        
        label_idx = 0
        
        from xv.km.ui import SvgHelper  
        import schemdraw
        import schemdraw.elements as elm
        import matplotlib
        matplotlib.use('Agg') 
        
        dot_radius = 0.001
        
        with schemdraw.Drawing(show=False) as d:
            d.config(inches_per_unit=.5, unit=3, fontsize= 10)
            
            #elm.Dot().label('A', color = dot_color)
            l0 = elm.Line()
            
            #elm.Dot().label('B', color = dot_color)
            l = elm.Inductor(at = l0.end).length(d.unit).label(
                f"${latex(L)}$", rotate = True)
            
            c = elm.Capacitor(at = l.end).length(d.unit).label(
                f"${latex(C)}$", rotate = True)
            
            r = elm.Resistor(at = c.end).length(d.unit).label(
                f"${latex(R)}$", rotate = True)
            
            l1 = elm.Line()
            
            l2 = elm.Line(at = l1.end).down().length(d.unit)

            l3 = elm.Line(at = l0.start).down().length(d.unit)
            
            l4 = elm.SourceSin(at = l2.end, to = l3.end).left().label(
                f"${latex(V)}$", rotate = True, loc = "bottom")
            
            
        svg_str = self._convert_d_to_svg_str(d)
        
        return svg_str
        pass


    pass
#class LcrCircuitHelper:

    