#!/usr/bin/python

from math import *
#import numpy as np
import random
import Manyo as m
import PeakSearch as Adv
#import Adv

####    linear combination of gaussian    ####
#def dist(x, n, a, c, w):
def dist(x, param):
    sum=param[0]
    for i in range(len(param[1])):
        a, c, w = param[1][i]
        sum = sum + a*exp(-1.0*((x-c)/w)**2)
    return sum

####    sign function    ####
def sign(r):
    if r > 0.0:
        s = 1.0
    elif r == 0.0:
        s = 0.0
    else:
        s = -1.0
    return s

####    initialize an ElementContainer    ####
def initElementContainer(xmin, xmax, nDiv, param):

    bin = m.MakeDoubleVector(nDiv+1)
    delta = (xmax - xmin)/nDiv
    for i in range(nDiv+1):
        bin[i] = xmin + delta*i

    xc = m.MakeDoubleVector(nDiv)
    for i in range(nDiv):
        xc[i] = (bin[i] + bin[i+1])/2.0

    nPeak=1
    #a=m.MakeDoubleVector(nPeak)
    #c=m.MakeDoubleVector(nPeak)
    #w=m.MakeDoubleVector(nPeak)
    #a[0]=100000.0
    #c[0]=7.5
    #w[0]=2.5
    y = m.MakeDoubleVector(nDiv)
    e = m.MakeDoubleVector(nDiv)
    for i in range(nDiv):
        #p = dist(xc[i], nPeak, a, c, w)
        p = dist(xc[i], param)
        #q = sign(np.random.rand(1)-0.5)*(p/10.0)*sqrt(-1.0*log(np.random.rand(1)))
        q = sign(random.random()-0.5)*(p/10.0)*sqrt(-1.0*log(random.random()))
        y[i] = p + q
        e[i] = p/10.0

    ec = m.ElementContainer()
    ec.AddToHeader("run number", 1)
    ec.AddToHeader("level",      1)
    ec.AddToHeader("Inst.",      "manyo")
    ec.Add("TOF",       bin, "sec." )
    ec.Add("Intensity", y,   "count")
    ec.Add("Error",     e,   "count")
    ec.SetKeys("TOF", "Intensity", "Error")

    return ec

def outputElementContainer(ec):
    bin = ec.Put(ec.PutXKey())
    y   = ec.Put(ec.PutYKey())
    e   = ec.Put(ec.PutEKey())

    print str("No.").rjust(4), str("----------- bin -----------").rjust(27), str("xc").rjust(10), str("Intensity").rjust(23), str("error").rjust(23)
    for i in range(ec.PutSize(ec.PutYKey())):
         print str(i).rjust(4), "[", str(bin[i]).rjust(10), ",", str(bin[i+1]).rjust(10), ")", str((bin[i]+bin[i+1])/2.0).rjust(10), str(y[i]).rjust(23), str(e[i]).rjust(23)


####    plot    ####
def plot(src, dest, peakData):
    srcBin  = src.Put(src.PutXKey())
    srcY    = src.Put(src.PutYKey())
    destBin = dest.Put(dest.PutXKey())
    destY   = dest.Put(dest.PutYKey())

    count=0
    g=m.GnuplotInterface()
    g.e("set xrange[" + str(srcBin.front()) + ":" +str(srcBin.back())+"]")
    g.e("set yrange[0: 150000]")
    v=peakData.toVector()
    for i in range(peakData.size()):
        peak=peakData.getPeak(i)
        v=peak.toFullVector()
        h=v[0] # height
        c=v[1] # position
        l=v[3] # left  pos at HWHM
        u=v[4] # right pos at HWHM
        #print "peak id = ", i, p
        g.e("set arrow "+str(3*i+1)+" from "+str(c)+", 0 to "+str(c)+", 150000 nohead")
        g.e("set arrow "+str(3*i+2)+" from "+str(c)+","+str(h/2.0)+" to "+str(l)+","+str(h/2.0))
        g.e("set arrow "+str(3*i+3)+" from "+str(c)+","+str(h/2.0)+" to "+str(u)+","+str(h/2.0))
        g.e("set label "+str(4*i+1)+" '"+str(c)+"' at "+str(c)+",10000" )
        g.e("set label "+str(4*i+2)+" '"+str(h)+"' at "+str(c)+","+str(h)+" front" )
        g.e("set label "+str(4*i+3)+" '"+str(c-l)+"' at "+str((c+l)/2.0)+","+str(h/2.0)+" center front" )
        g.e("set label "+str(4*i+4)+" '"+str(u-c)+"' at "+str((c+u)/2.0)+","+str(h/2.0)+" center front" )

    while 1:
        g.e("plot '-' using 1:2 with lines linewidth 1 title '%d', '-' using 1:3 with lines linewidth 4" %count)
        for i in range(srcY.size()):
            #print str( (srcBin[i]+srcBin[i+1])/2.0 ) + " " + str( srcY[i] )+ " " + str( destY[i] )
            g.e( str( (srcBin[i]+srcBin[i+1])/2.0 ) + " " + str( srcY[i] )+ " " + str( destY[i] ) )
        g.e("e")
        c=raw_input("hit any key except return for next")
        if c != "":
            break

        

########        main routine        ########
#### initialise an element conatainer ####
xmin = 0.0
xmax = 15.0
nDiv = 1500

#      background    param for f0          param for f1
param1=[1000.0,     [[100000.0, 5.0, 1.5], [100000.0, 10.0, 1.5], [35000.0, 2.8, 1.0] ]]

src = initElementContainer(xmin, xmax, nDiv, param1)
outputElementContainer(src)

#### 
print Adv.BSPLINE.name
peakSearch = Adv.PeakSearch(src, Adv.BSPLINE)
print "PeakSearch(src, method)"
print "checkParama", peakSearch.checkParam()
paramSet = peakSearch.getParam()
paramSet.dump()

peakSearch.setParam(Adv.BSpline.NUMBER_OF_BREAK_POINTS, 16)

#smoothing.setDefaultParam()
print "checkParama", peakSearch.checkParam()
print peakSearch.getLowerBoundID()
print peakSearch.getUpperBoundID()
if peakSearch.checkParam() :
    peakSearch.execute()
    result = peakSearch.getResult()
    peakData = peakSearch.getPeaks()
    peakData.Dump()
    plot(src, result, peakData)
    #outputElementContainer(result)
