'''
Created on 01-Apr-2021
@author: bthakur
'''
import random
import inspect
import traceback

from sympy.core.expr import UnevaluatedExpr

from sympy import ( latex, solve, simplify, 
                    pi, Rational,
                    exp, sin, cos, tan,
                    asin, acos, atan,
                    sinh, cosh, tanh,
                    log, exp, sqrt,
                    Eq,
                    symbols, Symbol, Function,
                    )

from numpy import linspace

from xv.util import number_to_nth, list_to_str
from xv.util import run_with_timeout

from ...helper import BaseHelper
from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate
        
# _func_transform_manager        
# FuncTransformManager        
        
class FuncTransformManager(BaseManager):
    '''
    Tranformation of function
    
    Example:
        ke = FuncTransformManager()
        ke
        
        ke.setTerms(5) #number of terms in polynomial
        
        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ke.getRandomProblem(problem_type = 1)
        ...
        ke.get_polynomial()
        ke.printPolynomial()
        
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()
        
        from sympy import *
        x = symbols('x')
        func = cos(x)
        ke.initProblem(func)        
        
    '''    
    def __new__(cls, *args, **kwargs):
        instance = super(FuncTransformManager, cls).__new__(cls, *args, **kwargs)
        for base_class in FuncTransformManager.__bases__:
            base_class.__init__(instance, *args, **kwargs)
        return instance
    
    def __init__(self, *args, **kwargs):
        self.base_helper = BaseHelper(**kwargs)
        pass
    
    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
                '_problem_tr_transforms_summary',
                '_problem_convert_tr_transforms',
                '_problem_convert_simp_transforms',
                '_problem_convert_simp_sum_of_terms_transforms',
             ])
        pass

    def _problem_tr_transforms_summary(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        ft_helper = self.base_helper.get_algebra_helper().get_func_transform_helper()
        tr_transforms = ft_helper.get_tr_transforms()
        result = ft_helper.func_transforms_to_str(tr_transforms)
                
        problem_s = f""" 
        Summary of trigonometric transformations:
        """
        problemTemplate.add_problem(problem_s, "text/html")

        soln_s = f"""
        {result['transforms_str']}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        {result['transforms_str']}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        pass
    
    def _problem_convert_trig_to_exp(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        ft_helper = self.base_helper.get_algebra_helper().get_func_transform_helper()
   
        from sympy import cos, sin, exp, I, UnevaluatedExpr as ueval
        
        from sympy.abc import x
        
        exprs = []

        expr = cos(x) + I*sin(x)
        expr_item = {
            'expr': expr,
            'transform': expr.rewrite(exp),
            }
        exprs.append(expr_item)
        
        expr = exp(x)
        expr_item = {
            'expr': expr,
            'transform': expr.rewrite(sin),
            }
        exprs.append(expr_item)
        
        expr = tan(x)
        expr_item = {
            'expr': expr,
            'transform': expr.replace(tan(x), sin(x)/cos(x)),
            }
        exprs.append(expr_item)

                
        identifier = f"{self.__class__.__name__}{id(self)}.{inspect.stack()[0][3]}"
        random_expr = self.get_no_repeat_random_choice(identifier, exprs)
                
        problem_s = f""" 
        Transform the following expression into other formats:
        $\\displaystyle {latex(random_expr['expr'])}$
        """
        problemTemplate.add_problem(problem_s, "text/html")

        soln_s = f"""
        $\\displaystyle {latex(random_expr['expr'])}$

        $\\displaystyle = {latex(random_expr['transform'])}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        pass

    def _problem_convert_tr_transforms(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        ft_helper = self.base_helper.get_algebra_helper().get_func_transform_helper()
        tr_transforms = ft_helper.get_tr_transforms()
        
        count = 4
        random_tr_transforms = ft_helper.get_random_sample_transforms(tr_transforms, 
                                                                  count = count)
        random_result = ft_helper.func_transforms_to_str(random_tr_transforms)
        
                
        problem_s = f""" 
        Transform the following trigonometric expression into other formats:
        {random_result['funcs_str']}
        """
        problemTemplate.add_problem(problem_s, "text/html")

        soln_s = f"""
        {random_result['transforms_str']}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        {random_result['transforms_str']}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        pass


    def _problem_convert_simp_transforms(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        ft_helper = self.base_helper.get_algebra_helper().get_func_transform_helper()
        result = ft_helper.get_simp_transforms()
        
                
        problem_s = f""" 
        Transform the following expression into simple format:
        
        $\\displaystyle {latex(result['expr'])} $
        
        """
        problemTemplate.add_problem(problem_s, "text/html")

        soln_s = f"""
        
        {result['soln_s']}
        """
        
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {latex(result['expr_transform'])} $
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        pass


    def _problem_convert_simp_sum_of_terms_transforms(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        ft_helper = self.base_helper.get_algebra_helper().get_func_transform_helper()
        result = ft_helper.get_sum_of_terms_transforms()
        
                
        problem_s = f""" 
        Transform the following expression into simple format:
        
        $\\displaystyle {latex(result['expr'])} $
        
        """
        problemTemplate.add_problem(problem_s, "text/html")

        soln_s = f"""
        {result['soln_s']}
        """
        
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        pass

