'''
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)

from numpy import linspace

from xv.util import number_to_nth
from xv.util import run_with_timeout

from ...helper import BaseHelper
from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate
        
class ArithmeticManager(BaseManager):
    '''
    ArithmeticManager
    Example:
        ke = ArithmeticManager()
        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ...
        
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()
        
        ke.printProblemTypes()
        
    '''    
    _OPR_TYPE_COUNT = 10
    
    def __new__(cls, *args, **kwargs):
        instance = super(ArithmeticManager, cls).__new__(cls, *args, **kwargs)
        for base_class in ArithmeticManager.__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_100_grasshoppers_on_a_triangular_board',
            '_problem_a_2_variable_optimization_from_a_china_competition',
            ])
        pass

    def _problem_100_grasshoppers_on_a_triangular_board(self, *args, **kwargs):
                
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        statement = f"""
        A triangular board has been cut into 100 small triangular cells by the lines parallel to its 
        sides. Two cells that share a side are said to be neighbors. In each cell there is a 
        grasshoper. All at once, the grasshoppers hop from their cells to neighboring cells. This 
        happens 9 times. Prove that at least 10 cells are now empty.
        """
        problemTemplate.add_problem(statement.strip(), "text/html")
        
        soln_s = f"""
        <img src = "https://www.cut-the-knot.org/arithmetic/Grasshoppers.gif"></img>
        The board is naturally colored into two colors so that the neighboring cells are colored differently. Let the colors be red 
        and brown and label the grasshoppers by the color of their cells. Convince yourself that there are 55 red and 45 brown 
        cells. In one hop, the brown grasshoppers move to the red cells thus emptying 55 cells. On the same hop, the brown 
        grasshoppers move to the red cells thus filling at most 45 red cells. Inevitably, at least 10 red cells will remain empty.

        The next time the grasshoppers move, they can move into their original cells, thus filling all of them. The situation will 
        return to the original one, while the argument will apply to every odd hop. Perhaps there may happen a greater mix-up 
        of the red and brown hoppers, but the best that may be claimed is that after every odd hop, there are at least 10 empty 
        cells.

        In general, there are n(n+1)/2 red cells and n(n-1)/2 brown cells. The difference being n(n+1)/2 - n(n-1)/2 = n, there are 
        always at least n empty cells after an odd number of hops.

        The specific number of hops (9) is nothing but a red herring.


        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')


        answer_s = soln_s
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

    def _problem_a_2_variable_optimization_from_a_china_competition(self, *args, **kwargs):
                
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        statement = f"""
        Let $x, y$ be real numbers such that
        $\\displaystyle x^{{3}}+y^{{3}}+\\frac{{x+y}}{{4}}=\\frac{{15}}{{2}}$
        Find maximum value of $x+y$.
        """
        problemTemplate.add_problem(statement.strip(), "text/html")
        
        soln_s = f"""
        Using Lagrange multipliers,
        $\\displaystyle F{{\\left(x,y,\\lambda \\right)}} = f{{\\left(x,y \\right)}} + \\lambda \\left( g{{\\left(x,y \\right)}} - k\\right)$

        Let $\\displaystyle f{{\\left(x,y \\right)}} = x + y$ and $\\displaystyle g{{\\left(x,y \\right)}} = x^{{3}} + y^{{3}} + \\frac{{x + y}}{{4}} - \\frac{{15}}{{2}}$ and $k = 0$,
        $\\displaystyle F{{\\left(x,y,\\lambda \\right)}} = x + y + \\lambda \\left(x^{{3}} + y^{{3}} + \\frac{{x + y}}{{4}} - \\frac{{15}}{{2}}\\right)$

        $\\displaystyle \\frac{{\\partial}}{{\\partial x}} F{{\\left(x,y,\\lambda \\right)}} = \\lambda \\left(3 x^{{2}} + \\frac{{1}}{{4}}\\right) + 1 = 0 $ $\\quad (1)$

        $\\displaystyle \\frac{{\\partial}}{{\\partial y}} F{{\\left(x,y,\\lambda \\right)}} = \\lambda \\left(3 y^{{2}} + \\frac{{1}}{{4}}\\right) + 1 = 0$ $\\quad (2)$

        $\\displaystyle \\frac{{\\partial}}{{\\partial \\lambda}} F{{\\left(x,y,\\lambda \\right)}} = x^{{3}} + y^{{3}} + \\frac{{x + y}}{{4}} - \\frac{{15}}{{2}} = 0$ $\\quad (3)$

        Solving the equtions (1), (2) and (3),
        $\\displaystyle x = \\frac{{3}}{{2}}, \\frac{{3}}{{4}} + \\frac{{\\sqrt{{31}} i}}{{4}}, - \\frac{{3}}{{4}} - \\frac{{\\sqrt{{31}} i}}{{4}}$
        $\\displaystyle y = \\frac{{3}}{{2}}, \\frac{{3}}{{4}} + \\frac{{\\sqrt{{31}} i}}{{4}}, - \\frac{{3}}{{4}} - \\frac{{\\sqrt{{31}} i}}{{4}}$
        $\\displaystyle \\lambda = -\\frac{{1}}{{7}}, \\frac{{1}}{{14}} - \\frac{{9\\sqrt{{31}} i}}{{434}}, \\frac{{1}}{{14}} + \\frac{{9\\sqrt{{31}} i}}{{434}}$

        As the $x, y \\in \\mathbb{{R}}$, $\\displaystyle x = \\frac{{3}}{{2}}$ and $\\displaystyle x = \\frac{{3}}{{2}}$ are the solutions.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')


        answer_s = soln_s
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

