'''
Created on 16-Apr-2021

@author: rishi_priyansh
'''
from sympy import symbols, Eq, solve, Symbol, latex, sqrt, UnevaluatedExpr
from xv.km.ui import SvgHelper  
import matplotlib.pyplot as plt

import random
import inspect
import traceback

from ..helper import BaseHelper

from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate
        
class RelativityManager(BaseManager):
    '''
    RelativityManager
    Example:
        ke = RelativityManager()
        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(RelativityManager, cls).__new__(cls, *args, **kwargs)
        for base_class in RelativityManager.__bases__:
            base_class.__init__(instance, *args, **kwargs)
        return instance
    
    def __init__(self, *args, **kwargs):
        self.base_helper = BaseHelper(**kwargs)
        self.trh = self.base_helper.get_theory_of_relativity_helper()

        self.setContent()
        self.implies = symbols(u'\U000021D2')
        self.right_arrow = symbols(u'\U00002192')
        self.t_0 = Symbol('t_0', constant = True)
        self.t = Symbol('t')
        self.d, self.L, self.c, self.gamma = symbols('d, L, c, gamma', constant = True)
        self.u = symbols('u')
        
        
        self._relativistic_system = None
        pass


    def get_relativistic_system(self, *args, **kwargs):
        if self._relativistic_system is None:
            from xv.km.mathsys import MathSystemFactory, RelativisticSystem
            math_sys = MathSystemFactory.GET_INSTANCE(RelativisticSystem, 
                                                      use_cache = True,
                                                      verbose = self.verbose)
            self._relativistic_system = math_sys
            pass

        return self._relativistic_system
        pass



    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
            '_problem_find_time_using_c_in_static_clock',
            '_problem_find_time_using_c_in_moving_clock',
            '_problem_derive_time_dilation',
            '_problem_plot_speed_and_time',
            '_problem_plot_speed_and_gamma',
            '_problem_plot_gamma_and_time',
            '_problem_plot_speed_and_length',
            '_problem_plot_gamma_and_length',
            '_problem_relativistic_system',
            
            '_problem_comprehension_space_time',
            
            ])
        pass




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

        eq = Eq(self.t_0, 2*self.d/self.c)


        problem_s = fr"""
        Find the time passed in if the the distance between the static mirrors
        is d and light is reflecting up and down.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        fig = self.trh.plot_static_mirror()
        svgHelper = SvgHelper()
        svg_str = svgHelper.plt_to_svg()
        plt.close() 
        
        soln_s = fr"""
        The distance travelled by light in a cycle = ${latex(2*self.d)}$
        The speed of light = ${latex(self.c)}$ = $3 \cdot 10^8 m s^{{-1}}$

        The total time in a cycle 
        ${latex(eq)}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        
        answer_s = fr"""
        ${latex(eq)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        # problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate
    
    def _problem_find_time_using_c_in_moving_clock(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        eq = Eq(self.t, 2*self.L/self.c)

        problem_s = fr"""
        Find the time passed in if the mirrors are moving with a velocity $u$, 
        the distance between the mirrors is d and light is reflecting up and down.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        fig = self.trh.plot_moving_mirror()
        svgHelper = SvgHelper()
        svg_str = svgHelper.plt_to_svg()
        plt.close() 
        
        soln_s = fr"""
        The distance travelled by light in a cycle = ${latex(2*self.L)}$
        The speed of light = ${latex(self.c)}$ = $3 \cdot 10^8 m s^{{-1}}$

        The total time in a cycle 
        ${latex(eq)}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        
        answer_s = fr"""
        ${latex(eq)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

    def _problem_derive_time_dilation(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        eq1 = Eq(self.t_0, 2*self.d/self.c)
        eq2 = Eq(self.t, 2*self.L/self.c)
        eq3 = Eq(self.L, sqrt(self.d**2 + UnevaluatedExpr(self.u*self.t/2)**2))
        eq4 = Eq(self.d, self.t_0*UnevaluatedExpr(self.c/2))
        eq5 = Eq(self.L, sqrt((self.t_0*self.c/2)**2 + (self.u*self.t/2)**2))
        eq6 = Eq(self.t, UnevaluatedExpr(2/self.c) * sqrt((self.t_0*self.c/2)**2 + (self.u*self.t/2)**2))
        eq7 = Eq(self.t**2, UnevaluatedExpr(2/self.c)**2 * ((self.t_0*self.c/2)**2 + (self.u*self.t/2)**2))
        eq8 = eq7.simplify()
        eq9 = Eq(self.t**2 - (self.t*self.u/self.c)**2, self.t_0**2)
        eq10 = Eq(self.t**2 * (1 - (self.u/self.c)**2), self.t_0**2)
        eq11 = Eq(self.t**2, self.t_0**2 / (1 - (self.u/self.c)**2))
        eq12 = Eq(self.t, self.t_0 / sqrt(1 - (self.u/self.c)**2))
        eq13 = Eq(self.gamma, 1 / sqrt(1 - (self.u/self.c)**2))
        eq14 = Eq(self.t, self.gamma*self.t_0)


        problem_s = fr"""
        Derive the time dilation while moving with a velocity $u$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = fr"""
        From the previous problems, the time taken to light to travel a cycle in a static and moving mirrors,
        ${latex(eq1)}$ (static mirrors)$\quad\quad$... (1)
        ${latex(eq2)}$ (moving mirrors)$\quad\quad$... (2)
        
        The distance L in moving mirrors,
        ${latex(eq3)}$
        $\Rightarrow {latex(eq4)}$$\quad\quad$... (3)
        
        From (1) substitute t using (3),
        ${latex(eq5)}$
        $\Rightarrow {latex(eq6)}$
        $\Rightarrow {latex(eq7)}$
        $\Rightarrow {latex(eq8)}$
        $\Rightarrow {latex(eq9)}$
        $\Rightarrow {latex(eq10)}$
        $\Rightarrow {latex(eq11)}$
        $\Rightarrow {latex(eq12)}$$\quad\quad$... (4)
        
        The gamma factor,
        ${latex(eq13)}$$\quad\quad$... (5)
        
        From (4) substitute (5),
        $\Rightarrow {latex(eq14)}$
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        
        answer_s = fr"""
        ${latex(eq14)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_plot_speed_and_time(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = fr"""
        Plot time delay with respect to speed of the object
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        fig = self.trh.plot_speed_and_time()
        svgHelper = SvgHelper()
        svg_str = svgHelper.plt_to_svg()
        plt.close() 
        
        soln_s = fr"""
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        
        answer_s = fr"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_plot_speed_and_gamma(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = fr"""
        Plot gamma with respect to speed of the object
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        fig = self.trh.plot_speed_and_gamma()
        svgHelper = SvgHelper()
        svg_str = svgHelper.plt_to_svg()
        plt.close() 
        
        soln_s = fr"""
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        
        answer_s = fr"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_plot_gamma_and_time(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = fr"""
        Plot time delay with respect to gamma
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        fig = self.trh.plot_gamma_and_time()
        svgHelper = SvgHelper()
        svg_str = svgHelper.plt_to_svg()
        plt.close() 
        
        soln_s = fr"""
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        
        answer_s = fr"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_plot_speed_and_length(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = fr"""
        Plot length contraction with respect to speed of the object
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        fig = self.trh.plot_speed_and_length()
        svgHelper = SvgHelper()
        svg_str = svgHelper.plt_to_svg()
        plt.close() 
        
        soln_s = fr"""
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        
        answer_s = fr"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate

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

        problem_s = fr"""
        Plot length contraction with respect to gamma
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        fig = self.trh.plot_gamma_and_length()
        svgHelper = SvgHelper()
        svg_str = svgHelper.plt_to_svg()
        plt.close() 
        
        soln_s = fr"""
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        
        answer_s = fr"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_relativistic_system(self, *args, **kwargs):
        
        math_sys = self.get_relativistic_system()
        
        result = math_sys.get_random_problem(**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





    def _problem_comprehension_space_time(self, *args, **kwargs):
        folder_path = "comprehension/physics/relativity"
        search = "space_time.txt"
        
        search_in_content = kwargs.get("search", None)
        file_paths = self.get_comp_factory().search_comprehension_files(folder_path,
                                                                        search_in_name = search,
                                                                        search_in_content = search_in_content)

        file_path = random.choice(file_paths)
        
        return self.get_comp_factory().PROBLEM_TEMPLATE_COMP_RANDOM_QUESTIONS(file_path, *args, **kwargs)

    

