'''
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.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

#  BanachTarskiParadox
#  _banach_tarski_paradox
class BanachTarskiParadoxManager(BaseManager):
    '''
    Circle and its geometry
    Example:
        ke = BanachTarskiParadoxManager()
        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(BanachTarskiParadoxManager, cls).__new__(cls, *args, **kwargs)
        for base_class in BanachTarskiParadoxManager.__bases__:
            base_class.__init__(instance, *args, **kwargs)
        return instance
    
    def __init__(self, *args, **kwargs):
        self.base_helper = BaseHelper(**kwargs)
        self.geometry_helper = self.base_helper.get_geometry_helper()
        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', 'o']
        self._p_labels = 'ABCDEFGHIJKLMNPQRSTUVWXYZ'
        self._center_label = 'O'
        self._center = (0, 0)
        
        self._default_font_size = 10
        self._default_fig_size = 6
        self._axis_multiplier = 1.2
        pass


    def _plot_code_circle(self, center = None, axis_off = True, axis_lim = None):
        if center is None:
            center = self._center

        if center == (0, 0):
            s_xs_ys = f"""
            xs = cos(angles)
            ys = sin(angles)
            """
        else:
            s_xs_ys = f"""
            xs = {center[0]} + cos(angles)
            ys = {center[1]} + sin(angles)
            """
        if axis_off:
            s_axis_off = "plt.axis('off')"
        else:
            s_axis_off = ""
            
        if axis_lim is None:
            axis_lim = max(abs(center[0]), abs(center[1])) + self._axis_multiplier
        
        idx = -1
        marker = self._markers[idx]
        color = self._colors[idx]
        markersize = self._default_font_size

        code_0 = f"""import numpy as np
            from numpy import linspace, pi, sin, cos
            fig = plt.figure(figsize=({self._default_fig_size}, {self._default_fig_size}))

            angles = linspace(0 * pi, 2 * pi, 100 )
            """
        code_1 = f"""{s_xs_ys.strip()}
            {self._code_piece_circle(center, marker, color, markersize)}
        """
        code_2 = f"""#optional code
            plt.xlim(-{axis_lim}, {axis_lim})
            plt.ylim(-{axis_lim}, {axis_lim})
            plt.gca().set_aspect('equal')
            {s_axis_off}
        """
        return (code_0, code_1, code_2)
        pass

    def _code_piece_circle(self, center, marker, color, markersize):
        circle_code = f"""#plot center
            plt.plot({center[0]}, {center[1]}, marker = '{marker}', color = '{color}', markersize = {markersize})
            plt.gca().annotate('{self._center_label} ({center[0]}, {center[1]})', xy=({center[0]}-0.20, {center[1]}-0.12), xycoords='data', fontsize={self._default_font_size})

            #plot circle
            plt.plot(xs, ys, color = '{color}')
        """
        
        return circle_code
        pass


    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
            '_problem_plot_a_unit_circle_with_marked_integers',
            '_problem_plot_four_unit_circles_with_marked_integers',
         ])
        pass
    

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

        use_cache = kwargs.get('use_cache', True)
        refresh_cache = kwargs.get('refresh_cache', False)
        
        ch = self.geometry_helper.get_circle_helper()
        #plot_code, svg_str = ch.plot_a_unit_circle_with_marked_integers(point_count,
        #                                                                use_cache = True)
        
        plotting_method = ch.plot_a_unit_circle_with_marked_integers
        
        plot_code, svg_str = self.base_helper.call_plot_method(plotting_method, 
                                                               point_count,
                                                               use_cache = use_cache,
                                                               refresh_cache = refresh_cache)
        
        statement = f"""Plot a unit circle and mark the points 0, 1, 2, ..."""
        problemTemplate.add_problem(statement)

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

        
        problemTemplate.add_answer(svg_str, 'text/svg')

        return problemTemplate
        pass
    
    
    def _problem_plot_four_unit_circles_with_marked_integers(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        point_count = kwargs.get('point_count', 100)
        


        use_cache = kwargs.get('use_cache', True)
        refresh_cache = kwargs.get('refresh_cache', False)
        
        ch = self.geometry_helper.get_circle_helper()
        #plot_code, svg_str = ch.plot_four_unit_circles_with_marked_integers(point_count,
        #                                                    use_cache = True)
        
        plotting_method = ch.plot_four_unit_circles_with_marked_integers
        
        plot_code, svg_str = self.base_helper.call_plot_method(plotting_method, 
                                                               point_count,
                                                               use_cache = use_cache,
                                                               refresh_cache = refresh_cache)
        
        
        statement = f"""Plot a unit circle and mark the points 0, 1, 2, ..."""
        problemTemplate.add_problem(statement)

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

        
        problemTemplate.add_answer(svg_str, 'text/svg')

        return problemTemplate
        pass
    
