'''
Created on 20-Jan-2022

@author: bthakur
'''

import codecs
import inspect
import traceback
import random
import numpy as np
import pandas as pd
from sympy import (latex, Symbol, symbols,
                   Matrix, Identity, nsimplify,
                    Rational,
                    sin, cos, tan,
                    asin, acos, atan,
                    sinh, cosh, tanh,
                    log, exp, sqrt,
                   diff, factor, 
                   Function, Eq,
                   Add, 
                   simplify, solve, factorial,
                   UnevaluatedExpr as ueval
                   )
from sympy import Sum, Indexed, pi, oo, Integral
import sympy
from sympy.core.numbers import One, Integer
from sympy.series import series

from xv.km.util import latex_fraction


from xv.km.ui import SvgHelper
from xv.util.data import CacheUtil

import matplotlib.pyplot as plt
from xv.util import CategorizedSampleData, list_to_str
from xv.km.util._latex import latex_color


class FourierHelper:
    
    def __init__(self, **kwargs):
        self.verbose = kwargs.get('verbose', False)
        pass
    
    
    def _expr_for_coeff_b_n(self, f, m, n, t, a0, T0):
        soln_items = []

        omega0_expr = 2 * pi / T0
        omega0 = Symbol(latex(omega0_expr))

        cos_expr = ueval(Indexed('a',n))  * ueval(cos(omega0 * n * t))
        sin_expr = ueval(Indexed('b',n))  * ueval(sin(omega0 * n * t))

        mult1 = sin(ueval(omega0_expr) * ueval(m * t))
        mult1_symb = self._expr_to_symbol(mult1, 'brown')
        
        term_lhs = mult1_symb * ueval(f)
        
        term0 = ueval(mult1_symb) * ueval(a0)      
        cos_term = ueval(mult1_symb) * Sum(cos_expr, (n, 1, oo))
        sin_term = ueval(mult1_symb) * Sum(sin_expr, (n, 1, oo))
        term_rhs = term0 + cos_term + sin_term
        term_rhs_symb = Symbol(f"""
        {latex(term0)} + {latex(cos_term)} + {latex(sin_term)}
        """)

        eq1_1 = Eq(term_lhs, term_rhs_symb)
        
        soln_item = f"""
        Multiply both sides with $\\displaystyle {latex(mult1_symb)} $:
        
        $\\displaystyle \\implies {latex(eq1_1)} $
        """
        
        soln_items.append(soln_item.strip())

        # remove color        
        mult1_symb = self._expr_to_symbol(mult1)
        
        term_lhs = mult1_symb * ueval(f)
        
        term0 = ueval(mult1_symb) * ueval(a0)      
        cos_term = Sum(ueval(mult1_symb) * cos_expr, (n, 1, oo))
        sin_term = Sum(ueval(mult1_symb) * sin_expr, (n, 1, oo))
        term_rhs = term0 + cos_term + sin_term
        term_rhs_symb = Symbol(f"""
        {latex(term0)} + {latex(cos_term)} + {latex(sin_term)}
        """)

        eq1_2 = Eq(term_lhs, term_rhs_symb)
        
        soln_item = f"""
        eq1_2 $\\displaystyle \\implies {latex(eq1_2)} $
        """
        
        soln_items.append(soln_item.strip())
        
        lhs = Integral(term_lhs, (t, -T0/2, T0/2))
        
        rhs_t0 = Integral(term0, (t, -T0/2, T0/2))
        rhs_t1 = Integral(cos_term, (t, -T0/2, T0/2))
        rhs_t2 = Integral(sin_term, (t, -T0/2, T0/2))
        
        colors = ['red', 'green', 'blue']
        rhs_t0_colored = self._expr_to_symbol(rhs_t0, colors[0])
        rhs_t1_colored = self._expr_to_symbol(rhs_t1, colors[1])
        rhs_t2_colored = self._expr_to_symbol(rhs_t2, colors[2])
        
        rhs_str = f""" 
        {latex(rhs_t0_colored)} + {latex(rhs_t1_colored)} + {latex(rhs_t2_colored)} 
        """
        rhs = Symbol(rhs_str.strip())
        eq2 = Eq(lhs, rhs)
        
        I, I3, I4, I5 = symbols('I I_3 I_4 I_5')
        I3_colored = self._expr_to_symbol(I3, colors[0])
        I4_colored = self._expr_to_symbol(I4, colors[1])
        I5_colored = self._expr_to_symbol(I5, colors[2])

        I_rhs_str = f""" 
        {latex(I3_colored)} + {latex(I4_colored)} + {latex(I5_colored)} 
        """
        I_rhs = Symbol(I_rhs_str.strip())
        I_eq = Eq(I, I_rhs)
        
        soln_item = f"""
        $\\displaystyle \\implies {latex(eq2)} $
        
        $\\displaystyle \\implies {latex(I_eq)} 
        \\qquad \\qquad \\cdots (i)
        $
        
        """
        
        soln_items.append(soln_item.strip())


        I3_eq = Eq(I3, rhs_t0)
        rhs_t0_expr = a0 * mult1
        rhs_t0_expr = Integral(rhs_t0_expr, (t, -T0/2, T0/2))
        I3_eq_soln = Eq(I3, rhs_t0_expr.doit())
        
        soln_item = f"""
        Solving for $\\displaystyle {latex(I3_eq.lhs)} $:
        <div style="color:{colors[0]};">
        
        $\\displaystyle {latex(I3_eq)} $
        
        $\\displaystyle = {latex(rhs_t0_expr)} $
        
        $\\displaystyle = {latex(rhs_t0_expr.doit())} $
        
        $\\displaystyle \\implies {latex(I3_eq_soln)} 
        \\qquad \\qquad \\cdots (ii)
        $
        </div>
        """
        
        soln_items.append(soln_item.strip())


        I4_eq = Eq(I4, rhs_t2)
        cos_term_mult1 =  ueval(Indexed('a',n)) * ueval(mult1) * ueval(cos(omega0 * n * t))
        expr_intgr = Integral(cos_term_mult1, (t, -T0/2, T0/2))
        rhs_t2_expr = Sum(expr_intgr, (n, 1, oo))
        
        rhs_t2_expr_intgr_doit = 0

        I4_eq_soln = Eq(I4, rhs_t2_expr_intgr_doit)
        
        soln_item = f"""
        Solving for $\\displaystyle {latex(I4_eq.lhs)} $:
        <div style="color:{colors[2]};">
        
        $\\displaystyle {latex(I4_eq)} $
        
        rhs_t2_expr = $\\displaystyle = {latex(rhs_t2_expr)} $
        
        rhs_t2_expr_intgr_doit = $\\displaystyle = {latex(rhs_t2_expr_intgr_doit)}$
        
        $\\displaystyle \\implies {latex(I4_eq_soln)} 
        \\qquad \\qquad \\cdots (iv)
        $
        </div>
        """
        
        soln_items.append(soln_item.strip())



        I5_eq = Eq(I5, rhs_t1)
        sin_term_mult1 =  ueval(Indexed('a',n)) * ueval(mult1) * ueval(sin(omega0 * n * t))
        expr_intgr = Integral(sin_term_mult1, (t, -T0/2, T0/2))
        rhs_t1_expr = Sum(expr_intgr, (n, 1, oo))
        
        rhs_t1_expr_reduced = ueval(Indexed('a',m)) * ueval(mult1) * ueval(sin(omega0 * m * t))
        rhs_t1_expr_reduced = Integral(rhs_t1_expr_reduced, (t, -T0/2, T0/2))
        
        rhs_t1_expr_reduced_doit = ueval(Indexed('a',m)) * ueval(T0/2)
        
        I5_eq_soln = Eq(I5, rhs_t1_expr_reduced_doit)
        
        soln_item = f"""
        Solving for $\\displaystyle {latex(I5_eq.lhs)} $:
        <div style="color:{colors[1]};">
        
        $\\displaystyle {latex(I5_eq)} $
        
        $\\displaystyle = {latex(rhs_t1_expr)} $

        $\\displaystyle = {latex(rhs_t1_expr_reduced)} $

        $\\displaystyle = {latex(rhs_t1_expr_reduced_doit)} $
        
        $\\displaystyle \\implies {latex(I5_eq_soln)} 
        \\qquad \\qquad \\cdots (iii)
        $
        </div>
        """
        
        soln_items.append(soln_item.strip())


        I_eq_soln_rhs = f"""
        {latex(I3_eq_soln.rhs)} + {latex(I4_eq_soln.rhs)} + {latex(I5_eq_soln.rhs)}
        """
        I_eq_soln_rhs = Symbol(I_eq_soln_rhs.strip())
        
        I_eq_soln_ueval = Eq(eq2.lhs, I_eq_soln_rhs)
        
        I_eq_soln = Eq(eq2.lhs, I3_eq_soln.rhs + I4_eq_soln.rhs + I5_eq_soln.rhs)
        
        a_m_eq = Eq(ueval(Indexed('a',m)), ueval(2/T0) * eq2.lhs)
        
        mult2 = sin(ueval(omega0_expr) * ueval(n * t))
        mult2_symb = Symbol(latex(ueval(f) * mult2))
        a_n_eq_rhs = ueval(2/T0) * ueval(Integral(mult2_symb, (t, -T0/2, T0/2)))

        a_n_eq = Eq(ueval(Indexed('a',n)), a_n_eq_rhs)
        
        soln_item = f"""
        Hence, from (i), (ii), (iii) and (iv):
        
        $\\displaystyle {latex(I_eq)} $
        
        $\\displaystyle \\implies {latex(I_eq_soln_ueval)} $
        
        $\\displaystyle \\implies {latex(I_eq_soln)} $
        
        $\\displaystyle \\implies {latex(a_m_eq)} $
        
        Which can be written as:
        
        $\\displaystyle \\implies {latex(a_n_eq)} $
        
        """
        
        soln_items.append(soln_item.strip())


        
        return soln_items
        pass
