from __future__ import print_function
import Manyo as mm
import Manyo.LevmarTools as ml
import math
import numpy as np

################################################################################################################

def Gaussian(param1,param2,param3,initial_bin,final_bin,delta_bin,errFact):
    """
    @param param1        (float) hight
    @param param2        (float) center
    @param param3        (float) fwhm
    @param initial_bin   (float)
    @param final_bin     (float)
    @param delta_bin     (float)
    @param errFact       (float)
    @retval ec (ElementContainer)
    """
    ybin=[]
    ebin=[]
    xbin=[]
    ibin=[]

    num_of_bin=int(math.ceil(math.fabs((initial_bin - final_bin)/delta_bin)))

    for i in range(num_of_bin):
        ibin.append(initial_bin+i*delta_bin)
    param=[]
    param.append(param1)
    param.append(param2)
    param.append(param3)

    func = ml.AdvFuncComb("g",param)

    for i in ibin:
        ybin.append(func.eval(i))
        xbin.append(i-delta_bin/2)
    xbin.append(final_bin+delta_bin/2)
    for i in range(num_of_bin):
        if (errFact<1):
            err = 0
        else:
            err = math.sqrt(ybin[i]*fact*100)/fact/100
        ebin.append(err)

    ec=mm.ElementContainer()

    ec.Add("x",xbin)
    ec.Add("y",ybin)
    ec.Add("e",ebin)

    ec.SetKeys("x","y","e")

    return ec

################################################################################################################

def Lorentzian(param1,param2,param3,initial_bin,final_bin,delta_bin,errFact):
    """
    @param param1        (float)
    @param param2        (float)
    @param param3        (float)
    @param initial_bin   (float)
    @param final_bin     (float)
    @param delta_bin     (float)
    @param errFact       (float)
    @retval ec (ElementContainer)
    """
    ybin=[]
    ebin=[]
    xbin=[]
    ibin=[]

    num_of_bin=int(math.ceil(math.fabs((initial_bin - final_bin)/delta_bin)))

    for i in range(num_of_bin):
        ibin.append(initial_bin+i*delta_bin)
    param=[]
    param.append(param1)
    param.append(param2)
    param.append(param3)

    func = ml.AdvFuncComb("l",param)

    for i in ibin:
        ybin.append(func.eval(i))
        xbin.append(i-delta_bin/2)
    fact = pow(10,math.ceil(math.fabs(math.log10(max(ybin)))))
    xbin.append(final_bin+delta_bin/2)
    for i in range(num_of_bin):
        if (errFact<1):
            err = 0
        else:
            err = math.sqrt(ybin[i]*fact*100)/fact/100
        ebin.append(err)

    ec=mm.ElementContainer()

    ec.Add("x",xbin)
    ec.Add("y",ybin)
    ec.Add("e",ebin)

    ec.SetKeys("x","y","e")

    return ec

################################################################################################################

def Function(function,param,initial_bin,final_bin,delta_bin,errFact):
    """
    @function            (string)
    @param param         (string)
    @param initial_bin   (float)
    @param final_bin     (float)
    @param delta_bin     (float)
    @param errFact       (float)
    @retval ec (ElementContainer)
    """
    ybin=[]
    ebin=[]
    xbin=[]
    ibin=[]

    num_of_bin=int(math.ceil(math.fabs((initial_bin - final_bin)/delta_bin)))

    for i in range(num_of_bin):
        ibin.append(initial_bin+i*delta_bin)


    paramString = param.split(",")

    paramFloat = []
    for i in range(len(paramString)):
        paramFloat.append(float(paramString[i]))

    func = ml.AdvFuncComb(function,paramFloat)

    for i in ibin:
        ybin.append(func.eval(i))
        ebin.append(0)
        xbin.append(i-delta_bin/2)
    xbin.append(final_bin+delta_bin/2)
    for i in range(num_of_bin):
        if (errFact<1):
            err = 0
        else:
            err = math.sqrt(ybin[i]*fact*100)/fact/100
        ebin.append(err)

    ec=mm.ElementContainer()

    ec.Add("x",xbin)
    ec.Add("y",ybin)
    ec.Add("e",ebin)

    ec.SetKeys("x","y","e")
    return ec

################################################################################################################

def NumpyHammingWindow(ec0):
    """
    @param ec0            (ElementContainer)
    @retval ec            (ElementContainer)
    """
    xbin = ec0.PutX()
    ybin = ec0.PutY()
    ebin = ec0.PutE()

    Window = np.hamming(ybin.size())

    ybin_new = []
    ebin_new = []

    for i in range(ybin.size()):
        ybin_new.append(float(ybin[i]*Window[i]))
        ebin_new.append(float(ebin[i]*Window[i]))
    ec=mm.ElementContainer()

    ec.Add("x",xbin)
    ec.Add("y",ybin_new)
    ec.Add("e",ebin_new)

    ec.SetKeys("x","y","e")

    return ec

################################################################################################################

def NumpyHanningWindow(ec0):
    """
    @param ec0            (ElementContainer)
    @retval ec            (ElementContainer)
    """
    xbin = ec0.PutX()
    ybin = ec0.PutY()
    ebin = ec0.PutE()

    Window = np.hanning(ybin.size())

    ybin_new = []
    ebin_new = []

    for i in range(ybin.size()):
        ybin_new.append(float(ybin[i]*Window[i]))
        ebin_new.append(float(ebin[i]*Window[i]))
    ec=mm.ElementContainer()

    ec.Add("x",xbin)
    ec.Add("y",ybin_new)
    ec.Add("e",ebin_new)

    ec.SetKeys("x","y","e")

    return ec

################################################################################################################

def NumpyBlackmanWindow(ec0):
    """
    @param ec0            (ElementContainer)
    @retval ec            (ElementContainer)
    """
    xbin = ec0.PutX()
    ybin = ec0.PutY()
    ebin = ec0.PutE()

    Window = np.blackman(ybin.size())

    ybin_new = []
    ebin_new = []

    for i in range(ybin.size()):
        ybin_new.append(float(ybin[i]*Window[i]))
        ebin_new.append(float(ebin[i]*Window[i]))
    ec=mm.ElementContainer()

    ec.Add("x",xbin)
    ec.Add("y",ybin_new)
    ec.Add("e",ebin_new)

    ec.SetKeys("x","y","e")

    return ec

################################################################################################################

def NumpyBartlettWindow(ec0):
    """
    @param ec0            (ElementContainer)
    @retval ec            (ElementContainer)
    """
    xbin = ec0.PutX()
    ybin = ec0.PutY()
    ebin = ec0.PutE()

    Window = np.bartlett(ybin.size())

    ybin_new = []
    ebin_new = []

    for i in range(ybin.size()):
        ybin_new.append(float(ybin[i]*Window[i]))
        ebin_new.append(float(ebin[i]*Window[i]))
    ec=mm.ElementContainer()

    ec.Add("x",xbin)
    ec.Add("y",ybin_new)
    ec.Add("e",ebin_new)

    ec.SetKeys("x","y","e")

    return ec

################################################################################################################

def RotationX(ec0,num):
    """
    @param ec0            (ElementContainer)
    @param num            (int)
    @retval ec            (ElementContainer)
    """

    xbin = ec0.PutX()
    ybin = ec0.PutY()
    ebin = ec0.PutE()

    ybin_new = []
    ebin_new = []

    ec=mm.ElementContainer()

    if (num>ybin.size() or num<1):
        print("maximum value of num is input EC-ybin-size")
    else:
        for i in range(ybin.size()):
            if (i<=ybin.size()-num-1):
                ybin_new.append(ybin[i+num])
                ebin_new.append(ebin[i+num])
            elif ((i>ybin.size()-num-1)):
                ybin_new.append(ybin[i-(ybin.size()-num)])
                ebin_new.append(ebin[i-(ybin.size()-num)])
        ec.Add("x",xbin)
        ec.Add("y",ybin_new)
        ec.Add("e",ebin_new)
        ec.SetKeys("x","y","e")

    return ec

################################################################################################################

def HalfRotationX(ec0):
    """
    @param ec0            (ElementContainer)
    @param num            (int)
    @retval ec            (ElementContainer)
    """

    num=int(math.ceil(ec0.PutY().size()*0.5))

    ec=mm.ElementContainer()
    ec=RotationX(ec0,num)

    return ec

################################################################################################################

def AddZeroUpper(ec0,number):
    """
    @param ec0            (ElementContainer)
    @param number         (int)
    @retval ec            (ElementContainer)
    """

    xbin = ec0.PutX()
    ybin = ec0.PutY()
    ebin = ec0.PutE()

    initial= xbin[0]
    final= xbin[xbin.size()-1]
    delta = xbin[1]-xbin[0]

    xbin_new = []
    ybin_new = []
    ebin_new = []

    zero = 1e-10

    for i in range(ybin.size()):
        xbin_new.append(xbin[i])
        ybin_new.append(ybin[i])
        ebin_new.append(ebin[i])
    xbin_new.append(final)

    for i in  range(number):
        xbin_new.append(final+(i+1)*delta)
        ybin_new.append(zero)
        ebin_new.append(zero)

    ec=mm.ElementContainer()

    ec.Add("x",xbin_new)
    ec.Add("y",ybin_new)
    ec.Add("e",ebin_new)

    ec.SetKeys("x","y","e")

    return ec


################################################################################################################

def AddZeroLower(ec0,number):
    """
    @param ec0            (ElementContainer)
    @param number         (int)
    @retval ec            (ElementContainer)
    """

    xbin = ec0.PutX()
    ybin = ec0.PutY()
    ebin = ec0.PutE()

    initial= xbin[0]
    final= xbin[xbin.size()-1]
    delta = xbin[1]-xbin[0]

    xbin_new = []
    ybin_new = []
    ebin_new = []

    zero = 1e-10 

    for i in range(number):
        xbin_new.append(initial+(-number+i)*delta)
        ybin_new.append(zero)
        ebin_new.append(zero)

    for i in range(ybin.size()):
        xbin_new.append(xbin[i])
        ybin_new.append(ybin[i])
        ebin_new.append(ebin[i])
    xbin_new.append(final)

    ec=mm.ElementContainer()

    ec.Add("x",xbin_new)
    ec.Add("y",ybin_new)
    ec.Add("e",ebin_new)

    ec.SetKeys("x","y","e")

    return ec

################################################################################################################

def AddZero(ec0,number):
    """
    @param ec0            (ElementContainer)
    @param number         (int)
    @retval ec            (ElementContainer)
    """

    xbin = ec0.PutX()
    ybin = ec0.PutY()
    ebin = ec0.PutE()

    initial= xbin[0]
    final= xbin[xbin.size()-1]
    delta = xbin[1]-xbin[0]

    xbin_new = []
    ybin_new = []
    ebin_new = []

#   zero = 1e-20
#    zero1 = ybin[0]
#    zero2=ybin[ybin.size()-1]

    zero1 = 0
    zero2 = 0


    for i in range(number):
        xbin_new.append(initial+(-number+i)*delta)
        ybin_new.append(zero1)
        ebin_new.append(zero1/100000)
        #ybin_new.append(zero1/(number+1)*(i+1))
        #ebin_new.append((zero1/(number+1)*(i+1))/1000)

    for i in range(ybin.size()):
        xbin_new.append(xbin[i])
        ybin_new.append(ybin[i])
        ebin_new.append(ebin[i])
    xbin_new.append(final)

    for i in  range(number):
        xbin_new.append(final+(i+1)*delta)
        ybin_new.append(zero2)
        ebin_new.append(zero2/100000)
        #ybin_new.append(-zero2/number*i+zero2)
        #ebin_new.append((-zero2/number*i+zero2)/1000)

    ec=mm.ElementContainer()

    ec.Add("x",xbin_new)
    ec.Add("y",ybin_new)
    ec.Add("e",ebin_new)

    ec.SetKeys("x","y","e")

    return ec

################################################################################################################

def AddSreiesSamaEC(ec0,number):
    """
    @param ec0            (ElementContainer)
    @param number         (int)
    @retval ec            (ElementContainer)
    """

    xbin = ec0.PutX()
    ybin = ec0.PutY()
    ebin = ec0.PutE()

    initial= xbin[0]
    final= xbin[xbin.size()-1]
    delta = xbin[1]-xbin[0]

    xbin_new = []
    ybin_new = []
    ebin_new = []

    for i in range(ybin.size()*number):
        xbin_new.append(initial+i*delta)
        ybin_new.append(ybin[i%int(ybin.size())])
        ebin_new.append(ebin[i%int(ybin.size())])
    xbin_new.append(initial+number*ybin.size()*delta)


    ec=mm.ElementContainer()

    ec.Add("x",xbin_new)
    ec.Add("y",ybin_new)
    ec.Add("e",ebin_new)

    ec.SetKeys("x","y","e")

    return ec


################################################################################################################

def ErrorValueMultiplyConstant(ec0,constant):
    """
    @param ec0            (ElementContainer)
    @param constant         (int)
    @retval ec            (ElementContainer)
    """

    xbin = ec0.PutX()
    ybin = ec0.PutY()
    ebin = ec0.PutE()

    ec=mm.ElementContainer()
    ec.Add("x",xbin)
    ec.Add("y",ybin)
    ec.Add("e",ebin*constant)

    ec.SetKeys("x","y","e")

    return ec

################################################################################################################
