'''
Created on 4-Jan-2023

@author: b thakur

'''

import random
import inspect
import traceback

from ..helper import BaseHelper

from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate

from sympy import UnevaluatedExpr as ueval
from sympy import latex

# _overview_manager
# OverviewManager

class OverviewManager(BaseManager):
    '''
    OverviewManager
    Example:
        ke = OverviewManager()
        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ...
        
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()
        
        ke.printProblemTypes()
        
    '''    
    
    def __new__(cls, *args, **kwargs):
        instance = super(OverviewManager, cls).__new__(cls, *args, **kwargs)
        for base_class in OverviewManager.__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_useful_links',
            '_problem_notations_in_math',
            ])
        pass

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

        doc_style: xv_doc
        """
        
        wl_helper = self.base_helper.get_web_link_helper()
        search_str = 'overview'
        result = wl_helper.search(search_str)
        
        result = wl_helper.convert_links_to_strs(result)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        if result is None:
            problemTemplate.add_problem(f"""
            No result found matching: 
                search_str = '{search_str}'
            """.strip(), 'text/html')
            return problemTemplate

        problem_s = f"""
        Useful links related to Math
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        
        soln_s = result['anchors_str']
        problemTemplate.add_solution(soln_s.strip(), 'text/html',
                                     add_html_line_break = False)
        
        answer_s = soln_s
        problemTemplate.add_answer(answer_s.strip(), 'text/html',
                                   add_html_line_break = False)
        
        return problemTemplate
                

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

        problem_s = f"""
        Symbols in Maths
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        
    
    
        $\\mathbb{{C}} \\quad$ set of complex numbers
        
        $\\widehat{{\\mathbb{{C}}}} \\quad$ set of extended complex numbers $\\mathbb{{C}} \\cup\\{{\\infty\\}}$
        
        $\\mathbb{{N}} \\quad$ set of natural numbers (nonnegative integers)
        
        $\\mathbb{{N}}^* \\quad$ set of positive integers $\\mathbb{{N}} \\backslash\\{{0\\}}$
        
        $\\mathbb{{Q}} \\quad$ set of rational numbers
        
        $\\mathbb{{R}} \\quad$ set of real numbers
        
        $\\mathbb{{Z}} \\quad$ set of integers
        
        $\\mathbb{{Z}} / n \\mathbb{{Z}} \\quad$ ring of residues modulo $n$
        
        $C^n \\quad \\text {{ set of (real or complex) functions with }} n \\text {{ continuous derivatives in the region of interest }}$
        
        $\\Re(z) \\quad$ real part of a complex number $z$
        
        $\\Im(z) \\quad$ imaginary part of a complex number $z$
        
        $\\bar{{z}} \\quad$ conjugate of a complex number $z$
        
        $|z|$ Euclidean norm of a complex number $z$, or absolute value of a scalar $z$
        
        $B_n \\quad$ Bernoulli numbers, $\\sum_{{n \\geq 0}} B_n z^n / n !=z /\\left(e^z-1\\right)$
        
        $C_n \\quad$ scaled Bernoulli numbers, $C_n=B_{{2 n}} /(2 n) !$
        
        $\\sum C_n z^{{2 n}}=(z / 2) / \\tanh (z / 2)$
        
        $T_n \\quad$ tangent numbers, $\\sum T_n z^{{2 n-1}} /(2 n-1) !=\\tan z$
        
        $H_n \\quad$ harmonic number $\\sum_{{j=1}}^n 1 / j \\quad(0$ if $n \\leq 0)$
        
        $\\left(\\begin{{array}}{{l}}n \\\\ k\\end{{array}}\\right) \\quad$ binomial coefficient " $n$ choose $k "=n ! /(k !(n-k) !)$ ( 0 if $k<0$ or $k>n$ )
        
    
        $\\beta$ "word" base (usually $2^{{32}}$ or $2^{{64}}$ ) or "radix" (floating-point)
        
        $n$ "precision": number of base $\\beta$ digits in an integer or in a floating-point significand, or a free variable
        
        $\\varepsilon \\quad$ "machine precision" $\\beta^{{1-n}} / 2$ or (in complexity bounds) an arbitrarily small positive constant
        
        $\\eta \\quad$ smallest positive subnormal number
        
        $\\circ(x), \\circ_n(x) \\quad$ rounding of real number $x$ in precision $n$ 
        
        ulp $(x) \\quad$ for a floating-point number $x$, one unit in the last place
        
        $M(n) \\quad$ time to multiply $n$-bit integers, or polynomials of degree $n-1$, depending on the context
        
        $\\sim M(n) \\quad$ a function $f(n)$ such that $f(n) / M(n) \\rightarrow 1$ as $n \\rightarrow \\infty$ (we sometimes lazily omit the " $\\sim$ " if the meaning is clear)
        
        $\\begin{{array}}{{ll}}M(m, n) & \\text {{ time to multiply an }} m \\text {{-bit integer by an }} n \\text {{-bit integer }} \\\\ D(n) & \\text {{ time to divide a }} 2 n \\text {{-bit integer by an }} n \\text {{-bit integer, }}\\end{{array}}$ giving quotient and remainder
        
        $a \\mid b \\quad a$ is a divisor of $b$, that is $b=k a$ for some $k \\in \\mathbb{{Z}}$
        
        $a=b \\bmod m \\quad$ modular equality, $m \\mid(a-b)$
        
        $q \\leftarrow a \\operatorname{{div}} b \\quad$ assignment of integer quotient to $q(0 \\leq a-q b<b)$
        
        $r \\leftarrow a \\bmod b \\quad$ assignment of integer remainder to $r(0 \\leq r=a-q b<b)$
        
        $(a, b) \\quad$ greatest common divisor of $a$ and $b$
        
        
        
        $a \\mid b \\quad a$ is a divisor of $b$, that is $b=k a$ for some $k \\in \\mathbb{{Z}}$
        
        $a=b \\bmod m \\quad$ modular equality, $m \\mid(a-b)$
        
        $q \\leftarrow a \\operatorname{{div}} b \\quad$ assignment of integer quotient to $q(0 \\leq a-q b<b)$
        
        $r \\leftarrow a \\bmod b \\quad$ assignment of integer remainder to $r(0 \\leq r=a-q b<b)$
        
        $(a, b) \\quad$ greatest common divisor of $a$ and $b$
        
        $\\left(\\frac{{a}}{{b}}\\right)$ or $(a \\mid b) \\quad$ Jacobi symbol ( $b$ odd and positive)
        
        iff $\\quad$ if and only if
        
        $i \\wedge j$ bitwise and of integers $i$ and $j$, or logical and of two Boolean expressions
        
        $i \\vee j$ bitwise or of integers $i$ and $j$, or logical or of two Boolean expressions
        
        $i \\oplus j$ bitwise exclusive-or of integers $i$ and $j$
        
        $i \\ll k \\quad$ integer $i$ multiplied by $2^k$
        
        $i \\gg k$ quotient of division of integer $i$ by $2^k$
        
        $a \\cdot b, a \\times b \\quad$ product of scalars $a, b$
        
        $a * b$ cyclic convolution of vectors $a, b$
        
        $\\nu(n) \\quad 2$-valuation: largest $k$ such that $2^k$ divides $n(\\nu(0)=\\infty)$
        
        $\\sigma(e) \\quad$ length of the shortest addition chain to compute $e$
        
        $\\phi(n) \\quad$ Euler's totient function, $\\#\\{{m: 0<m \\leq n \\wedge(m, n)=1\\}}$
        
        
        
    
        
    
        
        $[a, b] \\quad$ closed interval $\\{{x \\in \\mathbb{{R}}: a \\leq x \\leq b\\}}($ empty if $a>b)$
        
        $(a, b) \\quad$ open interval $\\{{x \\in \\mathbb{{R}}: a<x<b\\}}$ (empty if $a \\geq b$ )
        
        $[a, b), \\quad(a, b] \\quad$ half-open intervals, $a \\leq x<b, a<x \\leq b$ respectively
        
        $\\widehat{{a_j}}$ element of the (forward) Fourier transform of vector $a$
        
        $\\tilde{{a}}_j$ element of the backward Fourier transform of vector $a$
        
        $$
        \\begin{{array}}{{ll}}
        f(n)=O(g(n)) & \\exists c, n_0 \\text {{ such that }}|f(n)| \\leq c g(n) \\text {{ for all }} n \\geq n_0 \\\\
        f(n)=\\Omega(g(n)) & \\exists c>0, n_0 \\text {{ such that }}|f(n)| \\geq c g(n) \\text {{ for all }} n \\geq n_0 \\\\
        f(n)=\\Theta(g(n)) & f(n)=O(g(n)) \\text {{ and }} g(n)=O(f(n)) \\\\
        f(n) \\sim g(n) & f(n) / g(n) \\rightarrow 1 \\text {{ as }} n \\rightarrow \\infty \\\\
        f(n)=o(g(n)) & f(n) / g(n) \\rightarrow 0 \\text {{ as }} n \\rightarrow \\infty \\\\
        f(n) \\ll g(n) & f(n)=O(g(n)) \\\\
        f(n) \\gg g(n) & g(n) \\ll f(n) \\\\
        f(x) \\sim \\sum_0^n a_j / x^j & f(x)-\\sum_0^n a_j / x^j=o\\left(1 / x^n\\right) \\text {{ as }} x \\rightarrow+\\infty
        \\end{{array}}
        $$
        
                                
        
    
        
        
        
        
        
        
        
        
                    
                                        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = soln_s
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

        

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

        problem_s = f"""
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

        