'''
Created on 01-Apr-2021
@author: bthakur
'''

import random
import inspect
import traceback

from sympy import (symbols, Symbol, latex,
                   Rational,
                   )
from sympy.core.expr import UnevaluatedExpr
import numpy as np
import sympy as sp


from xv.km.util import latex_fraction
from xv.util import toIntOrFloat
from xv.km.ui import SvgHelper 


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

# _volume_area_manager
# VolumeAreaManager


class VolumeAreaManager(BaseManager):
    '''
    VolumeAreaManager
    Example:
        ke = VolumeAreaManager()
        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ...
        
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()
        
        ke.printProblemTypes()
        
    '''    
    
    def __new__(cls, *args, **kwargs):
        instance = super(VolumeAreaManager, cls).__new__(cls, *args, **kwargs)
        for base_class in VolumeAreaManager.__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_derive_volume_of_sphere',
            '_problem_derive_surface_area_of_sphere',
            '_problem_derive_volume_of_cone',
            '_problem_derive_surface_area_of_cone',
            '_problem_derive_volume_of_cylinder',
            '_problem_derive_surface_area_of_cylinder',
            '_problem_derive_volume_of_tetrahedra',
            '_problem_derive_volume_of_rect_pyramid',
            '_problem_relation_volumes_cylinder_cone_sphere',
            '_problem_calc_volume_of_mixed_objects',
            ])
        pass

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

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

        problem_s = f"""
        Derive the volume of a sphere.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        $\\displaystyle dV = A \\cdot ds $
        
        $\\displaystyle \\implies dV = \\pi y^{{2}} \\cdot dx$
        
        $\\displaystyle \\implies \\int_{{0}}^{{V}} dV = \\int_{{-r}}^{{r}}\\pi y^{{2}} \\cdot dx$
        
        $\\displaystyle \\implies \\int_{{0}}^{{V}} dV = \\int_{{-r}}^{{r}}\\pi (r^{{2}} - x^{{2}}) \\cdot dx$
        
        $\\displaystyle \\implies V = \\int_{{-r}}^{{r}} \\pi r^{{2}} \\cdot dx - \\int_{{-r}}^{{r}} \\pi x^{{2}}\\cdot dx$
        
        $\\displaystyle \\implies V = \\pi r^{{2}} \\int_{{-r}}^{{r}} dx - \\pi \\int_{{-r}}^{{r}} x^{{2}} \\cdot dx$
        
        $\\displaystyle \\implies V = \\pi \\left [ r^{{2}} \\int_{{-r}}^{{r}} dx - \\int_{{-r}}^{{r}} x^{{2}} \\cdot dx \\right ]$
        
        $\\displaystyle \\implies V = \\pi \\left [ r^{{2}} \\left . x \\right |_{{-r}}^{{r}} - \\left . \\frac{{x^{{3}}}}{{3}} \\right |_{{-r}}^{{r}} \\right ]$
        
        $\\displaystyle \\implies V = \\pi \\left [ r^{{2}} \\left ( r + r \\right ) - \\left( \\frac{{r^{{3}}}}{{3}} - \\frac{{\\left ( -r \\right )^{{3}}}}{{3}} \\right ) \\right ]$
        
        $\\displaystyle \\implies V = \\pi \\left [ 2 r^{{3}} - \\frac{{2 r^{{3}}}}{{3}} \\right ]$
        
        $\\displaystyle \\implies V = \\frac{{4}}{{3}} \\pi r^{{3}}$


        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        
    def _problem_derive_surface_area_of_sphere(self, *args, **kwargs):

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

        problem_s = f"""
        Derive the surface area of a sphere.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        $\\displaystyle dA = L \\cdot ds $
        
        $\\displaystyle \\implies dA = 2 \\pi r \\cos \\theta \\cdot r d\\theta$
        
        $\\displaystyle \\implies \\int_{{0}}^{{A}} dA = \\int_{{-\\frac{{\\pi}}{{2}}}}^{{\\frac{{\\pi}}{{2}}}} 2 \\pi r^{{2}} \\cos \\theta d\\theta$
        
        $\\displaystyle \\implies \\int_{{0}}^{{A}} dA = 2 \\pi r^{{2}} \\int_{{-\\frac{{\\pi}}{{2}}}}^{{\\frac{{\\pi}}{{2}}}} \\cos \\theta d\\theta$
        
        $\\displaystyle \\implies A = 2 \\pi r^{{2}} \\left. \\sin \\theta \\right |_{{-\\frac{{\\pi}}{{2}}}}^{{\\frac{{\\pi}}{{2}}}}$
        
        $\\displaystyle \\implies A = 2 \\pi r^{{2}} \\left( \\sin \\left (\\frac{{\\pi}}{{2}} \\right ) - \\sin \\left (-\\frac{{\\pi}}{{2}} \\right ) \\right )$
        
        $\\displaystyle \\implies A = 2 \\pi r^{{2}} \\left( 1 - \\left (- 1 \\right ) \\right )$
        
        $\\displaystyle \\implies A = 4 \\pi r^{{2}}$


        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        
    def _problem_derive_volume_of_cone(self, *args, **kwargs):

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

        problem_s = f"""
        Derive the volume of a cone.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        $\\displaystyle dV = A \\cdot ds $
        
        $\\displaystyle \\implies dV = \\pi x^{{2}} \\cdot dy$
        
        $\\displaystyle \\implies dV = \\pi \\left(\\frac{{r}}{{h}} y \\right )^{{2}} \\cdot dy$
        
        $\\displaystyle \\implies \\int_{{0}}^{{V}} dV = \\int_{{0}}^{{h}} \\pi \\left(\\frac{{r}}{{h}} y \\right )^{{2}} \\cdot dy$
        
        $\\displaystyle \\implies \\int_{{0}}^{{V}} dV = \\pi \\left(\\frac{{r}}{{h}} \\right )^{{2}} \\int_{{0}}^{{h}} y^{{2}} \\cdot dy$
        
        $\\displaystyle \\implies \\int_{{0}}^{{V}} dV = \\pi \\left(\\frac{{r}}{{h}} \\right )^{{2}} \\left . \\frac{{y^{{3}}}}{{3}} \\right |_{{0}}^{{h}}$
        
        $\\displaystyle \\implies \\int_{{0}}^{{V}} dV = \\pi \\left(\\frac{{r}}{{h}} \\right )^{{2}} \\left( \\frac{{h^{{3}}}}{{3}} - 0 \\right )$
        
        $\\displaystyle \\implies V = \\frac{{1}}{{3}} \\pi r^{{2}}h$


        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        
    def _problem_derive_surface_area_of_cone(self, *args, **kwargs):

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

        problem_s = f"""
        Derive the surface area of a cone.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        $\\displaystyle dA = L \\cdot ds $
        
        $\\displaystyle \\implies dA = 2 \\pi x \\cdot dl$
        
        $\\displaystyle \\implies dA = 2 \\pi x \\cdot \\left( \\frac{{l}}{{r}} dx \\right )$
        
        $\\displaystyle \\implies dA = 2 \\pi \\frac{{l}}{{r}} x \\cdot dx$
        
        $\\displaystyle \\implies \\int_{{0}}^{{A}} dA = \\int_{{0}}^{{r}} 2 \\pi \\frac{{l}}{{r}} x \\cdot dx$
        
        $\\displaystyle \\implies A = 2 \\pi \\frac{{l}}{{r}} \\int_{{0}}^{{r}} x \\cdot dx$
        
        $\\displaystyle \\implies A = 2 \\pi \\frac{{l}}{{r}} \\left. \\frac{{x^{{2}}}}{{2}} \\right |_{{0}}^{{r}}$
        
        $\\displaystyle \\implies A = 2 \\pi \\frac{{l}}{{r}} \\left. \\frac{{x^{{2}}}}{{2}} \\right |_{{0}}^{{r}}$
        
        $\\displaystyle \\implies A = 2 \\pi \\frac{{l}}{{r}} \\left(\\frac{{r^{{2}}}}{{2}}  -  0\\right )$
        
        $\\displaystyle \\implies A = \\pi r l \\quad \\text{{or}} \\quad A = \\pi r \\sqrt{{h^{{2}} + r^{{2}}}}$

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        
    def _problem_derive_volume_of_cylinder(self, *args, **kwargs):

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

        problem_s = f"""
        Derive the volume of a cylinder.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        $\\displaystyle dV = A \\cdot ds $
        
        $\\displaystyle \\implies dV = \\pi r^{{2}} \\cdot dy$
        
        $\\displaystyle \\implies \\int_{{0}}^{{V}} dV = \\int_{{0}}^{{h}} \\pi r^{{2}} \\cdot dy$
        
        $\\displaystyle \\implies \\int_{{0}}^{{V}} dV = \\pi r^{{2}} \\int_{{0}}^{{h}} dy$
        
        $\\displaystyle \\implies \\int_{{0}}^{{V}} dV = \\pi r^{{2}} \\left . y \\right |_{{0}}^{{h}}$
        
        $\\displaystyle \\implies \\int_{{0}}^{{V}} dV = \\pi r^{{2}} \\left( h - 0 \\right )$
        
        $\\displaystyle \\implies V = \\pi r^{{2}}h$


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

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

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

        problem_s = f"""
        Derive the surface area of a cylinder.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = f"""
        $\\displaystyle dA = L \\cdot ds $
        
        $\\displaystyle \\implies dA = 2 \\pi r \\cdot dy$
        
        $\\displaystyle \\implies \\int_{{0}}^{{A}} dA = \\int_{{0}}^{{h}} 2 \\pi r \\cdot dx$
        
        $\\displaystyle \\implies A = 2 \\pi r \\int_{{0}}^{{h}} dx$
        
        $\\displaystyle \\implies A = 2 \\pi r \\left. y \\right |_{{0}}^{{h}}$
        
        $\\displaystyle \\implies A = 2 \\pi r \\left ( h - 0 \\right )$
        
        $\\displaystyle \\implies A = 2 \\pi r h$

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        
    def _problem_derive_volume_of_tetrahedra(self, *args, **kwargs):

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

        problem_s = f"""
        Derive the volume of a tetrahedra.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        image_s = "see image::/images/math/volume_area_manager_volume_of_tetrahedra.png"
        image_s = k_transformer.get_img_str(image_s.strip(), verbose = True)
        
        ref_url = "https://users.math.msu.edu/users/gnagy/teaching/12-spring/mth133/l01-133.pdf"
        
        soln_stmts = []
        
        soln_stmt = f"""
        {image_s}

        $\\displaystyle 
        \\begin {{aligned}}
        
        x(y)
        & =-\\frac{{a}}{{b}} y+a
        \\\\ \\\\
        
        z(y)
        & =-\\frac{{c}}{{b}} y+c 
        
        \\end {{aligned}}
        $
        
        """
        soln_stmts.append(soln_stmt.strip())
        
                
        soln_stmt = f"""
        $\\displaystyle 
        \\begin {{aligned}}
        
        A(y)
        & =\\frac{{1}}{{2}} \\cdot x(y) \\cdot z(y)
        \\\\ \\\\
        
        & =\\frac{{1}}{{2}}\\left(-\\frac{{a}}{{b}}\\right)(y-b)\\left(-\\frac{{c}}{{b}}\\right)(y-b)
        \\\\ \\\\
        
        & =\\frac{{a c}}{{2 b^2}}(y-b)^2  
        \\\\ \\\\
        
        \\end {{aligned}}
        $
        
        """
        soln_stmts.append(soln_stmt.strip())
        
        soln_stmt = f"""
        $\\displaystyle 
        \\begin {{aligned}}
        
        dV
        & = A(y) dy
        \\\\ \\\\
        
        & = \\left( \\frac{{a c}}{{2 b^2}}(y-b)^2 \\right) dy

        \\end {{aligned}}
        $
        
        """
        soln_stmts.append(soln_stmt.strip())
        
                
        soln_stmt = f"""
        $\\displaystyle 
        \\begin {{aligned}}
        
        \\implies V
        & =\\frac{{a c}}{{2 b^2}} \\int_0^b(y-b)^2 d y
        \\\\ \\\\
        
        &  =\\frac{{a c}}{{2 b^2}}\\left[\\left.\\frac{{(y-b)^3}}{{3}}\\right|_0 ^b\\right] 
        \\\\ \\\\
        
        & =\\frac{{1}}{{6}} a b c 
        
        
        \\end {{aligned}}
        $
        
        """
        soln_stmts.append(soln_stmt.strip())
        
        soln_stmt = f"""
        Ref: <a target="_blank" href="{ref_url}">Source: math.msu.edu</a>
        """
        soln_stmts.append(soln_stmt.strip())

        soln_s = "\n\n".join(soln_stmts)
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        $\\displaystyle \\frac{{1}}{{6}} a b c$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate



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

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

        problem_s = f"""
        Derive the volume of a rectangular pyramid.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        image_s = "see image::/images/math/volume_area_manager_volume_of_rect_pyramid.png"
        image_s = k_transformer.get_img_str(image_s.strip(), verbose = True)
        
        ref_url = "https://users.math.msu.edu/users/gnagy/teaching/12-spring/mth133/l01-133.pdf"
        
        soln_stmts = []
        
        soln_stmt = f"""
        {image_s}

        $\\displaystyle 
        \\begin {{aligned}}
        
        x(y)
        & =-\\frac{{a}}{{b}} y+a
        \\\\ \\\\
        
        z(y)
        & =-\\frac{{c}}{{b}} y+c 
        
        \\end {{aligned}}
        $
        
        """
        soln_stmts.append(soln_stmt.strip())
        
                
        soln_stmt = f"""
        $\\displaystyle 
        \\begin {{aligned}}
        
        A(y)
        & =\\cdot x(y) \\cdot z(y)
        \\\\ \\\\
        
        & =\\left(-\\frac{{a}}{{b}}\\right)(y-b)\\left(-\\frac{{c}}{{b}}\\right)(y-b)
        \\\\ \\\\
        
        & =\\frac{{a c}}{{b^2}}(y-b)^2  
        \\\\ \\\\
        
        \\end {{aligned}}
        $
        
        """
        soln_stmts.append(soln_stmt.strip())
        
        soln_stmt = f"""
        $\\displaystyle 
        \\begin {{aligned}}
        
        dV
        & = A(y) dy
        \\\\ \\\\
        
        & = \\left( \\frac{{a c}}{{b^2}}(y-b)^2 \\right) dy

        \\end {{aligned}}
        $
        
        """
        soln_stmts.append(soln_stmt.strip())
        
                
        soln_stmt = f"""
        $\\displaystyle 
        \\begin {{aligned}}
        
        \\implies V
        & =\\frac{{a c}}{{b^2}} \\int_0^b(y-b)^2 d y
        \\\\ \\\\
        
        &  =\\frac{{a c}}{{b^2}}\\left[\\left.\\frac{{(y-b)^3}}{{3}}\\right|_0 ^b\\right] 
        \\\\ \\\\
        
        & =\\frac{{1}}{{3}} a b c 
        
        
        \\end {{aligned}}
        $
        
        """
        soln_stmts.append(soln_stmt.strip())
        
        soln_stmt = f"""
        Ref: <a target="_blank" href="{ref_url}">Source: math.msu.edu</a>
        """
        soln_stmts.append(soln_stmt.strip())

        soln_s = "\n\n".join(soln_stmts)
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        $\\displaystyle \\frac{{1}}{{3}} a b c$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate



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

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

        problem_s = f"""
        Write relation among volumes of a cylinder, a cone and a sphere.
        
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        
        soln_stmts = []
        
        soln_stmt = f"""
        $\\displaystyle 
        \\begin {{aligned}}
        
        & \\text {{Cylinder }} + \\text {{ Cone }} = \\text {{ Sphere }} 
        \\\\ \\\\
        
        \\equiv \\;
        & \\text {{Cylinder }} 
        + \\frac {{ 1 }} {{ 3 }} \\text {{ Cylinder }} 
        = \\frac {{ 4 }} {{ 3 }} \\text {{ Cylinder }} 
        \\\\ \\\\
        
        \\equiv \\;
        & \\pi r^2 h 
        + \\frac{{1}}{{3}} \\pi r^2 h 
        = \\frac{{4}}{{3}} \\pi r^2 h
        \\\\ \\\\
        
        \\equiv \\;
        & \\pi r^2 h 
        + \\frac{{1}}{{3}} \\pi r^2 h 
        = \\frac{{4}}{{3}} \\pi r^3
        \\qquad \\text {{ r = h in case of sphere }}
        
        \\end {{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())


        soln_s = "\n\n".join(soln_stmts)
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = f"""
        $\\displaystyle \\text {{Cylinder }} + \\text {{ Cone }} = \\text {{ Sphere }} $
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate



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

        volume_helper = self.base_helper.get_geometry_helper().get_volume_helper()

        result = volume_helper.get_problem_calc_volume_of_mixed_objects(**kwargs)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
    
        prob_s = f"""
        {result['prob_s']}
        """
        problemTemplate.add_problem(prob_s.strip(), 'text/html')
        
        soln_s = f"""
        {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


