'''
Created on 20-Jan-2022

@author: bthakur
'''

import os
import codecs
import inspect
import traceback
import random
import time

from xv.util import HtmlUtil



from xv.util import UtilClass, listAttr

class BaseHelper(UtilClass):
    _EXTERNAL_LINKS_FILE_PATH = 'resources/_math_external_links.csv'
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        
        start_time = time.time()
        
        self._algebra_helper = None
        self._aops_helper = None
        self._putnam_helper = None
        self._arithmetic_helper = None

        self._calculus_helper = None
        self._common_helper = None
        
        self._general_helper = None
        self._geometry_helper = None
        
        self._probability_helper = None
        self._stats_helper = None
        
        self._trigonometry_helper = None
        self._vector_helper = None

        self._cache_processor = None
        self._svg_helper = None
        self._plotter_2d = None

        self._web_link_helper = None

        
        self._crypto_helper = None
        
        self._fourier_helper = None
        self._complex_fourier_helper = None
        
        
        self._statement_to_expr_helper = None
        self._modelling_helper = None
        self._modelling_percentage_helper = None
        
        
        self._mid_level_math_helper = None
        
        
        self._plotting_helper = None
        
        self._text_to_speech_helper = None
        
        self._kwargs = kwargs
        
        self.htmlUtil = HtmlUtil()
        pass

    def get_helper(self, name):
        start_time = time.time()
        
        helper_instance = self.get_helper_instance(name)
    
        if not helper_instance is None:
            full_classpath = str(type(helper_instance)).split("'")[1]
            sOut = f"""
            {self.__class__.__name__}.{inspect.stack()[0][3]}: ({self._get_elapsed_time(start_time)} sec)
            Returing an instance of {full_classpath}
            """
            self._log(sOut.strip())
            return helper_instance
        
        sOut = f"""
        {self.__class__.__name__}.{inspect.stack()[0][3]}: ({self._get_elapsed_time(start_time)} sec)
        Failed to locate helper with name {repr(name)}.
        """
        self._log(sOut.strip())

        return None
        pass


    def get_algebra_helper(self):
        if self._algebra_helper is None:
            self._init_algebra_helper(**self._kwargs)
        return self._algebra_helper
        pass

    def _init_algebra_helper(self, **kwargs):  
        from ._algebra import AlgebraHelper
        self._algebra_helper = AlgebraHelper(**kwargs) 
        pass



    def get_aops_helper(self):
        if self._aops_helper is None:
            self._init_aops_helper(**self._kwargs)
        return self._aops_helper
        pass

    def _init_aops_helper(self, **kwargs):  
        from ._aops import AopsHelper
        self._aops_helper = AopsHelper(**kwargs) 
        pass


    def get_putnam_helper(self):
        if self._putnam_helper is None:
            self._init_putnam_helper(**self._kwargs)
        return self._putnam_helper
        pass

    def _init_putnam_helper(self, **kwargs):  
        from ._putnam import PutnamHelper
        self._putnam_helper = PutnamHelper(**kwargs) 
        pass



    def get_arithmetic_helper(self):
        if self._arithmetic_helper is None:
            self._init_arithmetic_helper(**self._kwargs)
        return self._arithmetic_helper
        pass

    def _init_arithmetic_helper(self, **kwargs):  
        from ._arithmetic import ArithmeticHelper
        self._arithmetic_helper = ArithmeticHelper(**kwargs) 
        pass



    def get_calculus_helper(self):
        if self._calculus_helper is None:
            self._init_calculus_helper(**self._kwargs)
        return self._calculus_helper
        pass

    def _init_calculus_helper(self, **kwargs):  
        from ._calculus import CalculusHelper
        self._calculus_helper = CalculusHelper(**kwargs) 
        pass


    def get_common_helper(self):
        if self._common_helper is None:
            self._init_common_helper(**self._kwargs)
        return self._common_helper
        pass

    def _init_common_helper(self, **kwargs):  
        from ._common import CommonHelper
        self._common_helper = CommonHelper(**kwargs) 
        pass


    def get_general_helper(self):
        if self._general_helper is None:
            self._init_general_helper(**self._kwargs)
        return self._general_helper
        pass

    def _init_general_helper(self, **kwargs):  
        from ._general import GeneralHelper
        self._general_helper = GeneralHelper(**kwargs) 
        pass


    def get_geometry_helper(self):
        if self._geometry_helper is None:
            self._init_geometry_helper(**self._kwargs)
        return self._geometry_helper
        pass

    def _init_geometry_helper(self, **kwargs):  
        from ._geometry import GeometryHelper
        self._geometry_helper = GeometryHelper(**kwargs) 
        pass

   
    def get_probability_helper(self):
        if self._probability_helper is None:
            self._init_probability_helper(**self._kwargs)
        return self._probability_helper
        pass

    def _init_probability_helper(self, **kwargs):  
        from ._probability import ProbabilityHelper
        self._probability_helper = ProbabilityHelper(**kwargs) 
        pass

    def get_stats_helper(self):
        if self._stats_helper is None:
            self._init_stats_helper(**self._kwargs)
        return self._stats_helper
        pass

    def _init_stats_helper(self, **kwargs):  
        from ._stats import StatsHelper
        self._stats_helper = StatsHelper(**kwargs) 
        pass


    def get_trigonometry_helper(self):
        if self._trigonometry_helper is None:
            self._init_trigonometry_helper(**self._kwargs)
        return self._trigonometry_helper
        pass

    def _init_trigonometry_helper(self, **kwargs):  
        from ._trigonometry import TrigonometryHelper
        self._trigonometry_helper = TrigonometryHelper(**kwargs) 
        pass

    def get_vector_helper(self):
        if self._vector_helper is None:
            self._init_vector_helper(**self._kwargs)
        return self._vector_helper
        pass

    def _init_vector_helper(self, **kwargs):  
        from ._vector import VectorHelper
        self._vector_helper = VectorHelper(**kwargs) 
        pass


    def call_plot_method(self, method, *args, **kwargs):
        '''
        It returns plot_code, svg_str
        
        @method: method to be called
        Pass these two methods to use cache util. Any other params passed will be subsequently 
        passed to the method to be called.
        @use_cache = True/False
        @refresh_cache = False/True
        '''
        cache_processor = self.get_cache_processor()
        plot_code, svg_str = cache_processor.get_svg_and_runnable_code(method, 
                                                                       *args, 
                                                                       **kwargs)
        plot_code = plot_code.replace("self.verbose", "False")
        return plot_code, svg_str
        pass


    def get_cache_processor(self):
        if self._cache_processor is None:
            self._init_cache_processor(**self._kwargs)
        return self._cache_processor
        pass

    def _init_cache_processor(self, **kwargs):  
        from xv.util.data import CacheProcessor
        self._cache_processor = CacheProcessor(**kwargs)
        pass


    def get_svg_helper(self):
        if self._svg_helper is None:
            self._init_svg_helper(**self._kwargs)
        return self._svg_helper
        pass

    def _init_svg_helper(self, **kwargs):  
        from xv.km.ui import SvgHelper  
        self._svg_helper = SvgHelper(**kwargs)
        pass



    def get_plotter_2d(self):
        if self._plotter_2d is None:
            self._init_plotter_2d(**self._kwargs)
        return self._plotter_2d
        pass

    def _init_plotter_2d(self, **kwargs):  
        from xv.plotter.core import Plotter2D
        self._plotter_2d = Plotter2D(**kwargs)
        pass


    def get_web_link_helper(self):
        if self._web_link_helper is None:
            self._init_web_link_helper(**self._kwargs)
            
        return self._web_link_helper
        pass

    def _init_web_link_helper(self, **kwargs):  
        import pathlib
        file_path = BaseHelper._EXTERNAL_LINKS_FILE_PATH
        root_folder = pathlib.Path(__file__).parent.absolute()

        from xv.km.helper import WebLinkHelper
        self._web_link_helper = WebLinkHelper(file_path = file_path,
                                              root_folder = root_folder,
                                              verbose = self.verbose)
        pass
    


    def get_crypto_helper(self):
        if self._crypto_helper is None:
            self._init_crypto_helper(**self._kwargs)
        return self._crypto_helper
        pass

    def _init_crypto_helper(self, **kwargs):  
        from ._crypto import CryptoHelper
        self._crypto_helper = CryptoHelper(**kwargs) 
        pass


    def get_fourier_helper(self):
        if self._fourier_helper is None:
            self._init_fourier_helper(**self._kwargs)
        return self._fourier_helper
        pass

    def _init_fourier_helper(self, **kwargs):  
        from ._fourier import FourierHelper
        self._fourier_helper = FourierHelper(**kwargs) 
        pass
   
    def get_complex_fourier_helper(self):
        if self._complex_fourier_helper is None:
            self._init_complex_fourier_helper(**self._kwargs)
        return self._complex_fourier_helper
        pass

    def _init_complex_fourier_helper(self, **kwargs):  
        from ._fourier import ComplexFourierHelper
        self._complex_fourier_helper = ComplexFourierHelper(**kwargs) 
        pass
   

  
   
    def get_statement_to_expr_helper(self):
        if self._statement_to_expr_helper is None:
            self._init_statement_to_expr_helper(**self._kwargs)
        return self._statement_to_expr_helper
        pass

    def _init_statement_to_expr_helper(self, **kwargs):  
        from ._data_model import StatementToExprHelper
        self._statement_to_expr_helper = StatementToExprHelper(**kwargs) 
        pass
   
    def get_modelling_helper(self):
        if self._modelling_helper is None:
            self._init_modelling_helper(**self._kwargs)
        return self._modelling_helper
        pass

    def _init_modelling_helper(self, **kwargs):  
        from ._data_model import ModellingHelper
        self._modelling_helper = ModellingHelper(**kwargs) 
        pass
   
    def get_modelling_percentage_helper(self):
        if self._modelling_percentage_helper is None:
            self._init_modelling_percentage_helper(**self._kwargs)
        return self._modelling_percentage_helper
        pass

    def _init_modelling_percentage_helper(self, **kwargs):  
        from ._data_model import ModellingPercentageHelper
        self._modelling_percentage_helper = ModellingPercentageHelper(**kwargs) 
        pass
   
   
   
    def get_mid_level_math_helper(self):
        if self._mid_level_math_helper is None:
            self._init_mid_level_math_helper(**self._kwargs)
        return self._mid_level_math_helper
        pass

    def _init_mid_level_math_helper(self, **kwargs):  
        from ._mid_level import MidLevelMathHelper
        self._mid_level_math_helper = MidLevelMathHelper(**kwargs) 
        pass

   
   
    def get_plotting_helper(self):
        if self._plotting_helper is None:
            self._init_plotting_helper(**self._kwargs)
        return self._plotting_helper
        pass

    def _init_plotting_helper(self, **kwargs):  
        from ._plotting import PlottingHelper
        self._plotting_helper = PlottingHelper(**kwargs) 
        pass
   
   
    def get_text_to_speech_helper(self):
        if self._text_to_speech_helper is None:
            self._init_text_to_speech_helper(**self._kwargs)
        return self._text_to_speech_helper
        pass

    def _init_text_to_speech_helper(self, **kwargs):  
        from xv.util import TextToSpeechUtil
        self._text_to_speech_helper = TextToSpeechUtil(**kwargs) 
        pass
   
   
    
    def _get_elapsed_time(self, start_time = None):
        if start_time is None:
            start_time = self.start_time
        return round(time.time() - start_time, 2)
            
    pass
#class BaseHelper:
