'''
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 AlgebraManager(BaseManager):
    '''
    AlgebraManager
    Example:
        ke = AlgebraManager()
        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(AlgebraManager, cls).__new__(cls, *args, **kwargs)
        for base_class in AlgebraManager.__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_a_2_variable_optimization_from_a_china_competition',
            '_problem_rooks_on_chessboard'
            ])
        pass

    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 = \\begin{{cases}} \\frac{{3}}{{2}} \\\\ \\frac{{3}}{{4}} + \\frac{{\\sqrt{{31}} i}}{{4}} \\\\ - \\frac{{3}}{{4}} - \\frac{{\\sqrt{{31}} i}}{{4}} \\end{{cases}}$
        
        $\\displaystyle y = \\begin{{cases}} \\frac{{3}}{{2}} \\\\ \\frac{{3}}{{4}} + \\frac{{\\sqrt{{31}} i}}{{4}} \\\\ - \\frac{{3}}{{4}} - \\frac{{\\sqrt{{31}} i}}{{4}} \\end{{cases}}$
        
        $\\displaystyle \\lambda = \\begin{{cases}} -\\frac{{1}}{{7}} \\\\ \\frac{{1}}{{14}} - \\frac{{9\\sqrt{{31}} i}}{{434}} \\\\ \\frac{{1}}{{14}} + \\frac{{9\\sqrt{{31}} i}}{{434}} \\end{{cases}}$

        As $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

    def _problem_rooks_on_chessboard(self, *args, **kwargs):
                
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        statement = f"""
        17 rooks are placed on an 8x8 chessboard. Prove that there are at least 3 rooks that 
        do not threaten each other.
        """
        problemTemplate.add_problem(statement.strip(), "text/html")
        
        soln_s = f"""
        Since there are 17 rooks in 8 rows, at least one row contains at least 3 rooks. Let this be row A. Disregard row A in the 
        following.

        The remaining 7 rows house at least 17 - 8 = 9 rooks. The Pigeonhole principle implies the existence of a row with at 
        least 2 rooks. Denote one of these rows B and remove it from further consideration.

        There at at least 9 - 8 = 1 rooks in the remaining 6 rows. It follows there is at least one row with at least one rook. 
        Denote one of these C.

        Now, let $R_C$ be any rook in row C. Since row B contains more than 1 rook, there is a rook $R_B$ in a column different from 
        that of $R_C$ so that the two do not threaten each other.

        Since row A contains at least 3 rooks, there is a rook $R_A$ in columns different from those of $R_B$ and $R_C$. So chosen rooks 
        do not threaten each other.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')


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


