'''
Created on 12-Jul-2021

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

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

# _vc_circuit_helper
# VcCircuitHelper

from ._base_circuit_helper import BaseCircuitHelper

class VcCircuitHelper(BaseCircuitHelper):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        pass
    
    def get_problem_circuit_VC_simple(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_V_series_C_circuit(**kwargs)
    
            if random_choice == 2:
                return self._get_series_V_parallel_C_circuit(**kwargs)
    
            return self._get_series_V_series_C_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_V_series_C_circuit(self, **kwargs):
        V = Symbol('V')
        Q = Symbol('Q')
        C = Symbol('C')
        V_unit = Symbol(f'V')
        C_unit = Symbol(f'\\Omega')
        
        V_count = random.randint(2, 3)
        C_count = random.randint(2, 4)
        
        dot_labels = list('ABDEFGHKLMNPS')[:V_count + C_count + 1 + 2]
        dot_idx = 0

        V_labels = []
        V_vals = []
        V_val_labels = []
        for idx in range(V_count):
            V_val = Symbol(f"{latex(V)}_{{ {idx} }}")
            V_val_label = Symbol(f"{latex(V)}_{{ {dot_labels[dot_idx]} {dot_labels[dot_idx + 1]} }}")
            
            V_labels.append(dot_labels[dot_idx])
            V_vals.append(V_val)
            V_val_labels.append(V_val_label)
            dot_idx = dot_idx + 1
            pass
        
        # ending label of voltages
        V_labels.append(dot_labels[dot_idx])
        
        V_result_label = Symbol(f"{latex(V)}_{{ {V_labels[0]} {V_labels[-1]} }}")

        C_labels = []
        C_vals = []
        C_val_labels = []
        V_of_C_labels = []
        for idx in range(C_count):
            C_val = Symbol(f"{latex(C)}_{{ {idx} }}")
            C_val_label = Symbol(f"{latex(C)}_{{ {dot_labels[dot_idx]} {dot_labels[dot_idx + 1]} }}")
            V_of_C_label = Symbol(f"{latex(V)}_{{ {dot_labels[dot_idx]} {dot_labels[dot_idx + 1]} }}")
            
            C_labels.append(dot_labels[dot_idx])
            C_vals.append(C_val)
            C_val_labels.append(C_val_label)
            V_of_C_labels.append(V_of_C_label)
            
            dot_idx = dot_idx + 1
            pass

        # ending label of capacitances
        C_labels.append(dot_labels[dot_idx])
        
        
        oth_labels = [*dot_labels[dot_idx: dot_idx + 3], V_labels[0]]
        
        
        svg_str = self._draw_series_V_series_C_circuit(V_vals, C_vals, Q, 
                                                       is_simplified = False)

        prob_s = f"""
        Draw the simplified circuit and find voltage, capacitance and charge in the circuit. 
        {svg_str}
        """

        soln_stmts = []

        svg_str_with_dots = self._draw_series_V_series_C_circuit(V_vals, C_vals, Q, 
                                                       dot_labels = dot_labels)
        
        soln_stmt = f"""
        Let us redraw the circuit labeling the end-points of each component.
        {svg_str_with_dots}
        """
        soln_stmts.append(soln_stmt.strip())
        

        dot_labels_V_result = [V_labels[0], *C_labels, *oth_labels[1:-1] ]
        svg_str_V_result_with_dots = self._draw_series_V_series_C_circuit([V_result_label], 
                                                        C_vals, Q, 
                                                        dot_labels = dot_labels_V_result)
        
        
        
        soln_stmt = f"""
        Voltage in series produces cumulative effect by simple addition.
        
        $\\displaystyle 
        \\begin{{aligned}}
        
        {latex(V_result_label)} 
        & = {latex(sum(V_val_labels))}
        \\\\ \\\\
        
        & = {latex(sum(V_vals))}
        \\quad \\cdots \\text{{ (i) }}
      
        \\end{{aligned}}
        $
        {svg_str_V_result_with_dots}
        """
        soln_stmts.append(soln_stmt.strip())
        
        
        V_oth_labels = []
        for idx, oth_label in enumerate(oth_labels[:-1]):
            V_oth_label = Symbol(f"{latex(V)}_{{ {oth_label} {oth_labels[idx + 1]} }}")
            V_oth_labels.append(V_oth_label)
            pass
        
        V_zero_label = Symbol(f"{latex(V)}_{{ {oth_labels[0]} {oth_labels[-1]} }}")
        V_oth_vals = 0
        
        soln_stmt = f"""
        The charges on each capacitor will be same dues to maintain equilibrium in the circuit.
        
        $\\displaystyle 
        \\begin{{aligned}}
        
        & {latex(V_zero_label)}  = {latex(sum(V_oth_labels))}
        \\\\ \\\\
        
        \\implies
        & {latex(V_zero_label)}  = {latex(V_oth_vals)}
        \\qquad \\text{{ as there is not source of voltage or capacitance in this part }}
        
        \\end{{aligned}}
        $
        
        """
        soln_stmts.append(soln_stmt.strip())
        
        
        V_oth_labels = []
        for idx, oth_label in enumerate(oth_labels[:-1]):
            V_oth_label = Symbol(f"{latex(V)}_{{ {oth_label} {oth_labels[idx + 1]} }}")
            V_oth_labels.append(V_oth_label)
            pass
        V_all_result_label = Symbol(f"{latex(V)}_{{ {oth_labels[-1]} {oth_labels[0]} }}")
        
        V_all_labels = [V_result_label, *[-item for item in V_of_C_labels]]
        
        Q_by_C_val_labels = [Q / item for item in C_val_labels]
        
        inv_C_val_labels = [1 / item for item in C_val_labels]

        C_resultant = 1 / sum([1/item for item in C_vals])
        
        soln_stmt = f"""
        $\\displaystyle 
        \\begin{{aligned}}
        
        \\implies
        & - {latex(V_all_result_label)} 
         = {latex(V_oth_vals)}
        \\qquad \\text{{ as  }} {latex(V_zero_label)} = - {latex(V_all_result_label)}
        \\\\ \\\\
        
        \\implies
        & {latex(V_all_result_label)} 
         = {latex(V_oth_vals)}
        \\\\ \\\\
        
        \\implies
        & {latex(sum(V_all_labels))} 
         = {latex(V_oth_vals)}
        \\qquad \\text{{ as capacitances consume voltage, they are shown as negative voltages. }} 
        \\\\ \\\\


        \\implies
        & {latex(V_result_label)} 
         = {latex(sum(V_of_C_labels))}
        \\\\ \\\\
        
        \\implies
        & {latex(Q / C)} 
         = {latex(sum(Q_by_C_val_labels))}
        \\qquad \\text{{ using }} {latex(V)} = {latex(Q/C)} 
        \\\\ \\\\
        
        \\implies
        & {latex(1 / C)} 
         = {latex(sum(inv_C_val_labels))}
        \\\\ \\\\
        
        \\implies
        & {latex(C)} 
         = \\frac{{ 1 }} {{ {latex(sum(inv_C_val_labels))} }}
        \\\\ \\\\
        
        \\implies
        & {latex(C)} 
         = {latex(C_resultant)}
        
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())
        
        svg_str_simplified = self._draw_series_V_series_C_circuit(V_vals, C_vals, Q, 
                                                                  is_simplified = True)
        
                
        soln_stmt = f"""
        {svg_str_simplified}
        
        Therefore, the charge ${latex(Q)}$ on each capacitor ,

        $\\displaystyle 
        \\begin{{aligned}}
        
        {latex(Q)} 
        & =  {latex( V / C  )}
        \\\\ \\\\
        
        & =  {latex( sum(V_vals) / C_resultant )}
        \\quad \\cdots \\text{{ (iii) }}

        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())
        
        
        
        soln_s = "\n\n".join(soln_stmts)
        
        answer_s = f"""
        $\\displaystyle {latex(V)} = {latex(sum(V_vals))} $
        
        $\\displaystyle {latex(C)} = {latex(C_resultant)} $
        
        $\\displaystyle {latex(Q)} = {latex( sum(V_vals) / C_resultant  )} $
        """
        
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        return result


    def _get_series_V_parallel_C_circuit(self, **kwargs):
        V = Symbol('V')
        Q = Symbol('Q')
        C = Symbol('C')
        V_unit = Symbol(f'V')
        C_unit = Symbol(f'\\Omega')
        
        V_count = random.randint(2, 3)
        C_count = random.randint(2, 4)
        
        dot_labels = list('ABCDEFGHKLMNPS')[:V_count + C_count + 1 + 2]
        dot_idx = 0

        V_labels = []
        V_vals = []
        V_val_labels = []
        for idx in range(V_count):
            V_val = Symbol(f"{latex(V)}_{{ {idx} }}")
            V_val_label = Symbol(f"{latex(V)}_{{ {dot_labels[dot_idx]} {dot_labels[dot_idx + 1]} }}")
            
            V_labels.append(dot_labels[dot_idx])
            V_vals.append(V_val)
            V_val_labels.append(V_val_label)
            dot_idx = dot_idx + 1
            pass
        
        # ending label of voltages
        V_labels.append(dot_labels[dot_idx])
        
        V_result_label = Symbol(f"{latex(V)}_{{ {V_labels[0]} {V_labels[-1]} }}")
            
        
        C_labels = []
        C_vals = []
        Q_vals = []
        C_val_labels = []
        V_of_C_labels = []
        C_label_V_labels = []
        
        for idx in range(C_count):
            C_val = Symbol(f"{latex(C)}_{{ {idx} }}")
            Q_val = Symbol(f"{latex(Q)}_{{ {idx} }}")
            C_val_label = Symbol(f"{latex(C)}_{{ {dot_labels[dot_idx]} {dot_labels[dot_idx + 1]} }}")
            
            next_label = dot_labels[dot_idx + 1]
            V_of_C_label = Symbol(f"{latex(V)}_{{ {next_label}_0 {next_label}_1 }}")
            
            C_label_V_label = Symbol(f"{latex( C_val * V)}")
            V_by_C_label = Symbol(f"{latex(C * V)}")
            
            
            C_labels.append(dot_labels[dot_idx])
            V_of_C_labels.append(V_of_C_label)
            C_vals.append(C_val)
            Q_vals.append(Q_val)
            C_val_labels.append(C_val_label)
            C_label_V_labels.append(C_label_V_label)
            
            dot_idx = dot_idx + 1
            pass

        
        # ending label of capacitances
        C_labels.append(dot_labels[dot_idx])
        
        C_result_label = Symbol(f"{latex(C)}_{{ {C_labels[0]} {C_labels[-1]} }}")
        
        oth_labels = [*dot_labels[dot_idx: dot_idx + 3], V_labels[0]]
        
        
        svg_str = self._draw_series_V_parallel_C_circuit(V_vals, C_vals, Q, 
                                                       is_simplified = False)

        prob_s = f"""
        Draw the simplified circuit and find voltage, capacitance and charge in the circuit. 
        {svg_str}
        """

        soln_stmts = []

        svg_str_with_dots = self._draw_series_V_parallel_C_circuit(V_vals, C_vals, Q, 
                                                       dot_labels = dot_labels)
        
        soln_stmt = f"""
        Let us redraw the circuit labeling the end-points of each component.
        {svg_str_with_dots}
        """
        soln_stmts.append(soln_stmt.strip())
        

        dot_labels_V_result = [V_labels[0], *C_labels, *oth_labels[1:-1] ]
        svg_str_V_result_with_dots = self._draw_series_V_parallel_C_circuit([V_result_label], 
                                                        C_vals, Q, 
                                                        dot_labels = dot_labels_V_result)
        
        
        
        soln_stmt = f"""
        Voltage in series produces cumulative effect by simple addition.
        
        $\\displaystyle 
        \\begin{{aligned}}
        
        {latex(V_result_label)} 
        & = {latex(sum(V_val_labels))}
        \\\\ \\\\
        
        & = {latex(sum(V_vals))}
        \\quad \\cdots \\text{{ (i) }}
      
        \\end{{aligned}}
        $
        {svg_str_V_result_with_dots}
        """
        soln_stmts.append(soln_stmt.strip())
        
        C_resultant = sum(C_vals)
        
        soln_stmt = f"""
        $\\displaystyle 
        \\begin{{aligned}}
        
        & {latex(Q)}  = {latex(sum(Q_vals))}
        \\qquad \\text{{ the total charge in the circuit is sum of charges on each capacitance }} 
        \\\\ \\\\
        
        \\implies
        & {latex(C * V )}  = {latex(sum(C_label_V_labels))}
        \\qquad \\text{{ as voltage across each capacitance is same }} 
        \\\\ \\\\
        
        
        \\implies
        & {latex(C)}  = {latex(C_resultant)}
        \\quad \\cdots \\text{{ (ii) }}
        
        \\end{{aligned}}
        $
        
        """
        soln_stmts.append(soln_stmt.strip())
        
        
        svg_str_simplified = self._draw_series_V_series_C_circuit(V_vals, [C_resultant], Q, 
                                                                  is_simplified = True)

        Q_symb = Symbol(f"""\\left( {latex( sum(V_vals) )} \\right) 
                            \\left( {latex(C_resultant)} \\right)""")
        
        soln_stmt = f"""
        {svg_str_simplified}
        
        Therefore, the charge ${latex(Q)}$ flowing through the circuit ,

        $\\displaystyle 
        \\begin{{aligned}}
        
        {latex(Q)} 
        & =  {latex( C * V_result_label  )}
        \\\\ \\\\
        
        & = {latex(Q_symb)}
        \\quad \\cdots \\text{{ (iii) }}

        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())
        
        
        
        soln_s = "\n\n".join(soln_stmts)
        
        answer_s = f"""
        $\\displaystyle {latex(V)} = {latex(sum(V_vals))} $
        
        $\\displaystyle {latex(C)} = {latex(C_resultant)} $
        
        $\\displaystyle {latex(Q)} = {latex(Q_symb)} $
        """
        
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        return result

    def _draw_series_V_series_C_circuit(self, Vs, Cs, Q,  **kwargs):
        
        is_simplified = kwargs.get('is_simplified', False)
        dot_labels = kwargs.get('dot_labels', None)
        dot_color = kwargs.get('dot_color', 'blue')
        Q_color = kwargs.get('Q_color', 'red')
        
        
        label_idx = 0
        
        if is_simplified:
            Vs = [sum(Vs)]
            Cs = [1 / sum([1/item for item in Cs])]
        
        from xv.km.ui import SvgHelper  
        import schemdraw
        import schemdraw.elements as elm
        import matplotlib
        matplotlib.use('Agg') 
        
        dot_radius = 0.001
        

        d = schemdraw.Drawing()
        std_length = d.unit * .75

        if dot_labels:
            d.add(elm.Dot(radius = dot_radius).label(dot_labels[label_idx], 
                                                     color = dot_color))
            label_idx = label_idx + 1
        
        for V_temp in Vs:
            V1 = d.add(elm.SourceV(label=f'${latex(V_temp)}$', d = "right"))
            if dot_labels:
                d.add(elm.Dot(radius = dot_radius).label(dot_labels[label_idx], 
                                                         color = dot_color))
                label_idx = label_idx + 1

        for C_temp in Cs:
            C1 = d.add(elm.Capacitor(polar = True, label=f'${latex(C_temp)}$', d = "right"))
            if dot_labels:
                d.add(elm.Dot(radius = dot_radius).label(dot_labels[label_idx], 
                                                         color = dot_color))
                label_idx = label_idx + 1
        
        d.add(elm.Line(d='down', l=std_length))

        if dot_labels:
            d.add(elm.Dot(radius = dot_radius).label(dot_labels[label_idx], 
                                                     color = dot_color, 
                                                     loc ='right'))
            label_idx = label_idx + 1

        length = d.unit * (len(Vs) + len(Cs))
        d.add( elm.Line(d='left', l=length ))
        if dot_labels:
            d.add(elm.Dot(radius = dot_radius).label(dot_labels[label_idx], 
                                                     color = dot_color, 
                                                     loc ='left'))
            label_idx = label_idx + 1

        d.add(elm.Line(d='up', l=std_length))
        
        image_bytes = d.get_imagedata('svg')
        svg_str = image_bytes.decode('ascii', 'ignore')
        
        svg_helper = SvgHelper(verbose = self.verbose)
        svg_str = svg_helper.remove_unwanted_defs(svg_str)
        return svg_str
        pass

    def _draw_series_V_parallel_C_circuit(self, Vs, Cs, Q,  **kwargs):
        
        is_simplified = kwargs.get('is_simplified', False)
        dot_labels = kwargs.get('dot_labels', None)
        dot_color = kwargs.get('dot_color', 'blue')
        Q_color = kwargs.get('Q_color', 'red')
        
        label_idx = 0
        
        if is_simplified:
            Vs = [sum(Vs)]
            Cs = [sum(Cs)]
        
        from xv.km.ui import SvgHelper  
        import schemdraw
        import schemdraw.elements as elm
        import matplotlib
        matplotlib.use('Agg') 
        
        dot_radius = 0.001
        

        d = schemdraw.Drawing()
        std_length = d.unit * .5

        if dot_labels:
            d.add(elm.Dot(radius = dot_radius
                          ).label(dot_labels[label_idx], 
                                  color = dot_color))
            label_idx = label_idx + 1
        
        for V_idx, V_temp in enumerate(Vs):
            d.add(elm.SourceV(label=f'${latex(V_temp)}$', d = "right"))

            if V_idx == len(Vs) - 1: 
                V_last = d.add(elm.Line(d='right', l=std_length))

            if dot_labels:
                if V_idx < len(Vs) - 1: 
                    loc ='top'
                else:
                    loc ='right'
                d.add(elm.Dot(radius = dot_radius
                              ).label(dot_labels[label_idx], 
                                      color = dot_color,
                                      loc = loc))
                label_idx = label_idx + 1
                pass
            
            pass
            

        for C_idx, C_temp in enumerate(Cs):
            d.push()
            L_length = std_length * (C_idx + 1)
            
            L_up = d.add(elm.Line(d='up', l=L_length, start = V_last.end,
                                   ))

            if dot_labels:
                d.add(elm.Dot(radius = dot_radius
                              ).label(f"${dot_labels[label_idx]}_0$", 
                                      color = dot_color,
                                      loc = 'left'))
        
            L_right = d.add(elm.Line(d='right', l=std_length, start = L_up.end))
        
            C1 = d.add(elm.Capacitor(polar = True, d = "right", start = L_right.end
                                    ).label(f'${latex(C_temp)}$', 
                                            ))

            L_right = d.add(elm.Line(d='right', l=std_length, start = L_up.end))
            
            if dot_labels:
                d.add(elm.Dot(radius = dot_radius
                              ).label(f"${dot_labels[label_idx]}_1$", 
                                      color = dot_color,
                                      loc = 'right'))
                label_idx = label_idx + 1

            d.add(elm.Line(d='down', l=L_length, start = L_right.end
                            ))
            
            if C_idx < len(Cs) - 1:
                d.pop()
            pass
            
        d.add(elm.Line(d='down', l=std_length))

        if dot_labels:
            d.add(elm.Dot(radius = dot_radius
                          ).label(dot_labels[label_idx], 
                                  color = dot_color, 
                                  loc ='right'))
            label_idx = label_idx + 1

        length = d.unit * len(Vs) + d.unit * 1 + std_length * 3
        d.add( elm.Line(d='left', l=length))
        if dot_labels:
            d.add(elm.Dot(radius = dot_radius
                          ).label(dot_labels[label_idx], 
                                  color = dot_color, 
                                   loc ='left') )
            
            label_idx = label_idx + 1

        d.add(elm.Line(d='up', l=std_length))
        
        image_bytes = d.get_imagedata('svg')
        svg_str = image_bytes.decode('ascii', 'ignore')
        
        svg_helper = SvgHelper(verbose = self.verbose)
        svg_str = svg_helper.remove_unwanted_defs(svg_str)
        return svg_str
        pass


    pass
#class VcCircuitHelper:

    