'''
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, Symbol, symbols, Eq, Matrix, latex, 
                   solve, Rational, diag, pi, nsimplify, Poly)

from sympy.abc import theta

#from xv.math.formulae import FormulaHelper, FormulaSet
from xv.math.formulae import FormulaHelper, FormulaSet


from xv.km.util import latex_fraction
        
from xv.util import toIntOrFloat, list_to_str

from sympy.core.expr import UnevaluatedExpr

from xv.km.util import latex_fraction

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

# _area_manager
# AreaManager
        
class AreaManager(BaseManager):
    '''
    AreaManager
    Example:
        ke = AreaManager()
        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ...
        
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()
        
        ke.printProblemTypes()
        
    '''    
    
    def __new__(cls, *args, **kwargs):
        instance = super(AreaManager, cls).__new__(cls, *args, **kwargs)
        for base_class in AreaManager.__bases__:
            base_class.__init__(instance, *args, **kwargs)
        return instance
    
    def __init__(self, *args, **kwargs):
        self.base_helper = BaseHelper(**kwargs)
        self.fh = FormulaHelper()
        pass

    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
            #'_problem_get_formulae_for_area',
            '_problem_area_rectangle',
            '_problem_area_square',
            '_problem_area_parallelogram',
            '_problem_area_triangle',
            '_problem_area_rhombus',
            '_problem_area_trapezoid',
            '_problem_area_sector_of_circle',
            '_problem_area_circle',
            '_problem_area_ellipse',
            '_problem_area_sphere',
            '_problem_area_cylinder',
            '_problem_area_cone',
            '_problem_area_prism',
            '_problem_area_cuboid',
            '_problem_area_cube',
            '_problem_area_misc_problems_type_1',
            '_problem_area_under_a_curve',
            '_problem_calculate_surface_area_of_rotation',
            ])
        pass

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

        category = 'Area'

        rfs = FormulaSet(count = 999, category = category, formula_helper = self.fh)
        category = rfs.category
        formulae_latex = rfs.get_latex_set(expr_type = 'latex_expr', 
                                           include_index = False,
                                           include_description = True,
                                           include_links = True)

        formulae_latex_str = "<ol><li>" + "<br/><br/></li><li>".join(formulae_latex) + "</li></ol>"
        
        problem_s = f"""
        Some important formulae in category: <b>{category}</b>

        <b>Note: </b>to get specific category:
        ke.getRandomProblem(problem_type = 0, category = '{category}')

        <b>Note: </b>to list all Categories:
        ke.fh.get_categories()
        
        """
        problemTemplate.add_problem(problem_s, "text/html")
        
        soln_s = f"""
            {formulae_latex_str}
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')


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


    def _problem_area_rectangle(self, *args, **kwargs):
        
        n1, n2  = random.sample(list(range(1, 10)), 2)
        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        area_rep = area_helper.get_reactangle_area_rep(n1, n2)
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Find area of a rectangle whose base is {n1} and height {n2}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        Area of rectangle = base * height $= {n1} * {n2} = {n1 * n2}$
        {area_rep}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        ${n1 * n2}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_area_square(self, *args, **kwargs):
        n1  = random.randint(1, 10)
        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        area_rep = area_helper.get_reactangle_area_rep(n1, n1)
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Find area of a square whose sides are {n1}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        The square is also a rectangle whose base and height are same.
        
        Area of square = base * height $= {n1} * {n1} = {n1 * n1}$
        {area_rep}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        ${n1 * n1}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    

    def _problem_area_parallelogram(self, *args, **kwargs):
        n1, n2  = random.sample(list(range(1, 10)), 2)
        theta = random.choice([pi/3, pi/4, pi/6])
        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        svg_str = area_helper.plot_parallelogram(n1, n2, theta)
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Find area of a parallelogram whose base is {n1} and height {n2}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        Area of parallelogram is same as the area of a rectangle with same base and height.
        
        Area of parallelogram = base * height $= {n1} * {n2} = {n1 * n2}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        answer_s = f"""
        ${n1 * n2}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_area_triangle(self, *args, **kwargs):
        n1, n2  = random.sample(list(range(1, 10)), 2)
        theta = random.choice([pi/3, pi/4, pi/6])
        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        svg_str = area_helper.plot_triangle(n1, n2, theta)
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Find area of a triangle whose base is {n1} and the corresponding height {n2}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        The area of a triangle is half of the parallelogram with same base and height. Therefore, 
        
        Area of triangle = ${latex_fraction(1, 2)}$ * base * height $= {latex_fraction(1, 2)} * {n1} * {n2} = {toIntOrFloat(n1 * n2 / 2)}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        
        answer_s = f"""
        ${toIntOrFloat(n1 * n2 / 2)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_area_rhombus(self, *args, **kwargs):
        n1, n2  = random.sample(list(range(1, 10)), 2)
        
        ar = nsimplify(Rational(1, 2) * n1 * n2)

        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        svg_str = area_helper.plot_rhombus(n1, n2)

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

        problem_s = f"""
        Find area of a rhombus whose diagonals are {n1} and {n2}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        The area of a rhombus is divided into four parts by its diagonals.
        The diagonals are perpendicular to each other. 
        Thus, each triangle has base equal to half of one diagonal 
        and height equal to another diagonal.
        """
        problemTemplate.add_solution (soln_s.strip(), 'text/html', 
                                      add_html_line_break = False)
        
        soln_s = f"""
        Therefore, Area of rhombus 
        
        = 4 * area of each triangle
        
        = $4 \\left({latex_fraction(1, 2)} * base * height \\right)$
        
        = $4 \\left({latex_fraction(1, 2)} * {latex_fraction(n1, 2)} * {latex_fraction(n2, 2)} \\right)$
        
        = ${latex_fraction(1, 2)} * {n1} * {n2} $
        
        = ${latex(ar)}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        
        answer_s = f"""
        ${latex(ar)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_area_trapezoid(self, *args, **kwargs):
        n1, n2, n3  = random.sample(list(range(1, 10)), 3)
        
        area_trapezoid = toIntOrFloat((1/2) * (n1 + n2) * n3)
        theta = random.choice([pi/3, pi/4, pi/6])
        
        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        svg_str = area_helper.plot_trapezoid(n1, n2, n3, theta)

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

        problem_s = f"""
        Find area of a trapezoid whose bases are {n1} and {n2} and height {n3}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        A trapezoid has parallel bases. If we divide it into two parts,
        we get two triangles with same height but different bases.
        """
        problemTemplate.add_solution (soln_s.strip(), 'text/html', 
                                      add_html_line_break = False)
        
        ns = min(n1, n2)
        nb = max(n1, n2)
        soln_s = f"""
        Therefore, Area of trapezoid 
        
        = Average of the bases * height  
        
        = ${latex_fraction(1, 2)} * ({n1} + {n2}) * {n3} $
        
        = ${area_trapezoid}$
        
        Method 2:

        = Area of a parallelogram with the smallest base + ((Difference of bases) * height)/2
        
        = ${ns}$ * ${n3}$ + ${latex_fraction(1, 2)} * ({nb} - {ns}) * {n3} $
        
        = ${ns}$ * ${n3}$ + ${latex_fraction(1, 2)} * ({nb - ns}) * {n3} $
        
        = ${ns*n3}$ + ${(nb - ns) * n3 * 0.5} $
                
        = ${area_trapezoid}$
        

        """
        
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        
        answer_s = f"""
        ${area_trapezoid}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

    def _problem_area_sector_of_circle(self, *args, **kwargs):
        n1  = random.randint(1, 10)
        n2  = random.randint(1, 10)
        r = symbols('r')
        angle = 2 * pi / n2

        
        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        center = (0, 0)
        svg_str = area_helper.plot_circle(n1, center, end_angle = angle, use_cache = False)
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Find area of the sector with radius is {n1} and angle ${latex(angle)}$.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        n3 = nsimplify( (1/2) * (2 / n2) * (n1 ** 2) )
        
        soln_s = f"""
        Area of sector 
        
        = ${latex_fraction(1, 2)} {latex(theta)} {r}^2 $
        
        = ${latex_fraction(1, 2)} * {latex(angle)} * {n1}^2  = {latex(pi * n3)}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        answer_s = f"""
        ${latex(pi * n3)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_area_circle(self, *args, **kwargs):
        n1  = random.randint(1, 10)
        r = symbols('r')

        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        center = (0, 0)
        svg_str = area_helper.plot_circle(n1, center, end_angle = 2 * pi)
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Find area of the circle whose radius is {n1}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        Circle is the sector with angle ${latex(2 * pi)}$.
        
        Therefore, area of circle 
        
        = ${latex_fraction(1, 2)} * {latex(2 * pi)} * {r}^2 $
        
        = ${latex(pi)} {r}^2 $
        
        = ${latex(pi)} * {n1}^2  $
        
        = ${latex(pi * n1 ** 2)} $
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        answer_s = f"""
        ${latex(pi * n1 ** 2)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_area_ellipse(self, *args, **kwargs):
        
        use_cache = kwargs.get('use_cache', False)
        
        n1, n2  = random.sample(list(range(1, 10)), 2)
        r1, r2 = symbols('r_1 r_2')
        
        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        center = (0, 0)
        svg_str = area_helper.plot_ellipse(n1, n2, center, end_angle = 2 * pi,
                                           use_cache = use_cache)
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Find area of the ellipse whose radii are {n1} and {n2}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        Area of ellipse = ${latex(pi)} {r1} {r2} = {latex(pi)} * {n1} * {n2}  = {latex(pi * n1 * n2)}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        answer_s = f"""
        ${latex(pi * n1 * n2)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

    def _problem_area_sphere(self, *args, **kwargs):
        n1  = random.randint(1, 10)
        r = symbols('r')
 
        n2 = 4 * n1 ** 2

        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        center = (0, 0, 0)
        svg_str = area_helper.plot_sphere(n1, center)
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Find surface area of the the sphere whose radius is {n1}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        Area of sphere 
        
        = $4 {latex(pi)} {r}^2 $
        
        = $4 {latex(pi)} * {n1}^2 $
        
        = ${latex(pi * n2)}$
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        answer_s = f"""
        ${latex(pi * n2)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_area_cylinder(self, *args, **kwargs):
        n1, n2  = random.sample(list(range(1, 10)), 2)
 
        r = symbols('r')
        h = symbols('h')
        circumference = 2 * pi * r
        n3 = 2 * n1 * ( n1 + n2)

        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        center = (0, 0, 0)
        svg_str = area_helper.plot_cylinder(n1, n2, center)
        
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Find surface area of the the cylinder whose base has radius {n1} and height {n2}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        A cylinder has two identical circular bases and vertical surface area.
        The vertical surface area is actually a rectangle with width equal to 
        circumference of the circular base, ${latex(circumference)}$ 
        and its height equal to height of the cylinder.
        <br />
        <br />
        Therefore, area of cylinder
        <br />
        <br />
        = 2 * area of each base + vertical surface area
        """
        problemTemplate.add_solution (soln_s.strip(), 'text/html', 
                                      add_html_line_break = False)
        
        soln_s = f"""
        = $2 * {latex(pi)} r^2 + {latex(circumference)} * {h}$
        
        = ${latex(circumference)} ({r} + {h}) $
        
        = $2 * {latex(pi)} * {n1} * ({n1} + {n2}) $
        
        = $2 * {latex(pi)} * {n1} * {n1 + n2} $
        
        = ${latex(pi * n3)}$
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        answer_s = f"""
        ${latex(pi * n3)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_area_cone(self, *args, **kwargs):
        n1, n2  = random.sample(list(range(1, 10)), 2)
        half = Rational(1, 2)
        slant_length_value = (n1 ** 2 + n2 ** 2) ** half
 
        r = symbols('r')
        h = symbols('h')
        slant_length = symbols('l')
        n3 = n1 * ( n1 + slant_length_value)
        slant_length_formula = (r ** 2 + h ** 2) ** half
        slant_length_formula_latex = f"""\\left( {n1}^2 + {n2}^2 \\right)"""
        slant_length_formula_latex = f"\\sqrt{{{slant_length_formula_latex}}}"


        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        center = (0, 0, 0)
        svg_str = area_helper.plot_cone(n1, n2, center)
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Find surface area of the the cone whose base has radius {n1} and height {n2}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        A cone has one circular base and slant surface area
        <br />
        = area of circular base + slant surface area
        """
        problemTemplate.add_solution (soln_s.strip(), 'text/html', 
                                      add_html_line_break = False)
        
        soln_s = f"""
        = ${latex(pi)} r^2 + {latex(pi)} {r} {slant_length}$ 
        \t\t where {latex(slant_length)} is slant length and is equal to $
        {latex(slant_length_formula)} 
        = {slant_length_formula_latex}
        = {latex(slant_length_value)}
        $
        
        = ${latex(pi)} {r} ({r} + {slant_length}) $
        
        = ${latex(pi)} * {n1} \\left({n1} + {latex(slant_length_value)}\\right) $
        
        = ${latex(pi)} * {n1} \\left({latex(n1 + slant_length_value)}\\right) $
        
        = ${latex(pi * n3)}$
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        answer_s = f"""
        ${latex(pi * n3)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_area_prism(self, *args, **kwargs):
        from sympy import sin
        n1, n2  = random.sample(list(range(1, 10)), 2)
        half = Rational(1, 2)
 
        l = symbols('l')
        h = symbols('h')
        a_length_formula = n1 * sin(pi/6)
        a_length_formula_n = float(a_length_formula.n(2))
        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        center = (0, 0, 0)
        svg_str = area_helper.plot_prism(n1, n2, center, use_cache = False)
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Find surface area of the the prism whose length is {n1} and height is {n2}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        A prism has 2 triangular base and 3 surface area
        <br />
        = area of triangular bases + 3 * surface area
        """
        problemTemplate.add_solution (soln_s.strip(), 'text/html', 
                                      add_html_line_break = False)
        
        soln_s = f"""
        = ${latex(half)} h * a + 3 * l * h$ 
        \t\t where a is length of height of the triangle and is equal to $
        {latex(a_length_formula)} 
        = {a_length_formula_n}
        $
        
        = ${latex(half)} {n2} * {a_length_formula_n} + 3 * {n1} * {n2}$ 
        
        = ${latex(half)} {n2 * a_length_formula_n} + 3 * {n1 * n2}$ 
        
        = ${(n2 * a_length_formula_n)/2 } + {3 * n1 * n2}$ 
        
        = ${(n2 * a_length_formula_n)/2 + 3 * n1 * n2}$ 
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        answer_s = f"""
        = ${(n2 * a_length_formula_n)/2 + 3 * n1 * n2}$ 
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_area_cuboid(self, *args, **kwargs):
        n1, n2, n3  = random.sample(list(range(1, 10)), 3)
 
        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        center = (0, 0, 0)
        svg_str = area_helper.plot_cubiod(n1, n2, n3, center)
        
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Find surface area of the the cubiod whose length is {n1}, width is {n2}, height is {n3}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        
        soln_s = f"""
        = $2 * (length * width + width * height + height * length)$

        = $2 * ({n1} * {n2} + {n2} * {n3} + {n3} * {n1})$
                
        = $2 * ({n1* n2} + {n2 * n3} + {n3 * n1})$
        
        = $2 * ({n1* n2 + n2 * n3 + n3 * n1})$
        
        = ${2 * (n1* n2 + n2 * n3 + n3 * n1)}$

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        answer_s = f"""
        = ${2 * (n1* n2 + n2 * n3 + n3 * n1)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_area_cube(self, *args, **kwargs):
        n1  = random.sample(list(range(1, 10)), 1)[0]
 
        area_helper = self.base_helper.get_geometry_helper().get_area_helper()
        center = (0, 0, 0)
        svg_str = area_helper.plot_cubiod(n1, n1, n1, center)
        
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Find surface area of the the cube whose length is {n1}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        
        soln_s = f"""
        The Cube has 6 sides and all the sides will have same area.
        = $6 * (length * length)$

        = $6 * ({n1} * {n1})$
        
        = $6 * ({n1 * n1})$
                
        = ${6 * n1 * n1}$
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        answer_s = f"""
        = ${6 * n1 * n1}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    
    def _problem_area_misc_problems_type_1(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        from xv.util import CategorizedSampleData
        names = CategorizedSampleData.get_human_names()
        name = random.choice(names)

        x, r, l, w, a, a1, a2 = symbols('x, r, l, w, a, a_1, a_2')

        l_rat = Symbol(r'l_r')
        w_rat = Symbol(r'w_r')
        
        delta_l1 = Symbol(r'\Delta l_1')
        delta_w1 = Symbol(r'\Delta w_1')
        
        delta_l2 = Symbol(r'\Delta l_2')
        delta_w2 = Symbol(r'\Delta w_2')
        
        r_val = random.randint(2, 6)
        l_rat_val = random.randint(2, 10) 
        w_rat_val = random.randint(2, 10)
        
        l_val = l_rat_val * r_val
        w_val = w_rat_val * r_val
        
        delta_l1_val = random.randint(1, l_val - 1) * random.choice([1, -1])
        delta_w1_val = random.randint(1, w_val - 1) * random.choice([1, -1])

        delta_l2_val = random.randint(1, l_val - 1) * random.choice([1, -1])
        delta_w2_val = random.randint(1, w_val - 1) * random.choice([1, -1])

        exprs = {
            l: l_rat_val * r,
            w: w_rat_val * r,
            }


        a_latex = UnevaluatedExpr(l) * UnevaluatedExpr(w)
        a1_latex = (UnevaluatedExpr(exprs[l]) + UnevaluatedExpr(delta_l1_val)) * (UnevaluatedExpr(exprs[w]) + UnevaluatedExpr(delta_w1_val))
        a2_latex = (UnevaluatedExpr(exprs[l]) + UnevaluatedExpr(delta_l2_val)) * (UnevaluatedExpr(exprs[w]) + UnevaluatedExpr(delta_w2_val))


        vals = {
            r: r_val,
            l_rat: l_rat_val,
            w_rat: w_rat_val,
            a: l_val * w_val,
            a1: (l_val + delta_l1_val) * (w_val + delta_w1_val),
            a2: (l_val + delta_l2_val) * (w_val + delta_w2_val),
            delta_l1: delta_l1_val,
            delta_w1: delta_w1_val,
            delta_l2: delta_l2_val,
            delta_w2: delta_w2_val,
            }

        ltxs = {
            'a_latex': latex(a_latex),
            'a1_latex': latex(a1_latex),
            'a2_latex': latex(a2_latex),
            }

        eq1 = Eq(simplify(a1_latex).expand(), vals[a1])
        r_solns = solve(eq1, r)
        r_solns_str = list_to_str([f"{latex(r_soln)}" for r_soln in r_solns])
        r_solns_pos = [r_soln for r_soln in r_solns if r_soln > 0]
        r_solns_pos_str = list_to_str([f"{latex(r_soln)}" for r_soln in r_solns_pos])


        a1_latex_val = simplify(a1_latex.subs({r: r_val}))
        a2_latex_val = simplify(a2_latex.subs({r: r_val}))
        if a1_latex_val != vals[a1]:
            print(f"Error: a1_latex_val = {a1_latex_val} and vals[a1] = {vals[a1]}")

        if a2_latex_val != vals[a2]:
            print(f"Error: a2_latex_val = {a2_latex_val} and vals[a2] = {vals[a2]}")


        problem_s = f"""
        {name} has a ${vals[l_rat]} \\times {vals[w_rat]}$ shape field. 
        If the length of sides of this field are changed by 
        ${vals[delta_l1]}$ and ${vals[delta_w1]}$ units, 
        the field would have area ${vals[a1]}$ square units. 
        What would the area of the field be in square units 
        if instead the length of sides are changed by 
        ${vals[delta_l2]}$ and ${vals[delta_w2]}$ units? 
        """.replace("\n", "")
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        Let:
        $\\displaystyle l = {latex(exprs[l])}$
        $\\displaystyle w = {latex(exprs[w])}$
        
        Area when length of sides of this field are changed by ${vals[delta_l1]}$ and ${vals[delta_w1]}$ units:
        
        $\\displaystyle 
        {ltxs['a1_latex']} = {latex(vals[a1])} 
        $
        
        $\\displaystyle \\implies
        {latex(eq1)} 
        $
        
        $\\displaystyle \\implies
        {latex(r)} = {r_solns_str} 
        $
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        if len(r_solns_pos) != len(r_solns):
            soln_s = f"""
            $\\displaystyle \\implies
            {latex(r)} = {r_solns_pos_str} \\qquad \\text{{ ignoring zero and negative values}}
            $
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
            pass
        
        soln_s = f"""
        <br />
        Now, let us substitute the value $\\displaystyle 
        {latex(r)} = {r_solns_pos_str} $ to compute area.
        
        Area when length of sides of this field are changed by ${vals[delta_l2]}$ and ${vals[delta_w2]}$ units:
        
        $\\displaystyle 
        {latex(a2)} = {ltxs['a2_latex']} 
        $
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        a_computed_list = []
        for r_soln_idx, r_soln in enumerate(r_solns_pos):
            a_computed = simplify(a2_latex.subs({r: r_soln}))
            a_computed_list.append(a_computed)
            if r_soln_idx == 0:
                soln_s = f"""
                $\\displaystyle 
                = {latex(a_computed)} 
                \\qquad \\text{{for {latex(r)} = {r_soln} }}
                $ 
                """
            else:
                soln_s = f"""
                $\\displaystyle 
                \\text{{and}} \\quad {latex(a_computed)} 
                \\qquad \\text{{for {latex(r)} = {r_soln} }}
                $ 
                """
                
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
            pass
        
        a_computed_list_pos = [f"{latex(a_computed)}" for a_computed in a_computed_list 
                               if a_computed > 0]
        
        if len(a_computed_list_pos) != len(a_computed_list):
            soln_s = f"""
            $\\displaystyle \\implies
            {latex(a2)} = {list_to_str(a_computed_list_pos)} \\qquad \\text{{ ignoring zero and negative values}}
            $
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')
            pass
        
        answer_s = f"""
        $\\displaystyle 
        {list_to_str(a_computed_list_pos)} 
        $
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    
    def _problem_area_under_a_curve(self, *args, **kwargs):
        """

        doc_style: xv_doc
        """
        index = kwargs.get("index", None)
        
        auc_helper = self.base_helper.get_calculus_helper().get_area_under_curve_helper()
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        expr, x, x_limits = auc_helper.get_random_area_curve_data_set(index = index)
        
        result = auc_helper.get_area_under_a_curve(expr, x, x_limits)
        
        
        prob_s = f"""
        {result['problem_s']}
        
        """
        
        problemTemplate.add_problem(prob_s.strip(), 'text/html')


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


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

        doc_style: xv_doc
        """
        index = kwargs.get("index", None)
        
        sar_helper = self.base_helper.get_calculus_helper().get_surface_area_of_rotation_helper()
        result = sar_helper.get_random_surface_area_of_rotation(index = index)
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        
        
        prob_s = f"""
        {result['problem_s']}
        
        """
        
        problemTemplate.add_problem(prob_s.strip(), 'text/html')


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

