'''
Created on 16-Apr-2021

@author: bthakur
'''
import os 
import numpy as np
import random
import inspect
import traceback

import sympy

from sympy import ( latex,symbols, diff, Symbol, Mul, Matrix, Function,
                    factorial, sympify, Rational, log,
                    Derivative, factor, Eq, simplify, expand,
                    exp, sin, cos, cosh, sinh, pi, sqrt, atan, Limit,
                    expand_trig, trigsimp, srepr, Integer, Pow, Add)

from sympy import UnevaluatedExpr as ueval

from sympy.core.numbers import One, Integer
from sympy.simplify.fu import TR1, TR2, TR2i, fu, TR16, TR22


from ...helper import BaseHelper, CalculusHelper
from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate

# _integration_overview_manager
# IntegrationOverviewManager
        
class IntegrationOverviewManager(BaseManager):
    '''
    Integration 
    Example:
        ke = IntegrationOverviewManager()
        ke
        
        ke.printProblemTypes()
        
        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ke.getRandomProblem(problem_type = 1)
        ...
        
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()
        
        
    '''    
    def __new__(cls, *args, **kwargs):
        instance = super(IntegrationOverviewManager, cls).__new__(cls, *args, **kwargs)
        for base_class in IntegrationOverviewManager.__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_random_integration',
            #'_problem_integration_ax_plus_b',
            '_problem_proof_of_identity_sets',
            '_problem_trig_functions',
            '_problem_integration_trig',
            '_problem_integration_by_var_change',
            '_problem_integration_by_transform',
            '_problem_separable_functions',
            '_problem_transform_ax_plus_b',
            '_problem_transform_numerator',
                
             ])
        pass
    
    def _problem_random_integration(self, *args, **kwargs):
        keyword = kwargs.get('keyword', None)

        intgr_helper = self.base_helper.get_calculus_helper().get_integration_helper()
        result = intgr_helper.get_solution(keyword = keyword)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
        problem_s = f"""
        {result['problem_s']}
        """
        
        problemTemplate.add_problem(problem_s.strip(), 'text/html')


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

        pass

    def _problem_proof_of_identity_sets(self, *args, **kwargs):
        """

        doc_style: xv_doc
        """
        ti_helper = self.base_helper.get_trigonometry_helper().get_trig_identity_helper()
        result = ti_helper.get_problem_random_identities_set()
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        prob_s = f"""
        {result['prob_s']}
        """
        problemTemplate.add_problem(prob_s.strip(), 'text/html')
        
        soln_s = f"""
        {result['soln_s']}
        """
        
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        {result['answer_s']}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate


    def _problem_trig_functions(self, *args, **kwargs):
        keyword = 'trig'

        intgr_helper = self.base_helper.get_calculus_helper().get_integration_helper()
        result = intgr_helper.get_solution(keyword = keyword)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
        problem_s = f"""
        {result['problem_s']}
        """
        
        problemTemplate.add_problem(problem_s.strip(), 'text/html')


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

        pass


    def _problem_integration_trig(self, *args, **kwargs):
        keyword = 'trig'

        intgr_helper = self.base_helper.get_calculus_helper().get_integration_helper()
        result = intgr_helper.get_solution(keyword = keyword)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
        problem_s = f"""
        {result['problem_s']}
        """
        
        problemTemplate.add_problem(problem_s.strip(), 'text/html')


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

        pass

    def _problem_integration_by_var_change(self, *args, **kwargs):
        keyword = 'by_var_change'

        intgr_helper = self.base_helper.get_calculus_helper().get_integration_helper()
        result = intgr_helper.get_solution(keyword = keyword)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
        problem_s = f"""
        {result['problem_s']}
        """
        
        problemTemplate.add_problem(problem_s.strip(), 'text/html')


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

        pass

    def _problem_integration_by_transform(self, *args, **kwargs):
        keyword = 'by_transform'

        intgr_helper = self.base_helper.get_calculus_helper().get_integration_helper()
        result = intgr_helper.get_solution(keyword = keyword)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
        problem_s = f"""
        {result['problem_s']}
        """
        
        problemTemplate.add_problem(problem_s.strip(), 'text/html')


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

        pass


    def _problem_separable_functions(self, *args, **kwargs):
        keyword = kwargs.get('keyword', None)

        de_helper = self.base_helper.get_calculus_helper().get_differential_equation_helper()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        result = de_helper.get_random_separable_functions(keyword = keyword)
        
        problem_s = f"""
        {result['problem_s']}
        """
        
        problemTemplate.add_problem(problem_s.strip(), 'text/html')


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

        pass

    
    def _problem_transform_ax_plus_b(self, *args, **kwargs):
        keyword = kwargs.get('keyword', None)

        intgr_helper = self.base_helper.get_calculus_helper().get_integration_helper()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        a, x, b, n = intgr_helper.get_default_symbs('axbn')
        
        sexpr = a + b * x
        expr_list = [
            1 / sexpr,
            sexpr ** n,
            x / sexpr,
            x**2 / sexpr,
            ]

        expr =  random.choice(expr_list[-1:])
        
        expr_list2 = [
            1 / sexpr,
            sexpr ** n,
            x ** 2 / sexpr, 
            1 / (x * sexpr),
            1 / (x ** 2 * sexpr),
            x / sexpr ** 2,
            x ** 2 / sexpr ** 2,
            1 / (x * sexpr ** 2),
            x / sexpr ** 3,
            
            ]
        
        result = intgr_helper.transform_ax_plus_b(expr, sexpr, x)
        self.result = result
        
        problem_s = f"""
        Solve: $\\displaystyle {latex(result['i_expr_dx'])} $
        """
        
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

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


    def _problem_transform_numerator(self, *args, **kwargs):
        keyword = kwargs.get('keyword', None)

        intgr_helper = self.base_helper.get_calculus_helper().get_integration_helper()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        a, x, b, n = intgr_helper.get_default_symbs('axbn')
        
        sexpr = a + b * x
        
        expr_list = [
            1 / sexpr,
            sexpr ** n,
            x ** 2 / sexpr, 
            1 / (x * sexpr),
            1 / (x ** 2 * sexpr),
            x / sexpr ** 2,
            x ** 2 / sexpr ** 2,
            1 / (x * sexpr ** 2),
            x / sexpr ** 3,
            2 / ((x-3) * (x-4)),
            ]
        
        expr = random.choice(expr_list)
        
        result = intgr_helper.transform_numerator(expr, x)
        self.result = result
        
        problem_s = f"""
        Solve: $\\displaystyle {latex(result['i_expr_dx'])} $
        """
        
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

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

