'''
'''
import random
import inspect
import traceback
import re

from sympy import (symbols, Symbol, limit, latex, Function,
                   Limit, Derivative, simplify,
                   expand_log,
                   Mul, Add, Pow, UnevaluatedExpr as ueval,
                   Sum, binomial, factorial, Rational, Integral
                   )
import sympy as sp
from sympy import (acos, acot, acoth, acsc, asec, asin, 
                   asinh, atan, atan2, atanh, 
                   cos, cosh, cot, coth, csc, sec, 
                   sin, sinc, sinh, tan, tanh)
       

from xv.km.util import latex_fraction

from xv.util import UtilClass

# _working_helper
# WorkingHelper
class WorkingHelper(UtilClass):
    '''
    
    doc_style: xv_doc
    '''    
    


    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        pass
    
    def get_problem_WORKING(self, **kwargs):
        x, L = symbols('x, L')
        t1 = x**2
        t2 = sin(1/x)
        t3 = x
        t4 = (1 + x)**(1/x)
        t5 = sp.exp(1)
        numr_expr = t1*t2 + t3
        denm_expr = t4 - t5
        
        expr = numr_expr/denm_expr
        lim_expr = Limit(expr, x, 0)

        prob_s = f"""
        Evaluate 
        $\\displaystyle 
        {latex(lim_expr)}
        $
        """
        
        
        soln_stmts = []
        
        numr_expr_0_symb = Symbol(f'''0^2 \\cdot {latex(t2)} + 0''')
        
        denm_expr_0_symb = Symbol(f'''{latex(t5)} - {latex(t5)}''')
        
        numr_expr_0 = 0
        denm_expr_0 = 0
        soln_stmt = f"""

        $\\displaystyle 
        \\begin{{aligned}}

        {latex(L)} 
        & = {latex(lim_expr)}
        \\\\ \\\\
        
        & = \\frac{{ {latex(numr_expr_0_symb)} }}{{ {latex(denm_expr_0_symb)} }}
        \\\\ \\\\

        & = \\frac{{ {latex(numr_expr_0)} }}{{ {latex(denm_expr_0)} }}

        \\end{{aligned}}
        $

        """
        soln_stmts.append(soln_stmt.strip())

        
        numr_expr_step1 = Derivative(numr_expr, x)
        denm_expr_step1 = Derivative(denm_expr,x)
        
        expr_step1 = numr_expr_step1/denm_expr_step1
        lim_expr_step1 = Limit(expr_step1, x, 0)

        numr_expr_step2 = numr_expr_step1.doit()
        denm_expr_step2 = denm_expr_step1.doit()
        
        expr_step2 = numr_expr_step2/denm_expr_step2
        lim_expr_step2 = Limit(expr_step2, x, 0)

        soln_stmt = f"""
        Applying l'hopital rule:

        $\\displaystyle 
        \\begin{{aligned}}

        {latex(L)} 
        & = {latex(lim_expr_step1)} 
        \\\\ \\\\

        & = \\frac{{ {latex(numr_expr_step2)} }}{{ {latex(denm_expr_step2)} }}

        \\\\ \\\\

        
        \\end{{aligned}}
        $

        """
        soln_stmts.append(soln_stmt.strip())
                
        soln_stmt = f"""


        """
        soln_stmts.append(soln_stmt.strip())
        
        soln_s = "\n\n".join(soln_stmts)
        
        answer_s = f"""
        $\\displaystyle 
        $
        """
        
        
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        
        
        return result
        pass

    def get_problem_stirlings_approximation(self, **kwargs):
        
        x, n = symbols('x, n')
        t1 = factorial(n)
        t2 = sp.log(t1)
        t3 = sp.log(x)
        t4 = Sum(t3, (x, 1, n))
        t4_inte = Integral(t3, (x, 1, n))
        
        prob_s = f"""
        Derive Stirling's approximation
        """
        
        
        soln_stmts = []
        
        t4_inte_step1 = t4_inte.doit()
        t4_inte_step2 = t4_inte_step1 - 1
        
        t2_step3 = sp.exp(t2)
        t4_inte_step3 = sp.exp(t4_inte_step2)

        multiplier = sp.sqrt(2*sp.pi*n)

        soln_stmt = f"""
        $\\displaystyle 
        \\begin{{aligned}}
        {latex(t2)} 
        &= {latex(t4)} \\\\
        &= {latex(t4_inte)} \\\\
        &= {latex(t4_inte_step1)} \\\\
        
        \\Rightarrow {latex(t2)} &\\approx {latex(t4_inte_step2)}  \\qquad \\text {{ for large }} {latex(n)} \\text {{, }}+1 \\text {{ term is negligible }} \\\\

        \\Rightarrow {latex(t2_step3)} &\\approx {latex(t4_inte_step3)} \\\\

        \\Rightarrow {latex(t2_step3)} &\\approx {latex(multiplier)} \\cdot {latex(t4_inte_step3)} \\qquad \\text {{ Multiple }} {latex(multiplier)} \\text {{ for better approximation }} \\\\
        
        
        \\end{{aligned}}
        $

        """
        soln_stmts.append(soln_stmt.strip())
                
        soln_stmt = f"""


        """
        soln_stmts.append(soln_stmt.strip())
        
        soln_s = "\n\n".join(soln_stmts)
        
        answer_s = f"""
        $\\displaystyle 
        {latex(t2_step3)} \\approx {latex(multiplier)} \\cdot {latex(t4_inte_step3)}
        $
        """
        
        
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        
        
        return result
        pass

    def get_sample(self, **kwargs):
        
        prob_s = f"""
        $\\displaystyle 
        $
        """
        
        
        soln_stmts = []
        
        soln_stmt = f"""


        """
        soln_stmts.append(soln_stmt.strip())
                
        soln_stmt = f"""


        """
        soln_stmts.append(soln_stmt.strip())
        
        soln_s = "\n\n".join(soln_stmts)
        
        answer_s = f"""
        $\\displaystyle 
        $
        """
        
        
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
        }
        return result
        pass