'''
Created on 12-Jul-2021

@author: bthakur

TR0 - simplify expression
TR1 - sec-csc to cos-sin
TR2 - tan-cot to sin-cos ratio
TR2i - sin-cos ratio to tan
TR3 - angle canonicalization
TR4 - functions at special angles
TR5 - powers of sin to powers of cos
TR6 - powers of cos to powers of sin
TR7 - reduce cos power (increase angle)
TR8 - expand products of sin-cos to sums
TR9 - contract sums of sin-cos to products
TR10 - separate sin-cos arguments
TR10i - collect sin-cos arguments
TR11 - reduce double angles
TR12 - separate tan arguments
TR12i - collect tan arguments
TR13 - expand product of tan-cot
TRmorrie - prod(cos(x*2**i), (i, 0, k - 1)) -> sin(2**k*x)/(2**k*sin(x))
TR14 - factored powers of sin or cos to cos or sin power
TR15 - negative powers of sin to cot power
TR16 - negative powers of cos to tan power
TR22 - tan-cot powers to negative powers of sec-csc functions
TR111 - negative sin-cos-tan powers to csc-sec-cot

use finite_difference

check https://github.com/sympy/sympy/issues/11155

>>> from sympy import *
>>> y = symbols('y')
>>> U = Function('U')(y)
>>> dU = Function('\delta U')(y)
>>> diff(U + dU,y).expand()
Derivative(U(y), y) + Derivative(\delta U(y), y)

https://stackoverflow.com/questions/46411124/how-to-rewrite-an-abstract-derivative-of-a-sum-as-a-sum-of-derivatives-in-sympy/46411350

'''

import inspect
import traceback
import random
from sympy import (latex, Symbol, symbols,
                   Rational,
                   )

from sympy import (cos, sin, tan, sec, csc, cot,
                   exp, I, pi,
                   sqrt,
                   simplify,
                   UnevaluatedExpr as ueval)
import sympy

from itertools import product

from sympy.simplify.fu import (TR111,TR22,TR16,TR15,TR14,
        TRmorrie,TR13,TR12i,TR12,TR11,TR10i,TR10,TR9,
        TR8,TR7,TR6,TR5,TR4,TR3,TR2i,TR2,TR1,TR0,
        TRpower, fu)

# _func_transform_helper
# FuncTransformHelper

from .._trigonometry import FuncTrTransformHelper
from ._funct_simp_transform_helper import FuncSimpTransformHelper

from xv.util import UtilClass

class FuncTransformHelper(UtilClass):
    '''
    This class provides identities and their proofs.
    TrigIdentityHelper is a subset of this.
    '''


    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.verbose = kwargs.get('verbose', False)
        self.fst_helper = FuncSimpTransformHelper(**kwargs)
        self.ftt_helper = FuncTrTransformHelper(**kwargs)
        pass

    def get_simp_transforms(self):
        return self.fst_helper.get_simp_transforms()
        pass

    def get_sum_of_terms_transforms(self):
        return self.fst_helper.get_sum_of_terms_transforms()
        pass

    def get_tr_transforms(self):
        return self.ftt_helper.get_tr_transforms()
        pass



    def get_random_sample_transforms(self, func_transforms = None, count = 4):
        if func_transforms is None:
            return None

        keys = list(func_transforms.keys())
        count = min(count, len(func_transforms))

        identifier = f"{self.__class__.__name__}{id(self)}.{inspect.stack()[0][3]}"
        random_keys = self.get_no_repeat_random_sample(identifier, keys, count)

        sample_transforms = {k: v for k, v in func_transforms.items()
                                if k in random_keys}
        return sample_transforms
        pass



    def func_transforms_to_str(self, func_transforms):

        funcs_str = []
        transforms_str = []
        for k, vs in func_transforms.items():
            k_str = f""" $\\displaystyle {latex(k)}$ """
            kv_str = [f""" $\\displaystyle
                        \\Large{{  \\color{{red}}{{{latex(k)}}}   }}
                        $ """]
            for v in vs:
                v_str = f""" $\\displaystyle = {latex(v)}$ """
                kv_str.append(v_str)
                pass

            kv_str = "\n\n".join(kv_str)

            funcs_str.append(k_str)
            transforms_str.append(kv_str)
            pass

        funcs_str = "\n\n".join(funcs_str)
        transforms_str = "\n\n\n".join(transforms_str)

        result = {
            'funcs_str': funcs_str,
            'transforms_str': transforms_str,
            }
        return result
        pass

    def _log_DELETED(self, sOut, to_print = None):
        if to_print is None:
            to_print = self.verbose

        if to_print:
            print(sOut)



    pass
#class FuncTransformHelper:
