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

import random
import inspect
import traceback
from sympy import (simplify, sympify, log, symbols, Symbol,
                    Eq, Matrix, latex,
                   solve, Rational, diag,
                   Add, Mul, Pow, Matrix, exp,
                   E, sin, cos, I, series, pi
                   )
from sympy.abc import theta
import numpy as np
import sympy as sp


from xv.km.util import latex_fraction

from xv.util import toIntOrFloat
from mpmath import rand


from xv.km.kelements import KPrintElement

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


class EulerNumberManager(BaseManager):
    '''
    EulerNumberManager
    Example:
        ke = EulerNumberManager()
        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(EulerNumberManager, cls).__new__(cls, *args, **kwargs)
        for base_class in EulerNumberManager.__bases__:
            base_class.__init__(instance, *args, **kwargs)
        return instance

    def __init__(self, *args, **kwargs):
        self.base_helper = BaseHelper(**kwargs)
        self._equation = None
        self.x = symbols('x')
        pass



    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
            '_problem_plot_unit_circle_mark_sin_cos_coordinates',
            '_problem_plot_unit_circle_relation_sin_cos_pi_by_2',

            '_problem_deduce_composite_A_B',
            '_problem_deduce_composite_A_multiples',
            '_problem_deduce_composite_A_B_C',
            '_problem_deduce_values_of_cos',

            '_problem_define_euler_number',
            '_problem_express_euler_number_as_a_series',
            '_problem_polynomial_maclaurin_expression_e_x',
            '_problem_polynomial_maclaurin_expression_sin_x',
            '_problem_polynomial_maclaurin_expression_cos_x',
            '_problem_express_e_i_theta_as_a_series',
            '_problem_prove_e_i_theta_as_sin_cos',
            '_problem_sin_cos_expr_as_euler_number',
            #'_problem_define_euler_detailed_content',
            ])
        pass


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

        doc_style: xv_doc
        """

        theta = Symbol('theta')

        circle_helper = self.base_helper.get_geometry_helper().get_circle_helper()
        plot_method = circle_helper.plot_unit_circle_mark_sin_cos_coordinates

        result = circle_helper.get_plot_code_and_svg_str(plot_method)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        if result is None:
            prob_s = f"""
            Error: Failed to plot a unit circle.
            """
            problemTemplate.add_problem(prob_s.strip(), 'text/html')
            return problemTemplate


        plot_code = result['plot_code']

        prob_s = f"""
        Plot a unit circle and mark points in terms of ${latex(cos(theta))}
        $ and ${latex(sin(theta))}$.
        """
        problemTemplate.add_problem(prob_s.strip(), 'text/html')

        soln_s = f"""
        <pre>{plot_code}</pre>
        """

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

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

        return problemTemplate
        pass



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

        doc_style: xv_doc
        """

        theta = Symbol('theta')

        circle_helper = self.base_helper.get_geometry_helper().get_circle_helper()
        plot_method = circle_helper.plot_unit_circle_relation_sin_cos_pi_by_2

        result = circle_helper.get_plot_code_and_svg_str(plot_method)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        if result is None:
            prob_s = f"""
            Error: Failed to plot a unit circle.
            """
            problemTemplate.add_problem(prob_s.strip(), 'text/html')
            return problemTemplate


        plot_code = result['plot_code']

        prob_s = f"""
        Plot a unit circle and show relation between cos and sin of $
        {latex(theta)}$ and $\\displaystyle
        {latex(sp.pi / 2)} - {latex(theta)}$.
        """
        problemTemplate.add_problem(prob_s.strip(), 'text/html')

        soln_s = f"""
        As sin is opposite side of the angle in a triangle, cos the adjacent.
        We can easily see that:

        $\\displaystyle cos({latex(theta)}) = sin({latex(sp.pi / 2)} - {latex(theta)})$

        $\\displaystyle sin({latex(theta)}) = cos({latex(sp.pi / 2)} - {latex(theta)})$
        <h3>Code to draw plot:</h3>
        <pre>{plot_code}</pre>
        """

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

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

        return problemTemplate
        pass



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

        en_helper = self.base_helper.get_algebra_helper().get_euler_number_helper()

        problem_s = f"""
        Define Euler's number {latex(E)}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        {en_helper.get_definition()}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        {en_helper.get_definition()}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

    def _problem_express_euler_number_as_a_series(self, *args, **kwargs):

        en_helper = self.base_helper.get_algebra_helper().get_euler_number_helper()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        x = symbols('x')
        func = exp(x)

        problem_s = f"""
        Express ${latex(func)}$ as a polynomial series of ${x}$.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        func_series = series(func, x)

        soln_s = f"""
        ${latex(func)} = {latex(func_series)}$

        In more familiar form:
        {en_helper.exp_x()}

        We can write ${latex(E)}$ as a series:

        {en_helper.as_series()}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        ${latex(func_series)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate



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

        ph = self.base_helper.get_algebra_helper().get_polynomial_helper()
        n = 5
        x = ph.x

        func, a = exp(x), 0
        x_val = a

        #result = ph.compute_taylor_series_for_a_func(func, x, a, n, x_val)

        timeout = 5
        result = run_with_timeout(
                          f'Thread_compute_taylor_series_for_a_func',
                          ph.compute_taylor_series_for_a_func,
                          (func, x, a, n, x_val),
                          timeout = timeout,
                          verbose = self.verbose)

        if not result:
            statement = f"""
            Failed to compute Maclaurin series of ${latex(func)}$ at ${latex(x)} = {latex(x_val)}$
            """
            problemTemplate.add_problem(statement, "text/html")
            return problemTemplate


        statement = f"""
        Derive Maclaurin series of ${result['func_latex']}$"""
        problemTemplate.add_problem(statement, "text/html")

        soln_s = f"""
        $\\displaystyle {result['eq_applied_latex']}$

        Calculate derivatives with respect to ${latex(x)}$

        {result['derivative_series_str']}
        $\\cdots$

        Substituting the value ${latex(x)} = {latex(x_val)}$:


        {result['derivative_series_subs_str']}
        $\\cdots$

        Rewrite the standard Maclaurin series with the computed values:

        $\\displaystyle {result['std_series_equation_latex']} + \\cdots$

        $\\displaystyle \\implies {result['rewitten_eq_latex']} + \\cdots$

        $\\displaystyle \\implies {result['rewitten_eq_final_latex']} + \\cdots$

        In simplified format:

        $\\displaystyle \\implies {latex(result['answer'])} + \\cdots$

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

        answer_s = f"""
        $\\displaystyle {result['rewitten_eq_final_latex']} + \\cdots$

        In simplified format:

        $\\displaystyle {latex(result['answer'])} + \\cdots$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass

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

        ph = self.base_helper.get_algebra_helper().get_polynomial_helper()
        n = 5
        x = ph.x

        func, a = sin(x), 0
        x_val = a

        #result = ph.compute_taylor_series_for_a_func(func, x, a, n, x_val)

        timeout = 5
        result = run_with_timeout(
                          f'Thread_compute_taylor_series_for_a_func',
                          ph.compute_taylor_series_for_a_func,
                          (func, x, a, n, x_val),
                          timeout = timeout,
                          verbose = self.verbose)

        if not result:
            statement = f"""
            Failed to compute Maclaurin series of ${latex(func)}$ at ${latex(x)} = {latex(x_val)}$
            """
            problemTemplate.add_problem(statement, "text/html")
            return problemTemplate


        statement = f"""
        Derive Maclaurin series of ${result['func_latex']}$"""
        problemTemplate.add_problem(statement, "text/html")

        soln_s = f"""
        $\\displaystyle {result['eq_applied_latex']}$

        Calculate derivatives with respect to ${latex(x)}$

        {result['derivative_series_str']}
        $\\cdots$

        Substituting the value ${latex(x)} = {latex(x_val)}$:

        {result['derivative_series_subs_str']}
        $\\cdots$

        Rewrite the standard Maclaurin series with the computed values:

        $\\displaystyle {result['std_series_equation_latex']} + \\cdots$

        $\\displaystyle \\implies {result['rewitten_eq_latex']} + \\cdots$

        $\\displaystyle \\implies {result['rewitten_eq_final_latex']} + \\cdots$

        In simplified format:

        $\\displaystyle \\implies {latex(result['answer'])} + \\cdots$

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

        answer_s = f"""
        $\\displaystyle {result['rewitten_eq_final_latex']} + \\cdots$

        In simplified format:

        $\\displaystyle {latex(result['answer'])} + \\cdots$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass

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

        ph = self.base_helper.get_algebra_helper().get_polynomial_helper()
        n = 5
        x = ph.x

        func, a = cos(x), 0
        x_val = a

        #result = ph.compute_taylor_series_for_a_func(func, x, a, n, x_val)

        timeout = 5
        result = run_with_timeout(
                          f'Thread_compute_taylor_series_for_a_func',
                          ph.compute_taylor_series_for_a_func,
                          (func, x, a, n, x_val),
                          timeout = timeout,
                          verbose = self.verbose)

        if not result:
            statement = f"""
            Failed to compute Maclaurin series of ${latex(func)}$ at ${latex(x)} = {latex(x_val)}$
            """
            problemTemplate.add_problem(statement, "text/html")
            return problemTemplate


        statement = f"""
        Derive Maclaurin series of ${result['func_latex']}$"""
        problemTemplate.add_problem(statement, "text/html")

        soln_s = f"""
        $\\displaystyle {result['eq_applied_latex']}$

        Calculate derivatives with respect to ${latex(x)}$

        {result['derivative_series_str']}
        $\\cdots$

        Substituting the value ${latex(x)} = {latex(x_val)}$:

        {result['derivative_series_subs_str']}
        $\\cdots$

        Rewrite the standard Maclaurin series with the computed values:

        $\\displaystyle {result['std_series_equation_latex']} + \\cdots$

        $\\displaystyle \\implies {result['rewitten_eq_latex']} + \\cdots$

        $\\displaystyle \\implies {result['rewitten_eq_final_latex']} + \\cdots$

        In simplified format:

        $\\displaystyle \\implies {latex(result['answer'])} + \\cdots$

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

        answer_s = f"""
        $\\displaystyle {result['rewitten_eq_final_latex']} + \\cdots$

        In simplified format:

        $\\displaystyle {latex(result['answer'])} + \\cdots$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass

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

        func = random.choice([
            exp(I*theta),
            cos(theta),
            sin(theta),
            ])

        problem_s = f"""
        Express ${latex(func)}$ as a polynomial series of ${latex(theta)}$.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        func_series = series(func, theta)

        soln_s = f"""
        ${latex(func)}$
        $= {latex(func_series)}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        ${latex(func_series)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

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

        funcs = [
            exp(I*theta),
            cos(theta),
            sin(theta),
            ]

        func_series = [ series(func, theta) for func in funcs]

        problem_s = f"""
        Prove
        ${latex(funcs[0])} = {latex(funcs[1])} + {latex(I * funcs[2])}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')


        soln_s = f"""
        ${latex(funcs[0])} = {latex(func_series[0])}$

        ${latex(funcs[1])} = {latex(func_series[1])}$

        ${latex(funcs[2])} = {latex(func_series[2])}$

        $\\implies {latex(funcs[0])} = {latex(funcs[1])} + {latex(I * funcs[2])}$

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

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

        return problemTemplate

    def _problem_sin_cos_expr_as_euler_number(self, *args, **kwargs):

        en_helper = self.base_helper.get_algebra_helper().get_euler_number_helper()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Define sin and cos as function Euler's number {latex(E)}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        z = r"$e^{ix} = \cos x+i\sin x$"
        z_ = r"$e^{-ix} = \cos x-i\sin x$"

        soln_s = f"""
        {z}
        {z_}

        Thus, we can write:

        ${en_helper.expr_cos_latex()}$

        ${en_helper.expr_sin_latex()}$

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

        answer_s = f"""
        ${en_helper.expr_cos_latex()}$

        ${en_helper.expr_sin_latex()}$

        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate


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

        A, B = symbols('A B', real = True)
        pm = random.choice([1,  -1])
        B = pm * B

        E_A_B_lhs = exp(I * (A + B))
        E_A_B_rhs = exp(I * A) * exp(I * B)
        E_A_B_lhs_expanded = exp(I * (A + B)).rewrite(cos)
        E_A_B_rhs_expanded = exp(I * A).rewrite(cos) * exp(I * B).rewrite(cos)

        E_A_B_lhs_expanded_2 = E_A_B_lhs_expanded
        E_A_B_rhs_expanded_2 = E_A_B_rhs_expanded.expand(force = True)
        #self.E_A_B_rhs_expanded_2  = E_A_B_rhs_expanded_2

        problem_s = f"""
        Find formula of

        ${latex(sp.re(E_A_B_lhs_expanded_2))} $ and

        ${latex(sp.im(E_A_B_lhs_expanded_2))} $

        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html',
                                    add_html_line_break = False
                                     )



        soln_s = f"""
        ${latex(E_A_B_lhs)} = {latex(E_A_B_rhs)}$

        $\\implies {latex(E_A_B_lhs_expanded)} = {latex(E_A_B_rhs_expanded)}$

        $\\implies {latex(E_A_B_lhs_expanded_2)} = {latex(E_A_B_rhs_expanded_2)}$

        Taking real terms of both sides:
        $\\implies {latex(sp.re(E_A_B_lhs_expanded_2))}
        = {latex(sp.re(E_A_B_rhs_expanded_2))}
        $

        Taking imaginary terms of both sides:
        $\\implies {latex(sp.im(E_A_B_lhs_expanded_2))}
        = {latex(sp.im(E_A_B_rhs_expanded_2))}
        $

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

        answer_s = f"""
        ${latex(sp.re(E_A_B_lhs_expanded_2))}
        = {latex(sp.re(E_A_B_rhs_expanded_2))}
        $

        ${latex(sp.im(E_A_B_lhs_expanded_2))}
        = {latex(sp.im(E_A_B_rhs_expanded_2))}
        $

        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

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

        A, B = symbols('A B', real = True)
        fctr = random.choice([2, 3, 4])

        E_A_B_lhs = exp(I * (A * fctr))
        E_A_B_rhs = exp(I * A) ** fctr
        E_A_B_rhs_latex = f"\\left({latex(exp(I * A))}\\right)^{{{fctr}}}"

        E_A_B_lhs_expanded = E_A_B_lhs.rewrite(cos)
        E_A_B_rhs_expanded = (exp(I * A).rewrite(cos)) ** fctr

        E_A_B_lhs_expanded_2 = E_A_B_lhs_expanded
        E_A_B_rhs_expanded_2 = E_A_B_rhs_expanded.expand(force = True)
        #self.E_A_B_rhs_expanded_2  = E_A_B_rhs_expanded_2

        re_lhs = sp.re(E_A_B_lhs_expanded_2)
        re_rhs = sp.re(E_A_B_rhs_expanded_2)

        im_lhs = sp.im(E_A_B_lhs_expanded_2)
        im_rhs = sp.im(E_A_B_rhs_expanded_2)



        problem_s = f"""
        Find formula of

        ${latex(re_lhs)} $ and

        ${latex(im_lhs)} $
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html',
                                    add_html_line_break = False
                                     )

        soln_s = f"""
        ${latex(E_A_B_lhs)} = {E_A_B_rhs_latex}$

        $\\implies {latex(E_A_B_lhs_expanded)} = {latex(E_A_B_rhs_expanded)}$

        $\\implies {latex(E_A_B_lhs_expanded_2)} = {latex(E_A_B_rhs_expanded_2)}$

        Taking real terms of both sides:
        $\\implies {latex(re_lhs)}
        = {latex(re_rhs)}$

        Taking imaginary terms of both sides:
        $\\implies {latex(im_lhs)}
        = {latex(im_rhs)}$

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

        if fctr == 2:
            soln_s = f"""
            We can also write
            ${latex(re_lhs)} $
            $= {latex(re_rhs)}$
            $= {latex(1 - 2 * sin(A) ** 2)} $
            $= {latex(2 * cos(A) ** 2 - 1)}$

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

            pass


        answer_s = f"""
        ${latex(re_lhs)} = {latex(re_rhs)}
        $

        ${latex(im_lhs)} = {latex(im_rhs)}
        $

        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

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

        A, B, C = symbols('A B C', real = True)
        B = random.choice([1,  -1]) * B
        C = random.choice([1,  -1]) * C

        E_A_B_lhs = exp(I * (A + B + C))
        E_A_B_rhs = exp(I * A) * exp(I * B) * exp(I * C)
        E_A_B_lhs_expanded = E_A_B_lhs.rewrite(cos)
        E_A_B_rhs_expanded = exp(I * A).rewrite(cos) * exp(I * B).rewrite(cos)  * exp(I * C).rewrite(cos)

        E_A_B_lhs_expanded_2 = E_A_B_lhs_expanded
        E_A_B_rhs_expanded_2 = E_A_B_rhs_expanded.expand(force = True)

        re_lhs = sp.re(E_A_B_lhs_expanded_2)
        re_rhs = sp.re(E_A_B_rhs_expanded_2)

        im_lhs = sp.im(E_A_B_lhs_expanded_2)
        im_rhs = sp.im(E_A_B_rhs_expanded_2)

        problem_s = f"""
        Find formula of

        ${latex(re_lhs)} $ and

        ${latex(im_lhs)} $

        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html',
                                    add_html_line_break = False
                                     )

        soln_s = f"""
        ${latex(E_A_B_lhs)} = {latex(E_A_B_rhs)}$

        $\\implies {latex(E_A_B_lhs_expanded)} = {latex(E_A_B_rhs_expanded)}$

        $\\implies {latex(E_A_B_lhs_expanded_2)}$
        $= {latex(E_A_B_rhs_expanded_2)}$

        Taking real terms of both sides:
        $\\implies {latex(re_lhs)}$
        $= {latex(re_rhs)}
        $

        Taking imaginary terms of both sides:
        $\\implies {latex(im_lhs)}
        = {latex(im_rhs)}
        $

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

        answer_s = f"""
        ${latex(re_lhs)}$
        $= {latex(re_rhs)}
        $

        ${latex(im_lhs)}$
        $= {latex(im_rhs)}
        $

        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

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

        A, B = symbols('A B', real = True)
        fctr = random.choice([
            Rational(1, 3),
            Rational(1, 2),
            Rational(2, 3),
            Rational(4, 3),
            Rational(5, 3),
            2
            ])

        E_A_B_lhs = exp(I * (A * fctr))
        E_A_B_rhs = exp(I * A) ** fctr

        E_A_B_lhs_expanded = E_A_B_lhs.rewrite(cos)
        E_A_B_rhs_expanded = (exp(I * A).rewrite(cos)) ** fctr

        E_A_B_lhs_expanded_2 = E_A_B_lhs_expanded
        E_A_B_rhs_expanded_2 = E_A_B_rhs_expanded.expand(force = True)

        re_lhs = sp.re(E_A_B_lhs_expanded_2)
        re_rhs = sp.re(E_A_B_rhs_expanded_2)

        im_lhs = sp.im(E_A_B_lhs_expanded_2)
        im_rhs = sp.im(E_A_B_rhs_expanded_2)

        self.result = (re_lhs, re_rhs, im_lhs, im_rhs)

        re_lhs_v = re_lhs.subs({A:pi/2, B:fctr * pi/2})
        re_rhs_v = re_rhs.subs({A:pi/2, B:fctr * pi/2})

        im_lhs_v = im_lhs.subs({A:pi/2, B:fctr * pi/2})
        im_rhs_v = im_rhs.subs({A:pi/2, B:fctr * pi/2})

        problem_s = f"""
        Find formula of

        ${latex(re_lhs)} $ and

        ${latex(im_lhs)} $
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html',
                                    add_html_line_break = False
                                     )

        soln_s = f"""
        ${latex(E_A_B_lhs)} = {latex(E_A_B_rhs)}$

        $\\implies {latex(E_A_B_lhs_expanded)} = {latex(E_A_B_rhs_expanded)}$

        $\\implies {latex(E_A_B_lhs_expanded_2)} = {latex(E_A_B_rhs_expanded_2)}$

        Taking real terms of both sides:
        $\\implies {latex(re_lhs)}$
        $= {latex(re_rhs)}$

        $\\implies {latex(re_lhs_v)} = {latex(re_rhs_v)}$


        Taking imaginary terms of both sides:
        $\\implies {latex(im_lhs)}
        = {latex(im_rhs)}$

        $\\implies {latex(im_lhs_v)} = {latex(im_rhs_v)}$

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

        answer_s = f"""
        ${latex(re_lhs)}$
        $= {latex(re_rhs)}
        $

        ${latex(im_lhs)}$
        $= {latex(im_rhs)}
        $

        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate


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


        en_helper = self.base_helper.get_algebra_helper().get_euler_number_helper()


        problem_s = f"""
        Define Euler's number {latex(E)}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        {en_helper.get_detailed_content()}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        {en_helper.get_definition()}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate


