'''
Created on 01-Apr-2021
@author: bthakur
'''
import os 
#import decimal
from functools import reduce
from xv.km.ui import SvgHelper 

import numpy as np
import random
import inspect
import traceback
from sympy import (simplify, sympify, log, symbols, Symbol,
                    Eq, Matrix, latex, 
                   solve, Rational, diag, 
                   Add, Mul, Pow)

from xv.km.util import latex_fraction
        
from xv.util import toIntOrFloat
from mpmath import rand

from ...helper import BaseHelper
from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate
        
class MultiVariableManager(BaseManager):
    '''
    Algebra of multiple variables


    Minimum Grade: 4
    Maximum Grade: 12


    Examples
    --------
    ke = MultiVariableManager()
    ke 
    
    ke.printProblemTypes()
    ke.helpProblemType(0)
    
    ke.getRandomProblem()
    ke.getRandomProblem(problem_type = 0)



    doc_style: xv_doc
    ''' 


    
    _OPR_TYPE_COUNT = 10
    
    def __new__(cls, *args, **kwargs):
        instance = super(MultiVariableManager, cls).__new__(cls, *args, **kwargs)
        for base_class in MultiVariableManager.__bases__:
            base_class.__init__(instance, *args, **kwargs)
        return instance
    
    def __init__(self, *args, **kwargs):
        self.base_helper = BaseHelper(**kwargs)
        self._equations = None
        pass
    


    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
            '_problem_unit_qty_price_cost',
            '_problem_unit_period_price_cost',
            '_problem_unit_qty_differential_cost',
            '_problem_expression_into_equation',
            '_problem_transactions_into_equation',
            '_problem_solve_transactions',
            '_problem_solve_equations',
            '_problem_solve_equations_2',
            '_problem_solve_equations_advanced',
            
            ])
        pass

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


        Minimum Grade: 4
        Maximum Grade: 12

        doc_style: xv_doc
        """

        mv_helper = self.base_helper.get_algebra_helper().get_multi_variable_helper()
        result = mv_helper.get_random_problem_unit_qty_price_cost()
        
        
                
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
            
        problem_s = f"""
        {result['problem_statement'].strip()}
        {result['question']}
        """
        problemTemplate.add_problem(problem_s.strip(), "text/html")
        
        soln_s = f"""
        {result['solution']}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')


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


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


        Minimum Grade: 4
        Maximum Grade: 12

        doc_style: xv_doc
        """

        mv_helper = self.base_helper.get_algebra_helper().get_multi_variable_helper()
        result = mv_helper.get_random_problem_unit_period_price_cost()
        
        
                
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
            
        problem_s = f"""
        {result['problem_statement'].strip()}
        {result['question']}
        """
        problemTemplate.add_problem(problem_s.strip(), "text/html")
        
        soln_s = f"""
        {result['solution']}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')


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


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


        Minimum Grade: 4
        Maximum Grade: 12

        doc_style: xv_doc
        """

        mv_helper = self.base_helper.get_algebra_helper().get_multi_variable_helper()
        result = mv_helper.get_random_problem_unit_qty_differential_cost()
        
        
                
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
            
        problem_s = f"""
        {result['problem_statement'].strip()}
        {result['question']}
        """
        problemTemplate.add_problem(problem_s.strip(), "text/html")
        
        soln_s = f"""
        {result['solution']}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')


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


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


        Minimum Grade: 4
        Maximum Grade: 12

        doc_style: xv_doc
        """

        mv_helper = self.base_helper.get_algebra_helper().get_multi_variable_helper()
        result = mv_helper.get_random_problem_unit()
        
        
                
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
            
        problem_s = f"""
        {result['problem_statement'].strip()}
        {result['question']}
        """
        problemTemplate.add_problem(problem_s.strip(), "text/html")
        
        soln_s = f"""
        {result['solution']}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')


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


    def _problem_transactions_into_equation(self, *args, **kwargs):
        """
        Convert transactions into equations

        doc_style: xv_doc
        """
        
                
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
        x, y = random.sample(symbols('pizza icecream burger chocolate'), 2)
        currency_dict = {symbols('\$'): 1, symbols('Rs.'): 10}
        
        currency = random.choice(list(currency_dict.keys()))
        
        q1, q2 = list(np.random.randint(5, 10, size=2))
        q1_plus = random.randint(1, q1)
        q2_plus = random.randint(1, q2)
        
        c1, c2 = list(np.random.randint(2, 10, size=2) * currency_dict[currency])
        tc = q1 * c1 + q2 * c2

        tc_q1_plus = q1 * c1 + q2 * c2 + q1_plus * c1
        tc_q2_plus = q1 * c1 + q2 * c2 + q1_plus * c1 + q2_plus * c2
        
        eq = Eq(q1 * x + q2 * y, currency * tc)
        eq_q1_plus = Eq((q1 + q1_plus ) * x + q2 * y, currency * tc_q1_plus)
        eq_q2_plus = Eq((q1 + q1_plus ) * x + (q2 + q2_plus ) * y, currency * tc_q2_plus)
        
        problem_s = f"""
        I buy {q1} {x} and {q2} {y} for {currency} {tc}. 
        I buy {q1_plus} {x} more and pay a total amount of {currency} {tc_q1_plus}. 
        I buy {q2_plus} {y} in addition to the above and pay a total amount of {currency} {tc_q2_plus}. 
        
        Write equations for the above transactions.
        """
        problemTemplate.add_problem(problem_s.strip(), "text/html",
                                     add_html_line_break = True)
        
        soln_s = f"""
        {latex(eq)}

        {latex(eq_q1_plus)}

        {latex(eq_q2_plus)}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html',
                                     add_html_line_break = True)


        answer_s = f"""
        {latex(eq)}

        {latex(eq_q1_plus)}

        {latex(eq_q2_plus)}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html',
                                     add_html_line_break = True)
        
        return problemTemplate

    def _problem_solve_transactions(self, *args, **kwargs):
        """
        Find prices from transaction


        doc_style: xv_doc
        """
        
                
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
        x, y = random.sample(symbols('pizza icecream burger chocolate'), 2)
        currency_dict = {symbols('\$'): 1, symbols('Rs.'): 10}
        
        currency = random.choice(list(currency_dict.keys()))
        
        q1, q2 = list(np.random.randint(5, 10, size=2))
        q1_plus = random.randint(1, q1)
        q2_plus = random.randint(1, q2)
        
        c1, c2 = list(np.random.randint(2, 10, size=2) * currency_dict[currency])
        tc = q1 * c1 + q2 * c2

        tc_q1_plus = q1 * c1 + q2 * c2 + q1_plus * c1
        tc_q2_plus = q1 * c1 + q2 * c2 + q1_plus * c1 + q2_plus * c2
        
        eq = Eq(q1 * x + q2 * y, currency * tc)
        eq_q1_plus = Eq((q1 + q1_plus ) * x + q2 * y, currency * tc_q1_plus)
        eq_q2_plus = Eq((q1 + q1_plus ) * x + (q2 + q2_plus ) * y, currency * tc_q2_plus)
        
        problem_s = f"""
        I buy {q1} {x} and {q2} {y} for {currency} {tc}. 
        I buy {q1_plus} {x} more and pay a total amount of {currency} {tc_q1_plus}. 
        I buy {q2_plus} {y} in addition to the above and pay a total amount of {currency} {tc_q2_plus}. 
        
        Find prices of {x} and {y}.
        """
        problemTemplate.add_problem(problem_s.strip(), "text/html",
                                     add_html_line_break = True)
        
        soln_s = f"""
        {latex(eq)}
        {latex(eq_q1_plus)}
        {latex(eq_q2_plus)}

        Note: All amounts are in {currency}.
        
        The cost of {q1} {x} and {q2} {y} is {tc}. 
        
        When we buy {q1_plus} {x} more, we pay additional amount = {tc_q1_plus} - {tc} = {tc_q1_plus - tc}  
        
        Therefore, the price of one {x} = ${latex_fraction(tc_q1_plus - tc, q1_plus)}$ = {(tc_q1_plus - tc)//q1_plus}
        
        Similarly:
        When we buy {q2_plus} {y} more, we pay additional amount = {tc_q2_plus} - {tc_q1_plus} = {tc_q2_plus - tc_q1_plus}  
        
        Therefore, the price of one {y} = ${latex_fraction(tc_q2_plus - tc_q1_plus, q2_plus)}$ = {(tc_q2_plus - tc_q1_plus)//q2_plus}
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html',
                                     add_html_line_break = True)


        answer_s = f"""
        {x} = {(tc_q1_plus - tc)//q1_plus}
        
        {y} = {(tc_q2_plus - tc_q1_plus)//q2_plus}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html',
                                     add_html_line_break = True)
        
        return problemTemplate

    def _problem_solve_equations(self, *args, **kwargs):
        """
        Solve equations


        Minimum Grade: 4
        Maximum Grade: 12


    
        Examples
        --------
        from xv.math.algebra import MultiVariableManager
        ke = MultiVariableManager()


        ke.getRandomProblem(problem_type = '_problem_solve_equations')


        doc_style: xv_doc
        """
        
                
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
        x, y = random.sample(symbols('pizza icecream burger chocolate'), 2)
        currency_dict = {symbols('\$'): 1, symbols('Rs.'): 10}
        
        currency = random.choice(list(currency_dict.keys()))
        
        q1, q2 = list(np.random.randint(5, 10, size=2))
        q1_plus = random.randint(1, q1)
        q2_plus = random.randint(1, q2)
        
        c1, c2 = list(np.random.randint(2, 10, size=2) * currency_dict[currency])
        tc = q1 * c1 + q2 * c2

        tc_q1_plus = q1 * c1 + q2 * c2 + q1_plus * c1
        tc_q2_plus = q1 * c1 + q2 * c2 + q1_plus * c1 + q2_plus * c2
        
        eq = Eq(q1 * x + q2 * y, currency * tc)
        eq_q1_plus = Eq((q1 + q1_plus ) * x + q2 * y, currency * tc_q1_plus)
        eq_q2_plus = Eq((q1 + q1_plus ) * x + (q2 + q2_plus ) * y, currency * tc_q2_plus)
        
        problem_s = f"""
        Find prices of {x} and {y}.

        {latex(eq)}
        {latex(eq_q1_plus)}
        {latex(eq_q2_plus)}
        """
        problemTemplate.add_problem(problem_s.strip(), "text/html",
                                     add_html_line_break = True)
        
        soln_s = f"""
        {latex(eq)}         \t\t $\\cdots$ (i) 
        {latex(eq_q1_plus)} \t\t $\\cdots$ (ii) 
        {latex(eq_q2_plus)} \t\t $\\cdots$ (iii) 

        Note: All amounts are in {currency}.
        
        Compare (i) and (ii).
        We buy same {q2} {y} but buy {q1 + q1_plus} - {q1} = {q1_plus} {x} more.
        We pay additional amount = {tc_q1_plus} - {tc} = {tc_q1_plus - tc}  
        
        Therefore, the price of one {x} = ${latex_fraction(tc_q1_plus - tc, q1_plus)}$ = {(tc_q1_plus - tc)//q1_plus}
        
        Compare (ii) and (iii).  
        We buy same {q1 + q1_plus} {x} but buy {q2 + q2_plus} - {q2} = {q2_plus} {y} more.
        We pay additional amount = {tc_q2_plus} - {tc_q1_plus} = {tc_q2_plus - tc_q1_plus}  
        
        Therefore, the price of one {y} = ${latex_fraction(tc_q2_plus - tc_q1_plus, q2_plus)}$ = {(tc_q2_plus - tc_q1_plus)//q2_plus}
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html',
                                     add_html_line_break = True)


        answer_s = f"""
        {x} = {(tc_q1_plus - tc)//q1_plus}
        
        {y} = {(tc_q2_plus - tc_q1_plus)//q2_plus}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html',
                                     add_html_line_break = True)
        
        return problemTemplate

    def _problem_solve_equations_2(self, *args, **kwargs):
        """
        Solve equations


        doc_style: xv_doc
        """
        
                
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
        x, y = random.sample(symbols('pizza icecream burger chocolate'), 2)
        currency_dict = {symbols('\$'): 1, symbols('Rs.'): 10}
        
        currency = random.choice(list(currency_dict.keys()))
        
        q1, q2 = list(np.random.randint(5, 10, size=2))
        q1_plus = random.randint(1, q1)
        q2_plus = random.randint(1, q2)
        
        c1, c2 = list(np.random.randint(2, 10, size=2) * currency_dict[currency])
        tc = q1 * c1 + q2 * c2

        tc_q1_plus = q1 * c1 + q2 * c2 + q1_plus * c1
        tc_q2_plus = q1 * c1 + q2 * c2 + q1_plus * c1 + q2_plus * c2
        
        eq = Eq(q1 * x + q2 * y, currency * tc)
        eq_q1_plus = Eq((q1 + q1_plus ) * x + q2 * y, currency * tc_q1_plus)
        eq_q2_plus = Eq((q1 + q1_plus ) * x + (q2 + q2_plus ) * y, currency * tc_q2_plus)
        
        problem_s = f"""
        Find prices of {x} and {y}.

        {latex(eq_q1_plus)}
        {latex(eq)}
        {latex(eq_q2_plus)}
        """
        problemTemplate.add_problem(problem_s.strip(), "text/html",
                                     add_html_line_break = True)
        
        soln_s = f"""
        {latex(eq_q1_plus)} \t\t $\\cdots$ (i) 
        {latex(eq)}         \t\t $\\cdots$ (ii) 
        {latex(eq_q2_plus)} \t\t $\\cdots$ (iii) 

        Note: All amounts are in {currency}.
        
        Compare (i) and (ii).
        We buy same {q2} {y} but buy {q1 + q1_plus} - {q1} = {q1_plus} {x} more.
        We pay additional amount = {tc_q1_plus} - {tc} = {tc_q1_plus - tc}  
        
        Therefore, the price of one {x} = ${latex_fraction(tc_q1_plus - tc, q1_plus)}$ = {(tc_q1_plus - tc)//q1_plus}
        
        Compare (i) and (iii).  
        We buy same {q1 + q1_plus} {x} but buy {q2 + q2_plus} - {q2} = {q2_plus} {y} more.
        We pay additional amount = {tc_q2_plus} - {tc_q1_plus} = {tc_q2_plus - tc_q1_plus}  
        
        Therefore, the price of one {y} = ${latex_fraction(tc_q2_plus - tc_q1_plus, q2_plus)}$ = {(tc_q2_plus - tc_q1_plus)//q2_plus}
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html',
                                     add_html_line_break = True)


        answer_s = f"""
        {x} = {(tc_q1_plus - tc)//q1_plus}
        
        {y} = {(tc_q2_plus - tc_q1_plus)//q2_plus}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html',
                                     add_html_line_break = True)
        
        return problemTemplate

    def _problem_solve_equations_advanced(self, *args, **kwargs):
        """
        Solve equations


        doc_style: xv_doc
        """
        
                
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
        x, y = random.sample(symbols('pizza icecream burger chocolate'), 2)
        currency_dict = {symbols('\$'): 1, symbols('Rs.'): 10}
        
        currency = random.choice(list(currency_dict.keys()))
        
        q1, q2 = list(np.random.randint(5, 10, size=2))
        q1_plus = random.randint(1, q1)
        q2_plus = random.randint(1, q2)
        
        q1f = q1 + q1_plus
        q2f = q2 + q2_plus
        
        
        c1, c2 = list(np.random.randint(2, 10, size=2) * currency_dict[currency])
        tc = q1 * c1 + q2 * c2
        tcf = q1f * c1 + q2f * c2
        
        
        eq = Eq(q1 * x + q2 * y, currency * tc)
        eqf = Eq(q1f * x + q2f * y, currency * tcf)

        eq1 = (eq * q2f).cancel()
        eqf1 = (eqf * q2).cancel()

        x_price = abs(tc * q2f - tcf * q2)//abs(q1 * q2f - q1f * q2)


        eq_subs1 = Eq(q1 * x + q2 * y, tc)
        eq_subs2 = Eq(q1 * x_price + q2 * y, tc)
        eq_subs3 = Eq(q2 * y, tc - q1 * x_price)
        
        y_price = (tc - q1 * x_price)//q2
        eq_subs4 = Eq(y, y_price)
        
        problem_s = f"""
        Find prices of {x} and {y}.

        $\\displaystyle {latex(eq)}$
        $\\displaystyle {latex(eqf)}$
        """
        problemTemplate.add_problem(problem_s.strip(), "text/html",
                                     add_html_line_break = True)
        
        soln_s = f"""
        $\\displaystyle {latex(eq)} $     \t\t $\\cdots$ (i) 
        $\\displaystyle {latex(eqf)} $    \t\t $\\cdots$ (ii) 

        Note: All amounts are in {currency}.
        
        We want to cancel {y}. So we will make quantity of {y} same in both equations. 
        Multiply (i) with {q2f}:
        $\\displaystyle {latex(eq1)} $       \t\t $\\cdots$ (iii) 
        
        Multiply (ii) with {q2}:
        $\\displaystyle {latex(eqf1)} $       \t\t $\\cdots$ (iv) 
        
        Now, compare (iii) and (iv):

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



        if q1f * q2 - q1 * q2f > 0:        
            soln_s = f"""
            Additional quantity of {x} = {q1f * q2} - {q1 * q2f} = {q1f * q2 - q1 * q2f}
            
            Additional cost of {x} = {tcf * q2} - {tc * q2f} = {tcf * q2 - tc * q2f}
            
            """
        else:
            soln_s = f"""
            Additional quantity of {x} = {q1 * q2f} - {q1f * q2} = {q1 * q2f - q1f * q2}
            
            Additional cost of  {x} = {tc * q2f} - {tcf * q2} = {tc * q2f - tcf * q2}
            
            """
            
        problemTemplate.add_solution(soln_s.strip(), 'text/html',
                                     add_html_line_break = True)



        soln_s = f"""
        Therefore, the price of one {x} = $
        {latex_fraction(abs(tc * q2f - tcf * q2), abs(q1 * q2f - q1f * q2))}
        $ = {x_price}
        
        """
            
        problemTemplate.add_solution(soln_s.strip(), 'text/html',
                                     add_html_line_break = True)


        soln_s = f"""
        From equation (i):
        $\\displaystyle {latex(eq_subs1)} $      
        
        $\\displaystyle \\implies {latex(eq_subs2)} $ \t\t as 1 {x} = {x_price}

        $\\displaystyle \\implies {latex(eq_subs3)} $ \t\t subtract {q1 * x_price} from both sides 

        $\\displaystyle \\implies {latex(eq_subs4)} $ \t\t divide both sides by {q2}

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




        answer_s = f"""
        {x} = {x_price}
        {y} = {y_price}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html',
                                     add_html_line_break = True)
        
        return problemTemplate

    def _problem_TEMPLATE(self, *args, **kwargs):
                
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        statement = f"""
        """
        problemTemplate.add_problem(statement.strip(), "text/html",
                                     add_html_line_break = False)
        
        soln_s = f"""
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html',
                                     add_html_line_break = False)


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



