import numpy as np
from nmreval.utils.constants import *

r"""
Create user-defined fitfunctions using this template.
Order in params and ext_params must agree with order in list p, i.e. p[0] is A_{infty}, p[1] is beta_1,
and C_{delta} is p[2].
Choices are passed to the function as extra arguments (a and g)

Sub- and superscripts of multiple characters are surrounded by braces. 
Use Latex notation for special characters (greek letters, infinity,...).
Put a "r" in front of strings with backslashes.


Known constants are:

* kB: Boltzmann constant (8.6173e-5 eV/K)
* N_A: Avogadro numbaer (6.02214129e23 1/mol)
* R: Gas constant (5.1895e19 eV/(K*mol))
* e: elementary charge (1.602176487e-19 C)
* mu0: magnetic constant (4e-7*pi N/A^2)
* h: Planck constant (6.6260693e-34 Js)
* hbar: reduced PLack constant (=h/(2*pi))
* Eu: Euler-Mascheroni constant (=-psi(1))

Gyromagnetic values of 1H, 2H, 7Li, 13C and 19F are available via gamma['nucleus'] (including factor 2pi, so in s^-1).

class Template(object):
    name = 'Template'
    type = 'User defined'
    equation = r'A_{\infty} x^2 - \beta_{1} exp(-x) + C_{\delta} + \gamma_{1H}'
    params = [r'A_{\infty}', r'\beta_{1}']    
    bounds = [(0, None), (7, 8)]    
    ext_params = [r'C_{\delta}']
    choices = [('a', {'choice 1': 'x', 'choice 2': 'inv_x'}), ('g', gamma)]

    @staticmethod
    def func(p, x, a, g):
        if a == 'x':
            x = x
        elif a == 'inv_x':
            x = 1/x
        return p[0] * x**2 - kB * p[1] * np.exp(-x) + p[2] + g
"""


class Template:
    name = 'Template'
    type = 'User defined'
    equation = r'A_{\infty} x^{2} - k_{B} \beta_{1} exp(-x) + C_{\delta} + \gamma'
    params = [r'A_{\infty}', r'\beta_{1}', r'C_{\delta}']
    bounds = [(0, None), (7, 8), (None, None)]
    choices = [('name in dialog', 'c1',
                {'Increase by': 'increase', 'Invert': 'inv_x'}),
               ('\gamma', 'g', gamma)]

    @staticmethod
    def func(x,
             a_inf, beta, delta,
             c1='inv_x', gamma=gamma['1H']):

        if c1 == 'increase':
            x = x
        elif c1 == 'inv_x':
            x = 1/x
        else:
            x = x

        return a_inf * x**2 - kB * beta * np.exp(-x) + delta + gamma

