'''
Created on 12-Jul-2021

@author: rishi_priyansh
'''
import inspect
import traceback

from sympy import (Symbol, symbols, Function, latex, Eq,
                   pi,
                   UnevaluatedExpr,
                   Integral,
                   sin, cos, pi
                   )


from xv.km.ui import SvgHelper         


class GaussLawHelper:
    def __init__(self, b = None, e = None, count = 2, **kwargs):
        self.verbose = kwargs.get('verbose', False)
        pass

    def get_gauss_law(self):
        E = Symbol("\overrightarrow{E}")
        q = Symbol("q")
        r = Symbol("r")
        r_unit = Symbol("\hat{r}\\;")
        
        S = Symbol("\overrightarrow{S}")
        
        
        epsilon  = Symbol(r"\epsilon_0")
        theta  = Symbol(r"\theta")
        
        k = 1 / (4 * pi * epsilon)
        E_rhs = UnevaluatedExpr(k) *  UnevaluatedExpr(q / r**2) * UnevaluatedExpr(r_unit)
        eq = Eq(E, E_rhs)
        
        gross_rhs = UnevaluatedExpr(E_rhs) * UnevaluatedExpr(4 * pi * r**2)
        eq_gauss_gross = Eq(LineIntegral(E, S), gross_rhs)
        eq_gauss = Eq(LineIntegral(E, S), q / epsilon)
        
        
        result = {
            'eq': eq,
            'eq_gauss_gross': eq_gauss_gross,
            'eq_gauss': eq_gauss,
            }
        
        return result
        pass
            
    pass
#class GaussLawHelper:


import sympy
class LineIntegral(sympy.Expr):
        
    def __init__(self, integrand, var, var2 = None):
        if var2 is None:
            var2 = list(integrand.free_symbols)[0]
        
        path = self._get_circle(var2, var)
        self.path = path
        
        Ii = Integral(integrand, var).transform(
            var, path.funcs[var]).subs(path.funcs)
        
        self.parametrized = Integral(Ii.args[0], path.limits)
        self.unparamatrized = Integral(integrand, var)

    def doit(self):
        return self.parametrized.doit()
    
    def _latex(self, printer):
        args = [printer._print(arg) 
                for arg in [self.path.name,
                            self.unparamatrized.args[0],
                            self.unparamatrized.args[1][0]
                            ]
                ]
        
        overrightarrow = r'\overrightarrow'
        if f"{args[2]}".startswith(overrightarrow):
            args[2] = overrightarrow + r"{d" + f"{args[2]}"[len(overrightarrow)+1:]
            pass
        
        if self.path.closed:   
            return rf"\oint_{{{args[0]}}} {{{args[1]}}} \, {{{args[2]}}}"

        #return r"\oint_{%s} %s \, d%s" % tuple(args)
        return rf"\oint_{{{args[0]}}} {{{args[1]}}} \, {{{args[2]}}}"
        pass
    
    def _get_circle(self, x, y):
        t = Symbol('t')
        circle = _IntegralPath('C', t, 
                      {x: cos(t), 
                       y: sin(t)}, 
                      (t, 0, 2*pi))
        return circle
    
class _IntegralPath:
    def __init__(self, name, t, funcs, limits):

        self.name = name
        self.t = t
        self.funcs = funcs
        self.limits = limits
        start, end = [{var: self.funcs[var].subs(t, self.limits[k_]) 
                       for var in funcs.keys()} 
                       for k_ in (1, 2)]
                      
        self.closed = start == end 
    
    
    