'''
Created on 12-Jul-2021

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

import sympy
from sympy import (simplify, sympify, log, 
                   symbols, Symbol, Function,
                   Add, Mul,
                   Eq, Matrix, latex, 
                   solve, Rational, diag,
                   Derivative, Integral,
                   UnevaluatedExpr as ueval
                   )

from xv.util import list_to_str
from xv.km.util import latex_fraction, latex_color

# _additive_property_helper
# AdditivePropertyHelper

from xv.util import UtilClass

class AdditivePropertyHelper(UtilClass):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        pass

    def get_simple_sum_data(self, prop, size):
        props = self._get_subscripted_series(prop, size)
        props_latex = self._get_series_latex(props)
        sum_props = Add(*props)

        result = {
            'props': props,
            'props_latex': props_latex,
            'sum_props': sum_props,
            }
        
        return result
        pass

    def get_function_sum_data(self, prop, func, *agrs, **kwargs):
        size = kwargs.get('size', None)
        if size is None:
            size = random.randint(2, 5)

        props = self._get_subscripted_series(prop, size)
        props_latex = self._get_series_latex(props)
        sum_props = Add(*props)
        
        prop_expr = func(*agrs)

        prop_exprs = []
        for idx in range(size):
            agrs_mod = [Symbol(f"{item}_{{{idx}}}") for item in agrs]
            term = func(*agrs_mod)
            prop_exprs.append(term)
            pass
        
        prop_exprs_latex = self._get_series_latex(prop_exprs)
        sum_prop_exprs = Add(*prop_exprs)

        result = {
            'prop': prop,
            'props': props,
            'props_latex': props_latex,
            'sum_props': sum_props,
            'prop_expr': prop_expr,
            'prop_exprs': prop_exprs,
            'prop_exprs_latex': prop_exprs_latex,
            'sum_prop_exprs': sum_prop_exprs,
            }
        
        return result
        pass

    def get_electric_potential_energy(self, q1, q2, r1, r2, 
                                      epsilon0 = None, include_k = True):
        
        unit_r1r2 = f"\\left| {latex(r1)} - {latex(r2)} \\right|"
        unit_r1r2 = Symbol(unit_r1r2)
        
        q1q2_by_unit_r1r2 = latex_fraction(latex(q1 * q2), unit_r1r2)
        q1q2_by_unit_r1r2 = Symbol(q1q2_by_unit_r1r2)

        if not include_k:
            return q1q2_by_unit_r1r2
            
        k = self.get_electric_field_constant(epsilon0 = epsilon0)
        return k * q1q2_by_unit_r1r2
        pass

    def get_electric_system_potential_energy(self, **kwargs):
        external_field = kwargs.get('external_field', None) 
        
        if external_field is None:
            return self._get_electric_system_potential_energy(**kwargs)
            
        return self._get_electric_system_potential_energy_with_external_field(**kwargs)
        pass

    def _get_ith_term(self, *args, i = "i"):
        ith_terms = [Symbol(f"{latex(item)}_{{{i}}}") for item in args]
        return ith_terms
    
    def _get_electric_system_potential_energy(self, **kwargs):
        size = kwargs.get('size', None)
        if size is None:
            size = random.randint(2, 5)

        prop = Symbol(f'\\vec U')
        q = Symbol(f'q')   
        r = Symbol(f'\\vec r')   

        props_subscripts = []
        for idx1 in range(size):
            for idx2 in range(idx1 + 1, size):
                props_subscripts.append([idx1, idx2])
                pass
            pass
        
        props = [Symbol(f"{prop}_{{{idx1}{idx2}}}") for idx1, idx2  in props_subscripts]
        props_latex = self._get_series_latex(props)
        sum_props = Add(*props)

        charges = [Symbol(f"{latex(q)}_{{{idx}}}") for idx in range(size)]
        radius_vectors = [Symbol(f"{latex(r)}_{{{idx}}}") for idx in range(size)]
        charge_radius_vectors = list(zip(charges, radius_vectors))
        charge_radius_vectors_latex = [
                f"$\\displaystyle \\left( {latex(charge)}, {latex(radius_vector)} \\right) $" 
                for charge, radius_vector in charge_radius_vectors]
        charge_radius_vectors_latex = list_to_str(charge_radius_vectors_latex, last_sep = ' and ')

        prop_ij = self._get_ith_term(prop, i = 'ij')
        qi, ri = self._get_ith_term(q, r, i = 'i')
        qj, rj = self._get_ith_term(q, r, i = 'j')
        
        prop_expr_ij = self.get_electric_potential_energy(qi, qj, ri, rj, include_k = True)

        prop_exprs = []
        prop_exprs_common_const = []
        for idx1, idx2  in props_subscripts:
            q1, r1 = charge_radius_vectors[idx1]
            q2, r2 = charge_radius_vectors[idx2]
            term1 = self.get_electric_potential_energy(q1, q2, r1, r2, include_k = True)
            term2 = self.get_electric_potential_energy(q1, q2, r1, r2, include_k = False)
            
            prop_exprs.append(term1)
            prop_exprs_common_const.append(term2)
            pass

        sum_prop_exprs = Add(*prop_exprs)
        sum_prop_exprs_common_const = Add(*prop_exprs_common_const)
        
        k = self.get_electric_field_constant()
        sum_prop_exprs_common_const = f"""
                {latex(k)} \\left( {sum_prop_exprs_common_const} \\right)"""
        
        result = {
            'size': size,
            'q': q,
            'r': r,
            'prop': prop,
            'props': props,
            'props_latex': props_latex,
            'sum_props': sum_props,
            'charge_radius_vectors_latex': charge_radius_vectors_latex,
            'prop_ij': prop_ij,
            'prop_expr_ij': prop_expr_ij,
            'prop_exprs': prop_exprs,
            'prop_exprs_common_const': prop_exprs_common_const,
            'sum_prop_exprs': sum_prop_exprs,
            'sum_prop_exprs_common_const': sum_prop_exprs_common_const,
            }
        
        return result
        pass
    

    def _get_electric_system_potential_energy_with_external_field(self, **kwargs):
        ef_prop = kwargs['external_field']
        
        result  = self._get_electric_system_potential_energy(**kwargs)
        size = result['size']
        prop = result['prop']
        q = result['q']
        r = result['r']


        ef_props = [Symbol(f"{prop}_{{ext{idx1}}}") for idx1 in range(size)]
        ef_props_latex = self._get_series_latex(ef_props)
        sum_ef_props = Add(*ef_props)
        
        
        ef_prop_exprs = []
        for idx1 in range(size):
            qi = Symbol(f"{latex(q)}_{{{idx1}}}")
            ri = Symbol(f"{latex(r)}_{{{idx1}}}")
            vi = qi * Function(f"{latex(ef_prop)}")(ri)
            ef_prop_exprs.append(vi)

        ef_prop_exprs_latex = self._get_series_latex(ef_prop_exprs)
        sum_ef_prop_exprs = Add(*ef_prop_exprs)

        ef_prop_i = Symbol(f"{latex(prop)}_{{exti}}")
        qi = Symbol(f"{latex(q)}_{{i}}")
        ri = Symbol(f"{latex(r)}_{{i}}")
        ef_prop_expr_i = qi * Function(f"{latex(ef_prop)}")(ri)


        result.update({
            'ef_prop': ef_prop,
            'ef_prop_i': ef_prop_i,
            'ef_prop_expr_i': ef_prop_expr_i,
            'ef_props': ef_props,
            'ef_props_latex': ef_props_latex,
            'sum_ef_props': sum_ef_props,
            'ef_prop_exprs': ef_prop_exprs,
            'ef_prop_exprs_latex': ef_prop_exprs_latex,
            'sum_ef_prop_exprs': sum_ef_prop_exprs,
            })
        
        return result
        pass
    

    
    def get_propotional_sum_data(self, src_prop, com_prop, add_prop, size, 
                                 solve_for = None):
        if solve_for is None:
            solve_for = com_prop


        add_props = self._get_subscripted_series(add_prop, size)
        add_props_latex = self._get_series_latex(add_props)
        
        soln_stmts = []

        src_props = self._get_subscripted_series(src_prop, size)
        src_props_sum = Add(*src_props)
        src_prop_eq = Eq(src_prop, src_props_sum)

        soln_stmt =  f"""
        # override this statement index 0
        The total voltage is sum of voltages across each resistances in a series.
        """
        soln_stmt = soln_stmt.replace("\n", "")
        soln_stmts.append(soln_stmt.strip())
 
        soln_stmt =  f"""
        $\\displaystyle {latex(src_prop_eq)}$
        """
        soln_stmts.append(soln_stmt.strip())

        com_props_into_add_prop = [com_prop * item for item in add_props]
        com_props_into_add_prop = Add(*com_props_into_add_prop)
        com_props_into_add_prop_eq = Eq(com_prop * add_prop, com_props_into_add_prop)
 
        soln_stmt =  f"""
        # override this statement index 2
        As the current through each of the resistance in a series must be same: 
        """
        soln_stmt = soln_stmt.replace("\n", "")
        soln_stmts.append(soln_stmt.strip())
 
        soln_stmt =  f"""
        $\\displaystyle \\implies {latex(com_props_into_add_prop_eq)}$
        """
        soln_stmts.append(soln_stmt.strip())
 
        add_props_sum = Add(*add_props)
        add_props_sum_eq = Eq(add_prop, add_props_sum)
 
        soln_stmt =  f"""
        $\\displaystyle \\implies {latex(add_props_sum_eq)}$
        """
        soln_stmts.append(soln_stmt.strip())

        if solve_for == add_prop:
            answer = add_props_sum_eq.rhs
            answer_s =  f"""
            $\\displaystyle {latex(answer)}$
            """.strip()
            pass
        elif solve_for == src_prop:
            answer = add_props_sum_eq.rhs
            src_prop_by_add_prop = latex_fraction(latex(src_prop), latex(add_prop))
            src_prop_by_add_props_sum = latex_fraction(latex(src_prop), latex(add_props_sum))
    
            soln_stmt =  f"""
            $\\displaystyle 
            \\implies 
            {latex(src_prop)} = {latex(add_prop * com_prop)}
            = \\left( {latex(add_props_sum_eq.rhs)} \\right) {latex(com_prop)}
            $
            """
            soln_stmts.append(soln_stmt.strip())
    
            answer_s =  f"""
            $\\displaystyle {latex(add_props_sum_eq.rhs)} $
            """.strip()
            pass

        else:
            answer = src_prop / add_props_sum
            src_prop_by_add_prop = latex_fraction(latex(src_prop), latex(add_prop))
            src_prop_by_add_props_sum = latex_fraction(latex(src_prop), latex(add_props_sum))
    
            soln_stmt =  f"""
            $\\displaystyle 
            \\implies {latex(com_prop)}
            = {src_prop_by_add_prop}
            = {src_prop_by_add_props_sum}
            $
            """
            soln_stmts.append(soln_stmt.strip())
    
            answer_s =  f"""
            $\\displaystyle {src_prop_by_add_props_sum} $
            """.strip()
            pass

        result = {
            'add_props': add_props,
            'add_props_latex': add_props_latex,
            'soln_stmts': soln_stmts,
            'answer_s': answer_s,
            'answer': answer,
            }
        
        return result
        pass

    def get_inverse_sum_data(self, src_prop, com_prop, add_prop, size, 
                             solve_for = None):
        if solve_for is None:
            solve_for = com_prop

        add_props = self._get_subscripted_series(add_prop, size)
        add_props_latex = self._get_series_latex(add_props)
 
        
        soln_stmts = []

        com_props = self._get_subscripted_series(com_prop, size)
        com_props_sum = Add(*com_props)
        com_prop_eq = Eq(com_prop, com_props_sum)

        soln_stmt =  f"""
        # override this statement index 0
        """
        soln_stmt = soln_stmt.replace("\n", "")
        soln_stmts.append(soln_stmt.strip())
 
        soln_stmt =  f"""
        $\\displaystyle {latex(com_prop_eq)}$
        """
        soln_stmts.append(soln_stmt.strip())

        src_props_by_add_prop = [src_prop/item for item in add_props]
        src_props_by_add_prop = Add(*src_props_by_add_prop)
        src_props_by_add_prop_eq = Eq(src_prop/add_prop, src_props_by_add_prop)
 
        soln_stmt =  f"""
        # override this statement index 2
        """
        soln_stmt = soln_stmt.replace("\n", "")
        soln_stmts.append(soln_stmt.strip())
 
        soln_stmt =  f"""
        $\\displaystyle \\implies {latex(src_props_by_add_prop_eq)}$
        """
        soln_stmts.append(soln_stmt.strip())
 
        inv_add_props = [1/item for item in add_props]
        inv_add_props = Add(*inv_add_props)
        inv_add_props_eq = Eq(1/add_prop, inv_add_props)
 
        soln_stmt =  f"""
        $\\displaystyle \\implies {latex(inv_add_props_eq)}$
        """
        soln_stmts.append(soln_stmt.strip())

        inv_add_props_frac = latex_fraction(1, latex(inv_add_props))

        soln_stmt =  f"""
        $\\displaystyle 
        \\implies {latex(add_prop)}
        = {inv_add_props_frac}
        $
        """
        soln_stmts.append(soln_stmt.strip())


        if solve_for == add_prop:
            answer = inv_add_props_frac
            answer_s =  f"""
            $\\displaystyle {inv_add_props_frac}$
            """.strip()
            pass
        elif solve_for == src_prop:
            answer = inv_add_props_frac
    
            soln_stmt =  f"""
            $\\displaystyle 
            \\implies 
            {latex(src_prop)} = {latex(add_prop * com_prop)}
            = \\left( {inv_add_props_frac} \\right) {latex(com_prop)}
            $
            """
            soln_stmts.append(soln_stmt.strip())
    
            answer_s =  f"""
            $\\displaystyle \\left( {inv_add_props_frac} \\right) {latex(com_prop)} $
            """.strip()
            pass
        else:
            src_prop_add_prop_frac = latex_fraction(latex(src_prop), latex(add_prop))
            src_prop_inv_add_props_frac = latex_fraction(latex(src_prop), latex(inv_add_props))
            answer = ueval(src_prop) / ueval(inv_add_props)
     
            soln_stmt =  f"""
            $\\displaystyle 
            \\implies {latex(com_prop)}
            = {src_prop_add_prop_frac}
            = {src_prop_inv_add_props_frac}
            $
            """
            soln_stmts.append(soln_stmt.strip())
    
            answer_s =  f"""
            $\\displaystyle {src_prop_inv_add_props_frac} $
            """.strip()
            pass

        result = {
            'add_props': add_props,
            'add_props_latex': add_props_latex,
            'soln_stmts': soln_stmts,
            'answer_s': answer_s,
            'answer': answer,
            }
        
        return result
        pass


    def _get_subscripted_series(self, x, size):
        xs = [Symbol(f"{x}_{{{idx}}}") for idx in range(size)]
        return xs

    def _get_series_latex(self, xs, last_sep = ' and '):
        xs_latex = [f"$\\displaystyle {latex(item)}$" for item in xs]
        xs_latex = list_to_str(xs_latex, last_sep = last_sep)
        return xs_latex


    def get_parallel_inductance_data(self, src_prop, com_prop, add_prop, size, 
                                     solve_for = None):
        if solve_for is None:
            solve_for = com_prop

        t = Symbol('t')

        #src_prop, com_prop, add_prop = V, I, L

        add_props = self._get_subscripted_series(add_prop, size)
        add_props_latex = self._get_series_latex(add_props)
        
        soln_stmts = []

        soln_stmt =  f"""
        # override this statement index 0
        """
        soln_stmt = soln_stmt.replace("\n", "")
        #soln_stmts.append(soln_stmt.strip())

        com_props = self._get_subscripted_series(com_prop, size)
        com_props_sum = Add(*com_props)
        com_prop_eq = Eq(com_prop, com_props_sum)

        soln_stmt =  f"""
        $\\displaystyle {latex(com_prop_eq)}$
        """
        soln_stmts.append(soln_stmt.strip())

        
        #src_prop, com_prop, add_prop = V, I, L
        com_props_dt = [Derivative(item, t) for item in com_props]
        com_props_dt_sum = Add(*com_props_dt)
        com_props_dt_eq = Eq(Derivative(com_prop, t), com_props_dt_sum)
 
        soln_stmt =  f"""
        $\\displaystyle \\implies {latex(com_props_dt_eq)}
        \\qquad \\qquad \\cdots (i)
        $
        """
        soln_stmts.append(soln_stmt.strip())


        #src_prop, com_prop, add_prop = V, I, L
        Ii =  Symbol(f'{com_prop}_{{i}}')
        src_prop_i = Symbol(f"{latex(src_prop)}_{{i}}")
        add_prop_i = Symbol(f"{latex(add_prop)}_{{i}}")
        
        src_prop_expr_i = f"{latex(add_prop)}_{{i}} {latex(Derivative(Ii, t))}"
        src_prop_expr_i = Symbol(src_prop_expr_i)
        
        src_prop_i_eq = Eq(src_prop_i, src_prop_expr_i)
        src_prop_i_dt_eq = Eq(Derivative(Ii, t), src_prop_i / add_prop_i)

        soln_stmt =  f"""
        We know, 
        
        $\\displaystyle {latex(src_prop_i_eq)}$

        $\\displaystyle \\implies {latex(src_prop_i_dt_eq)}
        \\qquad \\qquad \\cdots (ii)
        $
        """
        soln_stmts.append(soln_stmt.strip())
 

        com_prop_dt = Derivative(com_prop)
        com_props_dt = [Derivative(item) for item in com_props]
        com_props_dt_sum = Add(*com_props_dt)
        com_prop_dt_eq = Eq(com_prop_dt, com_props_dt_sum)

 

        src_props = self._get_subscripted_series(src_prop, size)
        
        src_props_by_add_prop1 = [item1/item2 for item1, item2 in zip(src_props, add_props)]
        src_props_by_add_prop1 = Add(*src_props_by_add_prop1)
        src_props_by_add_prop1_eq = Eq(src_prop/add_prop, src_props_by_add_prop1)
 
        src_props_by_add_prop = [src_prop/item for item in add_props]
        src_props_by_add_prop = Add(*src_props_by_add_prop)
        src_props_by_add_prop_eq = Eq(src_prop/add_prop, src_props_by_add_prop)
 

 
        soln_stmt =  f"""
        Rewriting (i) with help of (ii):
        
        $\\displaystyle \\implies {latex(src_props_by_add_prop1_eq)}$
        """
        soln_stmts.append(soln_stmt.strip())
 
        soln_stmt =  f"""
        # override this statement index 5
        """
        soln_stmt = soln_stmt.replace("\n", "")
        #soln_stmts.append(soln_stmt.strip())

        soln_stmt =  f"""
        $\\displaystyle \\implies {latex(src_props_by_add_prop_eq)}$
        """
        soln_stmts.append(soln_stmt.strip())
 
 
 
        inv_add_props = [1/item for item in add_props]
        inv_add_props = Add(*inv_add_props)
        inv_add_props_eq = Eq(1/add_prop, inv_add_props)
 
        soln_stmt =  f"""
        $\\displaystyle \\implies {latex(inv_add_props_eq)}$
        """
        soln_stmts.append(soln_stmt.strip())

        inv_add_props_frac = latex_fraction(1, latex(inv_add_props))

        soln_stmt =  f"""
        $\\displaystyle 
        \\implies {latex(add_prop)}
        = {inv_add_props_frac}
        $
        """
        soln_stmts.append(soln_stmt.strip())


        if solve_for == add_prop:
            answer = inv_add_props_frac
            answer_s =  f"""
            $\\displaystyle {inv_add_props_frac}$
            """.strip()
            pass
        elif solve_for == src_prop:

            #src_prop, com_prop, add_prop = V, I, L
            answer_gross = ueval(add_prop) * ueval(Derivative(com_prop, t))
            
            answer = f"\\left( {inv_add_props_frac} \\right) {latex(Derivative(com_prop, t))}"
            
    
            soln_stmt =  f"""
            $\\displaystyle 
            \\implies 
            {latex(src_prop)} = {latex(answer_gross)}
            = {answer}
            $
            """
            soln_stmts.append(soln_stmt.strip())
    
            answer_s =  f"""
            $\\displaystyle {answer} $
            """.strip()
            pass
        else:
            #src_prop, com_prop, add_prop = V, I, L
            
            answer_dt = f"\\left( {latex(inv_add_props)} \\right) {latex(src_prop)}"
            
            answer = Integral(Symbol(answer_dt), t)
    
            soln_stmt =  f"""

            $\\displaystyle 
            \\implies 
            {latex(Derivative(com_prop, t))} = {latex(1 / add_prop)} {latex(src_prop)} 
            $

            """
            soln_stmts.append(soln_stmt.strip())
    
            soln_stmt =  f"""
            $\\displaystyle 
            \\implies 
            {latex(Derivative(com_prop, t))} = {answer_dt}
            $
            """
            soln_stmts.append(soln_stmt.strip())
    
            soln_stmt =  f"""
            $\\displaystyle 
            \\implies 
            {latex(com_prop)} = {latex(answer)}
            $
            """
            soln_stmts.append(soln_stmt.strip())
    
            answer_s =  f"""
            $\\displaystyle {latex(answer)} $
            """.strip()
            pass

        result = {
            'src_prop_i': src_prop_i,
            'add_props': add_props,
            'add_props_latex': add_props_latex,
            'soln_stmts': soln_stmts,
            'answer_s': answer_s,
            'answer': answer,
            }
        
        return result
        pass



    def get_series_inductance_data(self, src_prop, com_prop, add_prop, size, 
                                     solve_for = None):
        if solve_for is None:
            solve_for = com_prop

        t = Symbol('t')

        #src_prop, com_prop, add_prop = V, I, L

        add_props = self._get_subscripted_series(add_prop, size)
        add_props_latex = self._get_series_latex(add_props)
        
        soln_stmts = []

        soln_stmt =  f"""
        # override this statement index 0
        """
        soln_stmt = soln_stmt.replace("\n", "")
        #soln_stmts.append(soln_stmt.strip())

        src_props = self._get_subscripted_series(src_prop, size)
        src_props_sum = Add(*src_props)
        src_prop_eq = Eq(src_prop, src_props_sum)

        soln_stmt =  f"""
        $\\displaystyle {latex(src_prop_eq)}
        \\qquad \\qquad \\cdots (i)
        $
        """
        soln_stmts.append(soln_stmt.strip())

        #src_prop, com_prop, add_prop = V, I, L
        Ii =  Symbol(f'{com_prop}_{{i}}')
        src_prop_i = Symbol(f"{latex(src_prop)}_{{i}}")
        
        src_prop_expr_i = f"{latex(add_prop)}_{{i}} {latex(Derivative(Ii, t))}"
        src_prop_expr_i = Symbol(src_prop_expr_i)
        
        src_prop_i_eq = Eq(src_prop_i, src_prop_expr_i)

        soln_stmt =  f"""
        We know, 
        $\\displaystyle {latex(src_prop_i_eq)}
        \\qquad \\qquad \\cdots (ii)
        $
        """
        soln_stmts.append(soln_stmt.strip())
 
        com_props = self._get_subscripted_series(com_prop, size)
        
        #src_prop, com_prop, add_prop = V, I, L
        com_props_dt = [ueval(item1) * ueval(Derivative(item2, t))
                        for item1, item2 in zip(add_props, com_props)]
        com_props_dt_sum = Add(*com_props_dt)
        com_props_dt_eq = Eq(ueval(add_prop) * ueval(Derivative(com_prop, t)), 
                             com_props_dt_sum)
 
        soln_stmt =  f"""
        Rewriting (i) with help of (ii):
        
        $\\displaystyle \\implies {latex(com_props_dt_eq)} $
        """
        soln_stmts.append(soln_stmt.strip())


        soln_stmt =  f"""
        # override this statement index 5
        """
        soln_stmt = soln_stmt.replace("\n", "")
        #soln_stmts.append(soln_stmt.strip())

        #src_prop, com_prop, add_prop = V, I, L
        com_props_2_dt = [ueval(item) * ueval(Derivative(com_prop, t))
                        for item in add_props]
        com_props_2_dt_sum = Add(*com_props_2_dt)
        com_props_2_dt_eq = Eq(ueval(add_prop) * ueval(Derivative(com_prop, t)), 
                             com_props_2_dt_sum)

        soln_stmt =  f"""
        $\\displaystyle \\implies {latex(com_props_2_dt_eq)} $
        """
        soln_stmts.append(soln_stmt.strip())

        add_props_sum = Add(*add_props)
        add_prop_eq = Eq(add_prop, add_props_sum)

        soln_stmt =  f"""
        $\\displaystyle 
        \\implies {latex(add_prop_eq)}
        $
        """
        soln_stmts.append(soln_stmt.strip())


        if solve_for == add_prop:
            answer = add_prop_eq.rhs
            answer_s =  f"""
            $\\displaystyle {add_prop_eq.rhs}$
            """.strip()
            pass
        elif solve_for == src_prop:

            #src_prop, com_prop, add_prop = V, I, L
            answer_gross = ueval(add_prop) * ueval(Derivative(com_prop, t))
            
            answer = f"\\left( {add_prop_eq.rhs} \\right) {latex(Derivative(com_prop, t))}"
            
    
            soln_stmt =  f"""
            $\\displaystyle 
            \\implies 
            {latex(src_prop)} = {latex(answer_gross)}
            = {answer}
            $
            """
            soln_stmts.append(soln_stmt.strip())
    
            answer_s =  f"""
            $\\displaystyle {answer} $
            """.strip()
            pass
        else:
            #src_prop, com_prop, add_prop = V, I, L
            
            frac1 = latex_fraction(latex(src_prop), latex(add_prop))
            frac2 = latex_fraction(latex(src_prop), latex(add_prop_eq.rhs))
            
            answer = Integral(Symbol(frac2), t)
    
            soln_stmt =  f"""
            Using (ii):
            
            $\\displaystyle {src_prop} = {latex(com_props_dt_eq.lhs)} $

            $\\displaystyle 
            \\implies 
            {latex(Derivative(com_prop, t))} = {frac1} 
            $
            
            $\\displaystyle 
            \\implies 
            {latex(Derivative(com_prop, t))} = {frac2} 
            $
            """
            soln_stmts.append(soln_stmt.strip())
    
    
            soln_stmt =  f"""
            $\\displaystyle 
            \\implies 
            {latex(com_prop)} = {latex(answer)}
            $
            """
            soln_stmts.append(soln_stmt.strip())
    
            answer_s =  f"""
            $\\displaystyle {latex(answer)} $
            """.strip()
            pass

        result = {
            'src_prop_i': src_prop_i,
            'add_props': add_props,
            'add_props_latex': add_props_latex,
            'soln_stmts': soln_stmts,
            'answer_s': answer_s,
            'answer': answer,
            }
        
        return result
        pass


    def get_electric_field_constant(self, epsilon0 = None):
        if epsilon0 is None:
            epsilon0 = Symbol(f'\\epsilon_{{0}}')   
        
        k_latex = latex_fraction(1, latex(4 * sympy.pi *  epsilon0))
        k = Symbol(f'{k_latex}') 
        return k  

    def lambda_electric_field(self, epsilon0 = None, include_k = True):
        unit_r = lambda r: Symbol(latex(r).replace(f"\\vec", "\\hat"))
        q_by_r_sqr = lambda a,b: Symbol(
                            latex_fraction(a, 
                                           f"\\left| {latex(b)} \\right|^2"
                                           ))  

        if not include_k:
            func = lambda q, r: q_by_r_sqr(q, r) * unit_r(r) 
            return func
            
        k = self.get_electric_field_constant(epsilon0 = epsilon0)
        func = lambda q, r: k * q_by_r_sqr(q, r) * unit_r(r)
        return func

    def lambda_moment_of_inertia(self):
        func = lambda m, r: m * ueval(r ** 2)
        return func

    def _log_DELETED(self, sOut, to_print = None):
        if to_print is None:
            to_print = self.verbose
            
        if to_print:
            print(sOut)
    

    pass
#class AdditivePropertyHelper:

    