'''
Created on 17-Jun-2021

@author: bthakur
'''
from xv.util import listAttr, locatePath
import pathlib
import csv
from latex2sympy2 import latex2sympy, latex2latex
from sympy import sympify, Eq, latex
from xv.util.local import FileSystemManager
import random

from ._formula import Formula

from xv.util import UtilClass


class FormulaHelper(UtilClass):
    '''
    List of maths and physics formulae
        formula
            type_of_formula
            category
            description
            latex_expr

    fh = FormulaHelper()
    fh
    
    formulae_found = fh.search_formulae('Algebra')
    print(f"formulae_found = {len(formulae_found)}")
    
    for formula in formulae_found:
        display(formula)
    
    '''
    
    _MATHS_PHYSICS_FORMULAE_FILE_PATH = 'xv_lib_resources/math/maths_physics_formulae.csv'
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.file_path = self._init_file_path(**kwargs)
        self.formulae = self._load_formulae()
        pass
    
    def get_formulae(self):
        return self.formulae
    
    def get_categories(self):
        categories = []
        for formula in self.formulae:
            categories.extend(formula.categories)
            pass
        return list(set(categories))
        pass
    
    def search_formulae(self, search, has_equation = False):
        
        formulae_found = [formula for formula in self.formulae
                    if formula.has_category(search)
                    ]
        
        if has_equation:
            formulae_found = [formula for formula in formulae_found
                        if not formula.eq is None
                        ]
            
        
        return formulae_found

    def _init_file_path(self, **kwargs):
        file_path = kwargs.get('file_path', None)
        if file_path is None:
            file_path = self.__class__._MATHS_PHYSICS_FORMULAE_FILE_PATH

        from xv.util.data import Repository
        return Repository.FIND_EXACT_FILE(file_path, verbose = self.verbose)
        pass

    def _load_formulae(self, file_path = None):
        
        if not self.file_path:
            return []
        
        formulae = []
    
        with open(self.file_path, newline='') as f:
            reader = csv.reader(f)
            for idx, row in enumerate(reader):
                if idx == 0:
                    keys = row.copy()
                    continue
                if len(row) < 6:
                    print(f"Error: number of columns ={len(row)}: {row}")
                    continue

                data = {field_name:row[i] for i, field_name in enumerate(keys) }

                if data.get('expr_lhs') == 'None':
                    data['expr_lhs'] = None
                    
                if data.get('expr_rhs') == 'None':
                    data['expr_rhs'] = None
                
                formula = Formula(**data)
                formulae.append(formula)
                pass
            pass
        return formulae
        
        pass   

    def load_latex(self, file_path = None, categories = None):
        '''
        the csv file should contain only two fields: latex, descritption 
            
        '''
        
        if file_path is None:
            return None

        if (isinstance(categories, tuple) or 
            isinstance(categories, list)):
            categories = ",".join(categories)
        
        formulae = []
    
        with open(file_path, newline='') as f:
            reader = csv.reader(f)
            for idx, row in enumerate(reader):
                if idx == 0:
                    continue
                if len(row) < 2:
                    print(f"""
                    Error: number of columns ={len(row)}: 
                    {row}
                    """)
                    continue
                
                latex_expr = row[0]
                description = row[1]
                
                if len(row) > 2:
                    row_categories = row[-1]
                    if (row_categories == '' or row_categories == 'None'):
                        row_categories = None
                else:
                    row_categories = categories
                
                if '=' in latex_expr:
                    type_of_formula = 'Equations'
                else:
                    type_of_formula = 'Expressions'
                
                formula = Formula(
                    type_of_formula = type_of_formula,
                    latex_expr = latex_expr,
                    description = description,
                    categories = row_categories
                    )

                formulae.append(formula)
                
        return formulae
        
        pass   

    def _get_field_index(self, field_name, row):
        if field_name in row:
            return row.index(field_name)
        return None
        pass
    
    def _get_field_value(self, field_index, row):
        if field_index is None:
            return None
        return row[field_index]
        pass
    

    def _init_expr(self, expr):
        if expr is None:
            return None
            
        if len(expr.strip()) < 1:
            return None
        
        return self.latex_to_sympy(expr)
        pass

    def latex_to_sympy(self, latex_expr, verbose = False):
        if verbose:
            sOut = f"""
            latex_expr = {latex_expr}
            """
            print(sOut)
        
        if not "=" in latex_expr:
            return None
            
        latex_parts = latex_expr.split('=')
        if verbose:
            sOut = f"""
            latex_parts = {latex_parts}
            """
            print(sOut)
        
        
        texts = []
        for latex_part in latex_parts:
            latex_part = latex_part.strip()
            
            if verbose:
                sOut = f"""
                latex_part = {latex_part}
                """
                print(sOut)
                
            if latex_part.startswith('$'):
                latex_part = latex_part[1:]
            
            if latex_part.endswith('$'):
                latex_part = latex_part[:-1]
            
            if verbose:
                sOut = f"""
                latex_part = {latex_part}
                """
                print(sOut)
                
            text = self._to_sympy(latex_part.strip())

            if verbose:
                sOut = f"""
                text = {text}
                """
                print(sOut)
            

            if text is None:
                return None 
            texts.append(text)
            pass

        lhs_rhs = [(texts[0], texts[i])
            for i in range(1, len(texts))
            ]
        
        return lhs_rhs
        pass
    
    def latex_to_sympy_eq(self, latex_expr):
        if not "=" in latex_expr:
            return self._to_sympy(latex_expr)
            
        latex_parts = latex_expr.split('=')
        
        texts = []
        for latex_part in latex_parts:
            text = self._to_sympy(latex_part.strip())
            if text is None:
                return None 
            texts.append(text)
            pass

        return texts
        
        eqs = [
            Eq(texts[i], texts[i+1], evaluate = False)
            for i in range(len(texts) - 1)
            ]
        if len(eqs) == 1:
            return eqs[0]
        return eqs
        pass
    
    def _to_sympy(self, text):
        if text is None:
            return None
        try:
            return latex2sympy(text.strip())
        except Exception as e1:
            try:
                text = text.replace(r'^', "**").strip()
                text = text.replace("c", "C")
                return latex2sympy(text)
            except Exception as e2:
                return None
            pass
    
        return None
        pass    

    def formulae_to_html(self, formulae):
        formulae_str = []
        for formula in formulae:
            formula_latex = f"""{formula.description}
            ${formula.get_latex_expr(expr_type = 'latex_expr')}$
            """
            
            formulae_str.append(formula_latex)
            pass
        
        formulae_str = "<ol><li>" + "</li><li>".join(formulae_str) + "</li></ol>"
        return formulae_str
        pass

    def __str__(self):
        cls = self.__class__
        s = f"{id(self)}@{cls.__name__}"
        s = f"""{s}\n{cls.__doc__}
        """
        return s
        pass

    def _repr_html_(self):
        return self.__str__().replace("\n", "<br />")
    
    
    pass