'''
Created on 16-Apr-2021

@author: bthakur
'''
import os 
import numpy as np
import random
import inspect
import traceback

from xv.km.ui import SvgHelper         


from sympy import ( symbols, diff, Symbol, Mul, Matrix, 
                    factorial, sympify, Rational,
                    Derivative, factor,
                    exp, sin, cos, cosh, sinh, pi, sqrt, atan)

from sympy.core.numbers import One, Integer


from ._movements import Movements
from ._movement import Movement
        
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, KPrintElement, KPrintHelper

# _movement_plotting_manager
# MovementPlottingManager
        
class MovementPlottingManager(BaseManager):
    '''
    Plotting simple movements using co-ordinates, angles and sin/cos


    Minimum Grade: 4
    Maximum Grade: 12


    Examples
    --------
    ke = MovementPlottingManager()
    ke 
    
    ke.printProblemTypes()
    ke.helpProblemType(0)
    
    ke.getRandomProblem()
    ke.getRandomProblem(problem_type = 0)
    ke.getRandomProblem(problem_type = 0, dim = 2) 


    ke.printAnswer()
    ke.printSolution()
    

    doc_style: xv_doc
    ''' 


    def __new__(cls, *args, **kwargs):
        instance = super(MovementPlottingManager, cls).__new__(cls, *args, **kwargs)
        for base_class in MovementPlottingManager.__bases__:
            base_class.__init__(instance, *args, **kwargs)
        return instance
    
    def __init__(self, *args, **kwargs):
        self.base_helper = BaseHelper(**kwargs)
        self._colors = ['indigo', 'blue', 'green', 'red', 'cyan', 'magenta', 
                        'violet', 'black', 'orange', 'black', 'grey']  
        self._markers = ['o', 'v', '^', '<', '>', '1', '2', '3', '4', 
                         '8', 's', 'p', 'P', '*', 'h', 'H', 'X', 'D', 'd', ]
        self._p_labels = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
        self.lastAnnotationX = 0
        self.lastAnnotationY = 0
        self._movements = None
        
        pass

    def printLength(self, x1, y1, x2, y2):
        mv = Movement.p1p2(x1, y1, x2, y2)
        length_latex = mv.get_length_latex_expr(prefix = '= ')
        content = f"Length of line-segment connecting ({x1}, {y1}) and ({x2}, {y2})<br/><br/>" +  KPrintElement(length_latex, 'text/html').print()
        kph = KPrintHelper()
        return kph.print(content)
        
    def printMovementLengths(self):
        if self._movements is None:
            print("No movement data found")
            return None
        
        return self._movements.printMovementLengths()
    

    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
                '_problem_plot_cartesian_line',
                '_problem_plot_polar_line',
                '_problem_plot_a_line',
                '_problem_plot_cartesian_movement',
                '_problem_plot_polar_movement',
                '_problem_plot_movement',
                #'_problem_plot_arcs',
                #'_problem_plot_multiple_circles',
             ])
        pass

    def _problem_plot_cartesian_line(self, *args, **kwargs):
        """
        Plot simple movements to left/right or up/down in cartesian axes 


        Minimum Grade: 3
        Maximum Grade: 6

    
        Examples
        --------
        from xv.math.algebra import MovementPlottingManager
        ke = MovementPlottingManager()


        ke.getRandomProblem(problem_type = '_problem_plot_cartesian_line')


        doc_style: xv_doc
        """

        
        movements = Movements.random_movements(size = 2, isPolar = False)
        self._movements = movements
        kwargs['problem_type'] = '_problem_plot_cartesian_line'
        return self._process_movements(movements, *args, **kwargs)
        pass
    
    def _problem_plot_polar_line(self, *args, **kwargs):
        """
        Plot simple movements in polar co-ordinates 


        Minimum Grade: 3
        Maximum Grade: 6

    
        Examples
        --------
        from xv.math.algebra import MovementPlottingManager
        ke = MovementPlottingManager()


        ke.getRandomProblem(problem_type = '_problem_plot_polar_line')


        doc_style: xv_doc
        """

        
        movements = Movements.random_movements(size = 2, isPolar = True)
        self._movements = movements
        kwargs['problem_type'] = '_problem_plot_polar_line'
        return self._process_movements(movements, *args, **kwargs)
        pass
    
    def _problem_plot_a_line(self, *args, **kwargs):
        """
        Plot simple movements lines 


        Minimum Grade: 3
        Maximum Grade: 6

    
        Examples
        --------
        from xv.math.algebra import MovementPlottingManager
        ke = MovementPlottingManager()


        ke.getRandomProblem(problem_type = '_problem_plot_a_line')


        doc_style: xv_doc
        """

        
        movements = Movements.random_movements(size = 2)
        self._movements = movements
        kwargs['problem_type'] = '_problem_plot_a_line'
        return self._process_movements(movements, *args, **kwargs)
        pass
    
    def _problem_plot_cartesian_movement(self, *args, **kwargs):
        """
        Plot cartesian movements in any direction 


        Minimum Grade: 3
        Maximum Grade: 6

    
        Examples
        --------
        from xv.math.algebra import MovementPlottingManager
        ke = MovementPlottingManager()


        ke.getRandomProblem(problem_type = '_problem_plot_cartesian_movement')


        doc_style: xv_doc
        """

        
        movements = Movements.random_movements(isPolar = False)
        self._movements = movements
        kwargs['problem_type'] = '_problem_plot_cartesian_movement'
        return self._process_movements(movements, *args, **kwargs)
        pass
    
    
    def _problem_plot_polar_movement(self, *args, **kwargs):
        """
        Plot polar movements in any direction 


        Minimum Grade: 3
        Maximum Grade: 6

    
        Examples
        --------
        from xv.math.algebra import MovementPlottingManager
        ke = MovementPlottingManager()


        ke.getRandomProblem(problem_type = '_problem_plot_polar_movement')


        doc_style: xv_doc
        """

        
        movements = Movements.random_movements(isPolar = True)
        self._movements = movements
        kwargs['problem_type'] = '_problem_plot_polar_movement'
        return self._process_movements(movements, *args, **kwargs)
        pass
    

    def _problem_plot_movement(self, *args, **kwargs):
        """
        Plot movements in any direction 


        Minimum Grade: 3
        Maximum Grade: 6

    
        Examples
        --------
        from xv.math.algebra import MovementPlottingManager
        ke = MovementPlottingManager()


        ke.getRandomProblem(problem_type = '_problem_plot_movement')


        doc_style: xv_doc
        """

        
        movements = Movements.random_movements()
        self._movements = movements
        kwargs['problem_type'] = '_problem_plot_movement'
        return self._process_movements(movements, *args, **kwargs)
        pass
    

    def _process_movements(self, movements, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        statement = f"""Plot the following moves:"""
        expr_s = ""
        for idx, mv in enumerate(movements):
            if idx == 0:
                expr_s = f"{idx + 1}. " +  f"Start at {mv.label}"
                pass
            else:
                expr_s = expr_s + f"\n{idx + 1}. " +  f"{mv.statement} to point {mv.name}"
                pass
            pass

        problemTemplate.add_problem(statement)
        problemTemplate.add_problem(expr_s.strip(), 'text/html')

                
        svgHelper = SvgHelper(verbose = True)
        movements_code = movements.get_movements_code()
        svg_str, plot_code = svgHelper.get_svg_data(movements_code, 
                                                    strip_lines = True)


        problemTemplate.add_solution(plot_code)
        problemTemplate.add_solution(svg_str, 'text/svg')
        problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate
        pass
    
    def _process_movement(self, data, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        x0, y0, movements, custom_code = data
        
        statement = f"""Plot the following moves:"""
        expr_s = ""
        for idx, movement in enumerate(movements):
            if idx == 0:
                expr_s = f"{idx + 1}. " +  f"Start at {self._p_labels[idx]}({x0}, {y0})"
                pass
            else:
                expr_s = expr_s + f"\n{idx + 1}. " +  f"{movement[0]} to point {self._p_labels[idx]}"
                pass
            pass

        problemTemplate.add_problem(statement)
        problemTemplate.add_problem(expr_s.strip(), 'text/html')

                
        svgHelper = SvgHelper()
        #svg_str, plot_code = svgHelper.get_svg_data(custom_code)
        svg_str, plot_code = svgHelper.get_svg_data(custom_code, strip_lines = True)


        problemTemplate.add_solution(plot_code)
        problemTemplate.add_solution(svg_str, 'text/svg')
        problemTemplate.add_answer(svg_str, 'text/svg')
        
        return problemTemplate
        pass
    
