'''
Created on 16-Apr-2021

@author: rishi_priyansh

Speed, time, distace, acceleration
cost, qty, rate, inflation
force and syatem of two particles - electrostatic, gravity, some force func
    how they move, energy and momentum
    
force and syatem of two particles - continuous, discrete
ellipse vs circle as orbit


'''
import os 
import numpy as np
import random
import inspect
import traceback

from ..helper import BaseHelper

from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate
        
from sympy import (Symbol, symbols, 
                   Derivative, Integral,
                   UnevaluatedExpr,
                   latex, Rational, Eq
                   )

class NewtonianSpaceTimeManager(BaseManager):
    '''
    NewtonianSpaceTimeManager

    For details on graph, see DecodingXyGraphManager
    
    
    Example:
        ke = NewtonianSpaceTimeManager()
        ke
        
        ke.printProblemTypes()
        
        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ke.getRandomProblem(problem_type = 1)
        ...
        
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()
        
        ke.printLength(2, 5, 3, -1)
        ke.printMovementLengths()        
        
        
    '''    
    def __new__(cls, *args, **kwargs):
        instance = super(NewtonianSpaceTimeManager, cls).__new__(cls, *args, **kwargs)
        for base_class in NewtonianSpaceTimeManager.__bases__:
            base_class.__init__(instance, *args, **kwargs)
        return instance
    
    def __init__(self, *args, **kwargs):
        self.base_helper = BaseHelper(**kwargs)
        self._newtonian_gravitation_system = None
        pass
    
    def get_newtonian_gravitation_system(self, *args, **kwargs):
        if self._newtonian_gravitation_system is None:
            from xv.km.mathsys import MathSystemFactory, NewtonianGravitationSystem
            math_sys = MathSystemFactory.GET_INSTANCE(NewtonianGravitationSystem, 
                                                      use_cache = True,
                                                      verbose = self.verbose)
            self._newtonian_gravitation_system = math_sys
            pass

        return self._newtonian_gravitation_system
        pass


    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
            '_problem_overview_one_dimention',
            '_problem_discrete_time_position_graph',
            '_problem_discrete_time_velocity_graph',
            '_problem_newtonian_gravitation_system',
         ])
        pass

    def _problem_overview_one_dimention(self, *args, **kwargs):
        nts_helper = self.base_helper.get_newtonian_space_time_helper()
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Overview of Newtonian time space in one dimension.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        result = nts_helper.get_statement()
        
        soln_s = f"""
        <b>Let</b>
        {result['label_dict_str']}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        soln_s = f"""
        <b>advanced_form</b>
        {result['advanced_form']}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

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

    def _problem_discrete_time_position_graph(self, *args, **kwargs):
        nts_helper = self.base_helper.get_newtonian_space_time_helper()
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        result = nts_helper.get_discrete_time_position_graph()
        
        problem_s = f"""
        Write a commentary on the following 
        {result['x_label']}({result['x']}) vs {result['y_label']}({result['y']}) 
        graph.
        """
        problemTemplate.add_problem(problem_s.replace("\n", " ").strip(), 'text/html')
        problemTemplate.add_problem(result['svg_str'], 'text/svg')


        soln_s = f"""
        <b>Let</b>
        {result['label_dict_str']}

        <b>The graph is shown for (x = {result['x_label']}, y = {result['y_label']}).</b>
        
        <b>Change in {result['x_label']}</b>
        {result['delta_x_stmt'].strip()}

        <b>Change in {result['y_label']}</b>
        {result['delta_y_stmt'].strip()}
        
        <b>Average {result['slope_label']}</b>
        {result['result_average_slope']['slope_stmt'].strip()}
        {result['result_average_slope']['svg_str']}

        <b>{result['slope_label']} between two points</b>
        {result['result_rndm_slope']['slope_stmt'].strip()}
        {result['result_rndm_slope']['svg_str']}

        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        soln_s = f"""
        <h2>PLot Code:</h2>
        <pre>{result['plot_code']}</pre>
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(result['svg_str'], 'text/svg')

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

    def _problem_discrete_time_velocity_graph(self, *args, **kwargs):
        nts_helper = self.base_helper.get_newtonian_space_time_helper()
        
        
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        result = nts_helper.get_discrete_time_velocity_graph()
        

        problem_s = f"""
        Write a commentary on the following 
        {result['x_label']}({result['x']}) vs {result['y_label']}({result['y']}) graph.
        """
        problemTemplate.add_problem(problem_s.replace("\n", " ").strip(), 'text/html')
        problemTemplate.add_problem(result['svg_str'], 'text/svg')
        
        
        soln_s = f"""
        <b>Let</b>
        {result['label_dict_str']}

        <b>The graph is shown for (x = {result['x_label']}, y = {result['y_label']}).</b>
        
        <b>The {result['area_label']} between two consecutive points</b>
        {result['result_rndm_area']['svg_str']}
        {result['result_rndm_area']['area_stmt'].strip()}
        
        <b>Total {result['area_label']}</b>
        {result['result_total_area']['svg_str']}
        {result['result_total_area']['area_stmt'].strip()}
        
        <b>Change in {result['x_label']}</b>
        {result['delta_x_stmt'].strip()}

        <b>Change in {result['y_label']}</b>
        {result['delta_y_stmt'].strip()}

        <b>Average {result['slope_label']}</b>
        {result['result_average_slope']['slope_stmt'].strip()}
        
        Similarly:
        {result['result_rndm_slope']['slope_stmt'].strip()}
        
        <b>{result['slope_label']} at a point:</b>
        {result['result_slope_at_a_point']['slope_stmt'].strip()}
        
        
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        soln_s = f"""
        <h2>PLot Code:</h2>
        <pre>{result['plot_code']}</pre>
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_solution(result['svg_str'], 'text/svg')

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


    def _problem_newtonian_gravitation_system(self, *args, **kwargs):
        
        math_sys = self.get_newtonian_gravitation_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
