#!/usr/bin/python3
# -*- coding: utf-8 -*-

from __future__ import print_function

import time
import os
import glob
import Manyo as mm
import Manyo.Utsusemi as mu
import Manyo.SAS as ms
import math

import utsusemi.ana.Reduction.BaseCommands as BaseCom
import Hist, Corr, QSpace
import utsusemi.SAS.ana.Reduction.QSpaceBaseCommands as QBC
import utsusemi.SAS.ana.Reduction.HistBaseCommands as HBC

# special reserved word for commands history
HISTORY = None

# reserved words for return value in this.
DAT = None
ecs = None
EC = None
ret = None
PyObj = None
Iq = None
Tr = None
ECA = None
DATList=None

SASBankDic={"SD":0,"SU":1,"SM16":2,"SM14":3,"SC":4,"MD":5,"MU":6,"ML":7,"MR":8,"HD":9,"HU":10,"HL":11,"BW":13,"RPMT":14}
#########################################
def GetNeunetHistSAS(runNo="197",HistParam="tof,0,40000,100",DetParam="psd",DetRange="All",TimeRange="All",FrameInfo="None",MaskInfo="NoFile",CaseInfo="None",BGInfo="TimeDep:None",TofShift="None",AnaMode="0",ParamFiles="-,-",SolAngCor=False):
    """
    Convert Event data of NEUNET to Histogram
    GetNeunetHist(runNo="197,198",
                  HistParam="tof,0,40000,100",
                  DetParam="psd",
                  DetRange="All",
                  TimeRange="All",
                  FrameInfo="None",
                  MaskInfo="NoFile"
                  CaseInfo="None",
                  BGInfo="TimeDep:None",
                  TofShift="None",
                  AnaMode="0",
                  ParamFiles="-,-",
                  SolAngCor=False
                  )

    -----------------------
    HistParam format
        TOF
           delta-TOF const :  tof,<min_tof>,<max_tof>,<delta_tof>
           d-TOF/TOF const : rtof,<min_tof>,<max_tof>,<racio>

        TOF with time forcusing
           delta-TOF const : tf-tof,<min_tof>,<max_tof>,<delta_tof>
           d-TOF/TOF const : tf-rtof,<min_tof>,<max_tof>,<racio>

        Lambda
           delta-lambda const        :  lambda,<min_lambda>,<max_lambda>,<delta_lambda>
           delta-lambda/lambda const : rlambda,<min_lambda>,<max_lambda>,<racio>

        Energy            : energy,<min_energy>,<max_energy>,<delta_energy>

        Momentum Transfer : q,<min_Q>,<max_Q>,<delta_Q>[,<ki_x>,<ki_y>,<ki_z>]

        Energy Transfer   : hw,<Ei>,<min_hw>,<max_hw>,<delta_hw>[,<t0_shift>]

        d-value
            delta-d-value                 : d,<min_d-val>,<max_d-val>,<delta_d-val>
            delta-d-value / d-value const : rd,<min_d-val>,<max_d-val>,<ratio>

    -----------------------
    DetParam format
        "<detType>[[<LLD_min>:<LLD_max>]][,..]" : detType in {"PSD","MON","PSD-PH","MON-PH", "UPSD", "TRIGNET"}
                                                "-PH" means that Pulse Height is calculated at the same time
    -----------------------
    DetRange format
        "All[:<number_of_pixels>]"                     : use all detectors
        "<startDetId>-<endDetId>[:<number_of_pixels>]" : use detectors from <startDetId> to <endDetId>
                                                         "X-Y:Z,A-B:C,D-E:F..." can be used for more settings
    -----------------------
    TofShift format
        "<ptnId>[,<p1>,<p2>,...]"
             ptnId = 0 : no use in this facade( only use if scattered data of tof origin shift vs lambda is given )
             ptnId = 1 : use shift = p1/(exp(-p2*(lambda-p3)) +p4) + p5*lambda
                         default p1=5.0, p2=8.464, p3=2.08765, p4=1.23477, p5=5.32657
    -----------------------

    @param runNo     (string or int) Run Number(s) 123 or "123,124"
    @param HistParam (string) "type,param,param,param,..." type must be in "tof" "rtof" "lambda" "rlambda" "hw" "energy" "q" "d" "rd"
    @param DetParam  (string) "DetType[,LLD,HLD]" DetType must be in "psd","n2mon","psd-ph" or "n2mon-ph"
    @param DetRange  (string) "All[:number_of_pixels]" or "startPsdId-endPsdId[:number_of_pixels]"
    @param TimeRange (string) "All" or "startTime,endTime" in [second] or "YYYY/MM/DD,hh:mm:ss,YYYY/MM/DD,hh:mm:ss"
    @param FrameInfo (string) "None" or "FrameNumber, boudaryTime"
    @param MaskInfo  (string) "<maskfile> [,<TOFmask>-<TOFmask>,..]" : if no use maskfile, set "NoFile"
    @param CaseInfo  (string) CaseInfo file must be in ${UTSUSEMI_USR_DIR}/ana/xml or ${UTSUSEMI_HOME_DIR}/ana/xml
    @param BGInfo    (string) "TimeDep:None" TimeDep:tof1-tof2
    @param TofShift  (string) "None" or "<ptnId> [,<p1>,<p2>,...]"
    @param AnaMode   (string or int) change analysis mode, which means to swich WiringInfo and DetectorInfo to be used for histogram.
    @param ParamFiles(string) "<path/to/WiringInfo>,<path/to/DetectorInfo>"
    @param SolAngCor (bool) True for doing SolidAngle Correction
    @retval DAT (ElementContainerMatrix)
    """

    HBC.CheckT0bUpdate(int(runNo))
    AnaMode = AnaMode+","+ParamFiles
    dat_list = BaseCom.GetNeunetHist(runNo,HistParam,DetParam,DetRange,TimeRange,FrameInfo,MaskInfo,CaseInfo,BGInfo,TofShift,AnaMode)
    if type(dat_list)!=list:
        dat_list=[dat_list]
    for dat in dat_list:
        ## Create Lambda Vector for each EC
        tt1 = ms.CreateLambVector( dat )
        tt1.Execute()
        del tt1

        ## Convertion from histogram to per_unit
        tt2 = ms.ConvertToPoint(dat)
        tt2.Execute()
        del tt2

        ## Solid angle correction
        if (SolAngCor):
            for i in range(dat.PutSize()):
                if (dat(i).PutHeaderPointer().PutString("TYPE")=="PSD"):
                    for j in range( dat(i).PutSize() ):
                        ec = dat(i,j)
                        sa = ec.PutHeaderPointer().PutDouble("PixelSolidAngle")
                        if sa==0.0:
                            raise UserWarning("Solid angle = 0 at %d,%d"%(i,j))
                        else:
                            ec.MulMySelf(1.0/sa)

            p_chk = mu.UtsusemiCheckDataProcess()
            p_chk.AddProcess( dat, "SolidAngleCorrection" )
            del p_chk

    return dat_list

def GetNeunetHistSASWitoutCheckPulseId(runNo="197",HistParam="tof,0,40000,100",DetParam="psd",DetRange="All",TimeRange="All",FrameInfo="None",MaskInfo="NoFile",CaseInfo="None",BGInfo="TimeDep:None",TofShift="None",AnaMode="0",ParamFiles="-,-",SolAngCor=False):
    """
    Convert Event data of NEUNET to Histogram
    GetNeunetHist(runNo="197,198",
                  HistParam="tof,0,40000,100",
                  DetParam="psd",
                  DetRange="All",
                  TimeRange="All",
                  FrameInfo="None",
                  MaskInfo="NoFile"
                  CaseInfo="None",
                  BGInfo="TimeDep:None",
                  TofShift="None",
                  AnaMode="0",
                  ParamFiles="-,-",
                  SolAngCor=False
                  )

    -----------------------
    HistParam format
        TOF
           delta-TOF const :  tof,<min_tof>,<max_tof>,<delta_tof>
           d-TOF/TOF const : rtof,<min_tof>,<max_tof>,<racio>

        TOF with time forcusing
           delta-TOF const : tf-tof,<min_tof>,<max_tof>,<delta_tof>
           d-TOF/TOF const : tf-rtof,<min_tof>,<max_tof>,<racio>

        Lambda
           delta-lambda const        :  lambda,<min_lambda>,<max_lambda>,<delta_lambda>
           delta-lambda/lambda const : rlambda,<min_lambda>,<max_lambda>,<racio>

        Energy            : energy,<min_energy>,<max_energy>,<delta_energy>

        Momentum Transfer : q,<min_Q>,<max_Q>,<delta_Q>[,<ki_x>,<ki_y>,<ki_z>]

        Energy Transfer   : hw,<Ei>,<min_hw>,<max_hw>,<delta_hw>[,<t0_shift>]

        d-value           : d,<min_d-val>,<max_d-val>,<delta_d-val>

    -----------------------
    DetParam format
        "<detType>[[<LLD_min>:<LLD_max>]][,..]" : detType in {"PSD","MON","PSD-PH","MON-PH", "UPSD", "TRIGNET"}
                                                "-PH" means that Pulse Height is calculated at the same time
    -----------------------
    DetRange format
        "All[:<number_of_pixels>]"                     : use all detectors
        "<startDetId>-<endDetId>[:<number_of_pixels>]" : use detectors from <startDetId> to <endDetId>
                                                         "X-Y:Z,A-B:C,D-E:F..." can be used for more settings
    -----------------------
    TofShift format
        "<ptnId>[,<p1>,<p2>,...]"
             ptnId = 0 : no use in this facade( only use if scattered data of tof origin shift vs lambda is given )
             ptnId = 1 : use shift = p1/(exp(-p2*(lambda-p3)) +p4) + p5*lambda
                         default p1=5.0, p2=8.464, p3=2.08765, p4=1.23477, p5=5.32657
    -----------------------

    @param runNo     (string or int) Run Number(s) 123 or "123,124"
    @param HistParam (string) "type,param,param,param,..." type must be in "tof" "rtof" "lambda" "rlambda" "hw"
    @param DetParam  (string) "DetType[,LLD,HLD]" DetType must be in "psd","n2mon","psd-ph" or "n2mon-ph"
    @param DetRange  (string) "All[:number_of_pixels]" or "startPsdId-endPsdId[:number_of_pixels]"
    @param TimeRange (string) "All" or "startTime,endTime" in [second] or "YYYY/MM/DD,hh:mm:ss,YYYY/MM/DD,hh:mm:ss"
    @param FrameInfo (string) "None" or "FrameNumber, boudaryTime"
    @param MaskInfo  (string) "<maskfile> [,<TOFmask>-<TOFmask>,..]" : if no use maskfile, set "NoFile"
    @param CaseInfo  (string) CaseInfo file must be in ${UTSUSEMI_USR_DIR}/ana/xml or ${UTSUSEMI_HOME_DIR}/ana/xml
    @param BGInfo    (string) "TimeDep:None" TimeDep:tof1-tof2
    @param TofShift  (string) "None" or "<ptnId> [,<p1>,<p2>,...]"
    @param AnaMode   (string or int) change analysis mode, which means to swich WiringInfo and DetectorInfo to be used for histogram.
    @param ParamFiles(string) "<path/to/WiringInfo>,<path/to/DetectorInfo>"
    @param SolAngCor (bool) True for doing SolidAngle Correction
    @retval DAT (ElementContainerMatrix)
    """

    HBC.CheckT0bUpdate(int(runNo))
    AnaMode = AnaMode+","+ParamFiles
    dat_list = BaseCom.GetNeunetHist(runNo,HistParam,DetParam,DetRange,TimeRange,FrameInfo,MaskInfo,CaseInfo,BGInfo,TofShift,AnaMode,Options="ISCHECKPULSEID:false")
    if type(dat_list)!=list:
        dat_list=[dat_list]
    for dat in dat_list:
        ## Create Lambda Vector for each EC
        tt1 = ms.CreateLambVector( dat )
        tt1.Execute()
        del tt1

        ## Convertion from histogram to per_unit
        tt2 = ms.ConvertToPoint(dat)
        tt2.Execute()
        del tt2

        ## Solid angle correction
        if (SolAngCor):
            for i in range(dat.PutSize()):
                if (dat(i).PutHeaderPointer().PutString("TYPE")=="PSD"):
                    for j in range( dat(i).PutSize() ):
                        ec = dat(i,j)
                        sa = ec.PutHeaderPointer().PutDouble("PixelSolidAngle")
                        if sa==0.0:
                            raise UserWarning("Solid angle = 0 at %d,%d"%(i,j))
                        else:
                            ec.MulMySelf(1.0/sa)

            p_chk = mu.UtsusemiCheckDataProcess()
            p_chk.AddProcess( dat, "SolidAngleCorrection" )
            del p_chk

    return dat_list

########################################
def DataReductionMulti( dat_list=DAT,Xrange="4.0 7.7 0.1 dL", kickerNorm=True, incVec="0.0 0.0 1.0", maskFile="mask_160316.xml" ):
    """

    @param dat_list(list)
    @param Xrange(string)
    @param kickerNorm(bool) True:do kicker normalization
    @retval None
    """
    run_st=dat_list[0].PutHeader().PutString("RUNNUMBER")
    runno=int(run_st)

    conv_type =""
    conv_params=""
    p_list=Xrange.split(" ")
    if len(p_list)!=4:
        raise UserWarning("param error")
    AxType=p_list[3].lower()
    if AxType=="dl":
        conv_type = "lambda"
        conv_params="%g %g %g"%(float(p_list[0]),float(p_list[1]),float(p_list[2]))
    elif AxType=="dl/l":
        conv_type = "lambda2"
        conv_params="%g %g %g"%(float(p_list[0]),float(p_list[1]),float(p_list[2]))
    elif AxType=="tof":
        conv_type = "tof"
        conv_params="%g %g %g"%(float(p_list[0]),float(p_list[1]),float(p_list[2]))
    else:
        raise UserWarning("param error about conv type")

    ECs = Hist.GetMonHistSAS(runNo=runno,MonNo=1,AxType=conv_type,Xrange=conv_params,MonIndex=0,TimeSlice="-1 -1",frameBoundary=0.0,CalibEffi=True)

    lambda_range = "%g %g"%(float(p_list[0]),float(p_list[1]))

    all_kickers = ECs.PutHeaderPointer().PutInt4("KICKERCOUNT")
    for DATs in dat_list:
        Corr.CorrectDetEffi(dat=DATs,filename="detectorEffiTBL.dat")
        Corr.I0LambdaCorrection(dat=DATs,I0Lamb=ECs)
        QSpace.ConvertQSpace(dat=DATs,InVec=incVec)
        DoMask(dat=DATs,filename=maskFile)
        if kickerNorm:
            kickers = DATs.PutHeaderPointer().PutInt4("KICKERCOUNT")
            DATs.MulMySelf( float(all_kickers)/float(kickers) )


########################################
def QzProjectionMulti(dat_list=DATList,QxRange="-0.06 0.06 0.001",QyRange="-0.06 0.06 0.001",QzRange="-0.5 0.0",LambdaRange="4.0 7.7 0.01"):
    """

    @param dat_list(list)
    @param Xrange(string)
    @retval list of ElementContainerArray
    """
    ret = []
    for dat in dat_list:
        eca = QSpace.QzProjection(dat,QxRange,QyRange,QzRange,LambdaRange)
        ret.append(eca)

    return ret

########################################
def SectorAverageByAnglesMulti( dat_list=DATList, index=0, Banks="SM16-SM14-SD-SU", Qrange="0.01 2.0 0.001 dQ/Q", LamRange="0.7 0.8", AzimAng="0.0 0.0", PolAng="0.0 0.0", QLamFile="None/QLambdaRange" ):
    """
    Convert Data to Q space EventData to produce histogram
    SectorAverageByAngles( dat=DAT, Banks="SM16-SM14-SD-SU", Qrange="0.01 2.0 0.001 dq/Q", LamRange="0.7 0.8", AzimAng="0.0 0.0", PolAng="0.0 0.0" )

    @param  dat_list (list of ElementContainerMatrix)
    @param  index    (int)    index number in dat_list to analyze
    @param  Banks    (string)  "SM16-SD-SU" means these banks are unified in one Iq, "SM SD SU" means separated Iq
    @param  Qrange   (string)  Q range and type of Qbin "Qmin Qmax deltaQ type" type must be dQ/Q or dQ
    @param  LamRange (string)  Lambda range "Lambda_min Lambda_max"
    @param  AzimAng  (string)  "-20.0 20 170 -170"
    @param  PolAng   (string)  "0 90 0 40"
    @param  QLamFile (string)  filename of Q-Lambda range info. If None, no use. (read QLambdaRange_SM.txt for SM bank)
    @retval Iq       (list of ElementContainer)
    """

    return QBC.SectorAverageByAngles( dat_list[index], Banks, Qrange, LamRange, AzimAng, PolAng, QLamFile )

########################################
def GetAzimuthProfile(dat=DAT, Qcenter=0.036, dQ=0.002, azim_bin=1.0, azim_range="0.0 360.0", lambda_range="0 0"):
    """
    Calculates Azimuth Profile from DataReduction

    @param dat          (ElementContainerMatrix)
    @param Qcenter      (float)
    @param dQ           (float)
    @param azim_bin     (float)
    @param azim_range   (string)
    @param lambda_range (string)
    @retval Iap
    """
    ec_list=GetAzimuthProfileMulti([dat], Qcenter, dQ, azim_bin, azim_range, lambda_range)
    return ec_list[0]

########################################
def GetAzimuthProfileMulti(dat_list=DATList, Qcenter=0.036, dQ=0.002, azim_bin=1.0, azim_range="0.0 360.0", lambda_range="0 0"):
    """
    Calculates Azimuth Profile from DataReduction

    @param dat_list     (list)
    @param Qcenter      (float)
    @param dQ           (float)
    @param azim_bin     (float)
    @param azim_range   (string)
    @param lambda_range (string)
    @retval IapList
    """
    azim_range_list = azim_range.split(" ")
    azim_min = float(azim_range_list[0])
    azim_max = float(azim_range_list[1])

    ec_list = []
    CAP = ms.CalcAzimuthProfile()
    CDP = mu.UtsusemiCheckDataProcess()
    if CAP.SetQRadius( Qcenter, dQ ):
        if CAP.SetAzimuthBinning( azim_bin, azim_min, azim_max ):
            if lambda_range!="0 0":
                l_list = lambda_range.split(" ")
                CAP.SetLambRange( float( l_list[0] ), float( l_list[1] ) )

            for i,dat in enumerate(dat_list):
                if not isinstance(dat, mm.ElementContainerMatrix):
                    raise UserWarning("Given data is not ElementContainerMatrix")
                if not CDP.CheckDataProcess(dat,"ConvertToQspace"):
                    raise UserWarning("Given data is invalid ( must do ConvertToQspace before )")
                CAP.SetTarget( dat )
                EC = CAP.GetProfileAverage()
                hh = EC.PutHeaderPointer()
                hh.Add( "AZIMUTHPROFILE","%03dfrm_Q%g_dQ%g"%(i+1,Qcenter,dQ) )
                ec_list.append( EC )
        else:
            raise UserWarning("Azimuth parameter is invalid.")
    else:
        raise UserWarning("Q or dQ parameter is invalid.")

    del CAP
    return ec_list

########################################
def Test( dat_list=DAT, Xrange="0.7 7.6 0.1 dL" ):
    """

    @param dat_list(list)
    @param Xrange(string)
    @retval list of ElementContainerArray
    """

    run_st=dat_list[0].PutHeader().PutString("RUNNUMBER")
    runno=int(run_st)

    conv_type =""
    conv_params=""
    p_list=Xrange.split(" ")
    if len(p_list)!=4:
        raise UserWarning("param error")
    AxType=p_list[3].lower()
    if AxType=="dl":
        conv_type = "lambda"
        conv_params="%g %g %g"%(float(p_list[0]),float(p_list[1]),float(p_list[2]))
    elif AxType=="dl/l":
        conv_type = "lambda2"
        conv_params="%g %g %g"%(float(p_list[0]),float(p_list[1]),float(p_list[2]))
    elif AxType=="tof":
        conv_type = "tof"
        conv_params="%g %g %g"%(float(p_list[0]),float(p_list[1]),float(p_list[2]))
    else:
        raise UserWarning("param error about conv type")

    ECs = Hist.GetMonHistSAS(runNo=runno,MonNo=1,AxType=conv_type,Xrange=conv_params,MonIndex=0,TimeSlice="-1 -1",frameBoundary=0.0,CalibEffi=True)

    lambda_range = "%g %g"%(float(p_list[0]),float(p_list[1]))
    ret = []
    for DATs in dat_list:
        Corr.CorrectDetEffi(dat=DATs,filename="detectorEffiTBL.dat")
        Corr.I0LambdaCorrection(dat=DATs,I0Lamb=ECs)
        QSpace.ConvertQSpace(dat=DATs,InVec="0.0 0.0 1.0")
        DoMask(dat=DATs,filename="mask_160316.xml")
        ECA = QSpace.QzProjection(dat=DATs,QxRange="-0.06 0.06 0.001",QyRange="-0.06 0.06 0.001",QzRange="-0.5 0.0",LambdaRange=lambda_range)
        ret.append( ECA )
    return ret

########################################
def PickDataByCaseId( dat=DAT, caseId=1 ):
    """
    """
    import Manyo
    if isinstance( dat, Manyo.ElementContainerMatrix() ):
        return dat
    for a_dat in dat:
        hh=a_dat.PutHeaderPointer()
        if caseId==hh.PutInt4("CASEID"):
            return a_dat

    raise UserWarning("This caseId is NOT included.")

########################################
def DoMask( dat=DAT, filename="mask.xml" ):
    """
    Does masking on Detectors, Pixels
    DoMask( dat, filename )

    @param dat       (ElementContainerMatrix)
    @param filename  (string) mask file must be in UTSUSEMI_USR_DIR/ana/xml
    @retval None
    """
    #fpath = os.path.join( mu.UtsusemiEnvGetInstDir(),"ana","xml",filename )
    fpath = mu.FindParamFilePath( filename, "" )
    if not os.path.exists( fpath ):
        raise UserWarning("Could not find file="+fpath)

    SMSK = mu.UtsusemiSetMask( dat, fpath )
    SMSK.Execute()
    del SMSK

########################################
def RemoveAllMask( dat=DAT ):
    """
    Does remove mask
    REmoveAllMask( dat, filename )

    @param dat       (ElementContainerMatrix)
    @param filename  (string) mask file must be in UTSUSEMI_USR_DIR/ana/xml
    @retval None
    """

    SMSK = mu.UtsusemiSetMask( dat )
    SMSK.UmaskAll()
    del SMSK

#########################################
def LoadDataFromDump(path="./",filename="Sample.dmp"):
    """
    Load ElementContainerMatrix from dump file made by ECMSerialize class
    @param  path     (String) path to data file
    @param  filename (String) data file name
    @retval DAT        ElementContainer/Array/Matrix
    """

    return BaseCom.LoadDataFromDump(path,filename)

#########################################
def SaveDataToDump(dat=DAT, path="./",filename="Sample.dmp"):
    """
    Serialize ElementContainerMatrix to dump file using ECMSerialize class.
    @param  dat      (ElementContainerMatrix)
    @param  path     (String) path to data file
    @param  filename (String) data file name
    @retval None
    """

    BaseCom.SaveDataToDump(dat,path,filename)

#########################################
def GetDataFromNeXus(path="./",filename="Sample.nx"):
    """
    Load ElementContainer/Array/Matrix from NeXus file.
    @param  path     (String)   path to data file
    @param  filename (String)  data file name
    @retval DAT      ElementContainer/Array/Matrix
    """
    return BaseCom.GetDataFromNeXus(path,filename)

#########################################
def SaveDataToNeXus(dat=DAT, name="Data",path="./",filename="Sample.nx"):
    """
    Save ElementContainer/Array/Matrix to NeXus file.
    @param  dat       (ElementContainerMatrix)
    @param  name      (String)   Title of saved data
    @param  path      (String)   path to data file
    @param  filename  (String)  data file name
    @retval None
    """
    BaseCom.SaveDataToNeXus(dat, name,path,filename)

##########################################
def getBeamCurrent(start_day="2009/5/30", start_time="10:00:00", end_day="2009/5/30", end_time="11:00:00" ):
    """
    get Beam current from web and calculate summation of the number of shots and protons
    @param start_day  the day of measurement start
    @param start_time the time of measurement start
    @param end_day    the day of measurement end
    @param end_time   the time of measurement end
    @retval ret       the number of protons [TelaProtons]
    """
    return BaseCom.getBeamCurrent(start_day, start_time, end_day, end_time)

##########################################
def NormByBeamCurrent(dat=DAT,factor=1000.0 ):
    """
    Normailze by Beam current from web and calculate summation of the number of shots and protons. Experimental info file, like SIK000XXX.xml file, must be placed in your ~/exp/xml directory.
    @param dat        (ElementContainer,-Array,-Matrix)
    @param factor     (double) normalize factor data*factor/beamCurrent
    """
    BaseCom.NormByBeamCurrent(dat, factor)



#########################################
def PrintObject(target=PyObj):
    """
    Print object for debug.
    @param target print to stdout
    @retval None
    """
    print(type(target))
    try:
        print(target)
    except:
        print("not printable")

#########################################
def MergeDataECM(dat1=DAT, coef1=1.0, dat2=DAT, coef2=0.0, dat3=DAT, coef3=0.0, dat4=DAT, coef4=0.0):
    """
    Merge Data (ElementContainerMatrix only)
    @param dat1  (ElementContainerMatrix)
    @param coef1 (float) coefficient for dat1
    @param dat2  (ElementContainerMatrix)
    @param coef2 (float) coefficient for dat2
    @param dat3  (ElementContainerMatrix)
    @param coef3 (float) coefficient for dat3
    @param dat4  (ElementContainerMatrix)
    @param coef4 (float) coefficient for dat4
    @retval DATmerg  (ElementContainerMatrix)
    """
    if not isinstance( dat1, mm.ElementContainerMatrix ):
        raise UserWarning("dat1 is not ElementContainerMatrix")
    if not isinstance( dat2, mm.ElementContainerMatrix ):
        raise UserWarning("dat2 is not ElementContainerMatrix")
    if not isinstance( dat3, mm.ElementContainerMatrix ):
        raise UserWarning("dat3 is not ElementContainerMatrix")
    if not isinstance( dat4, mm.ElementContainerMatrix ):
        raise UserWarning("dat4 is not ElementContainerMatrix")

    ret = dat1.Mul( coef1 )
    hh = ret.PutHeaderPointer()
    if (coef2!=0.0):
        for i in range( dat2.PutSize() ):
            ret.Add( dat2.PutPointer(i).Mul(coef2) )
        hht = dat2.PutHeaderPointer()
        if (hh.CheckKey("BANKIDLIST")==1) and (hht.CheckKey("BANKIDLIST")==1):
            bidvect=hh.PutInt4Vector("BANKIDLIST")
            bszvect=hh.PutInt4Vector("BANKSIZELIST")
            bnmvect=hh.PutStringVector("BANKNAMELIST")
            bidvectt=hht.PutInt4Vector("BANKIDLIST")
            bszvectt=hht.PutInt4Vector("BANKSIZELIST")
            bnmvectt=hht.PutStringVector("BANKNAMELIST")
            for i in range( bidvectt.size() ):
                bidvect.push_back( bidvectt[i] )
                bszvect.push_back( bszvectt[i] )
                bnmvect.push_back( bnmvectt[i] )
            hh.OverWrite("BANKIDLIST",bidvect)
            hh.OverWrite("BANKSIZELIST",bszvect)
            hh.OverWrite("BANKNAMELIST",bnmvect)

    if (coef3!=0.0):
        for i in range( dat3.PutSize() ):
            ret.Add( dat3.PutPointer(i).Mul(coef3) )
        hht = dat3.PutHeaderPointer()
        if (hh.CheckKey("BANKIDLIST")==1) and (hht.CheckKey("BANKIDLIST")==1):
            bidvect=hh.PutInt4Vector("BANKIDLIST")
            bszvect=hh.PutInt4Vector("BANKSIZELIST")
            bnmvect=hh.PutStringVector("BANKNAMELIST")
            bidvectt=hht.PutInt4Vector("BANKIDLIST")
            bszvectt=hht.PutInt4Vector("BANKSIZELIST")
            bnmvectt=hht.PutStringVector("BANKNAMELIST")
            for i in range( bidvectt.size() ):
                bidvect.push_back( bidvectt[i] )
                bszvect.push_back( bszvectt[i] )
                bnmvect.push_back( bnmvectt[i] )
            hh.OverWrite("BANKIDLIST",bidvect)
            hh.OverWrite("BANKSIZELIST",bszvect)
            hh.OverWrite("BANKNAMELIST",bnmvect)


    if (coef4!=0.0):
        for i in range( dat4.PutSize() ):
            ret.Add( dat4.PutPointer(i).Mul(coef4) )
        hht = dat4.PutHeaderPointer()
        if (hh.CheckKey("BANKIDLIST")==1) and (hht.CheckKey("BANKIDLIST")==1):
            bidvect=hh.PutInt4Vector("BANKIDLIST")
            bszvect=hh.PutInt4Vector("BANKSIZELIST")
            bnmvect=hh.PutStringVector("BANKNAMELIST")
            bidvectt=hht.PutInt4Vector("BANKIDLIST")
            bszvectt=hht.PutInt4Vector("BANKSIZELIST")
            bnmvectt=hht.PutStringVector("BANKNAMELIST")
            for i in range( bidvectt.size() ):
                bidvect.push_back( bidvectt[i] )
                bszvect.push_back( bszvectt[i] )
                bnmvect.push_back( bnmvectt[i] )
            hh.OverWrite("BANKIDLIST",bidvect)
            hh.OverWrite("BANKSIZELIST",bszvect)
            hh.OverWrite("BANKNAMELIST",bnmvect)

    return ret

########################################
def CopyData(first_run=10,last_run=-1,flag=0):
    """
    Copy EventData file from DAQ0 or DAQ1 into /data/XXX
    @param runno_from (int) First Run No of a measurement to be copied
    @param runno_to (int) Last Run No of a measurement to be copied
    @param flag  (int)  Flag for Copy(0) or Symbolic link(1) / default is Symbolic link or -1 for testing
    @retval None
    """
    BaseCom.CopyData( first_run, last_run, flag )

#########################################
def GetPH(dat=DAT, binSize=1):
    """
    Get Pulse Height Profile of PSD
    Each PSD pulse heignt profile is stored in header of ElementContaienrArray.
    @param  dat   (ElementContainerMatrix) Loaded ElementContainerMatrix.
    @param  binSize (UInt4)
    @retval ECS    ElementContainer or list of ElementContainers of pulse height profile
    """
    if type(dat)==list:
        import Manyo
        eca = Manyo.ElementContainerArray(dat[0].PutHeader())
        for a_dat in dat:
            eca_tmp = BaseCom.GetPH(a_dat,binSize)
            for i in range( eca_tmp.PutSize() ):
                eca.Add(eca_tmp.Put(i))
        return eca
    else:
        return BaseCom.GetPH(dat,binSize)


# Dictionary for entry the name of functions
_functions = {
              "GetNeunetHistSAS":GetNeunetHistSAS,
              "GetNeunetHistSASWitoutCheckPulseId":GetNeunetHistSASWitoutCheckPulseId,
              "DataReductionMulti":DataReductionMulti,
              "QzProjectionMulti":QzProjectionMulti,
              "GetAzimuthProfile":GetAzimuthProfile,
              "GetAzimuthProfileMulti":GetAzimuthProfileMulti,
              "SectorAverageByAnglesMulti":SectorAverageByAnglesMulti,
              "Test":Test,
              "NormByBeamCurrent":NormByBeamCurrent,
              "getBeamCurrent":getBeamCurrent,
              "SaveDataToDump":SaveDataToDump,
              "LoadDataFromDump":LoadDataFromDump,
              "SaveDataToNeXus":SaveDataToNeXus,
              "GetDataFromNeXus":GetDataFromNeXus,
              "PrintObject":PrintObject,
              "DoMask":DoMask,
              "RemoveAllMask":RemoveAllMask,
              "MergeDataECM":MergeDataECM,
              "CopyData":CopyData,
              "GetPH":GetPH
	      }

_functionsOrder = [
              "GetNeunetHistSAS",
              "DataReductionMulti",
              "QzProjectionMulti",
              "GetAzimuthProfileMulti",
              "GetAzimuthProfile",
              "SectorAverageByAnglesMulti",
              "Test",
              "NormByBeamCurrent",
              "getBeamCurrent",
              "SaveDataToDump",
              "LoadDataFromDump",
              "SaveDataToNeXus",
              "GetDataFromNeXus",
              "PrintObject",
              "DoMask",
              "RemoveAllMask",
              "MergeDataECM",
              "CopyData",
              "GetPH",
    ]
