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

import time
import os
import Manyo as mm
import math

import utsusemi.ana.Reduction.BaseCommandsEla as BaseCom
import utsusemi.HPN.ana.Reduction.Commands as HPNCom

# special reserved word for commands history
HISTORY = None

# reserved words for return value in this.
DAT = None
ecs = None
EC = None
ret = None

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


def CopyData(runno=10):
    """
    Copy EventData file from DAQ0 or DAQ1 into /data/SIK
    @param runno (int) First Run No of a measurement to be copied
    @retval None
    """
    BaseCom.CopyData(runno)

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


def GetNeunetHist(runNo="197", HistParam="tf-tof,0,40000,10", DetParam="psd", DetRange="All", TimeRange="All", FrameInfo="None", MaskInfo="NoFile, 39999-40400", CaseInfo="None", BGInfo="TimeDep:None", TofShift="1", AnaMode="1"):
    """
    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"
                  )

    -----------------------
    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_BASE_DIR}/${UTSUSEMI_INST_CODE}/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.
    @retval DAT (ElementContainerMatrix)
    """
    if type(AnaMode) == int:
        AnaMode = str(AnaMode)
    if TofShift.upper().find("NONE") != 0 and AnaMode == "0":
        AnaMode = "1"

    return BaseCom.GetNeunetHist(runNo=runNo,
                                 HistParam=HistParam,
                                 DetParam=DetParam,
                                 DetRange=DetRange,
                                 TimeRange=TimeRange,
                                 FrameInfo=FrameInfo,
                                 MaskInfo=MaskInfo,
                                 CaseInfo=CaseInfo,
                                 BGInfo=BGInfo,
                                 TofShift=TofShift,
                                 AnaMode=AnaMode)

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


def GetHistDTconstNeunetPsd(runNo=0, isTimeFoc=True, tofRange="0.0 40000.0", binTOF=10.0, detRange="-1 -1", NumOfPixel=-1, timeRange="-1 -1", frameBoundary=0.0):
    """
    Load EventData produced Neunet PSD and convert to histograms with deltaT const.
    GetHistDTconstNeunetPsd( runNo=0,isTimeFoc=True,tofRange="0.0 40000.0",binTOF=10.0,
                             detRange="-1 -1",NumOfPixel=-1,
                             timeRange="-1 -1",frameBoundary=0.0 )

    @param runNo     (int) RunNumber
    @param isTimeFoc (bool) True: use Time Focusing
    @param tofRange  (string) startTOF,endTOF
    @param binTOF    (int)    bin width
    @param detRange  (string) first Detector, last Detector
    @param NumOfPixel (int) number of pixels on a detector
    @param timeRange (string) start time, end time [seconds]
    @param frameBoundary (int)
    @retval DAT
    """
    return BaseCom.GetHistDTconstNeunetPsd(runNo, isTimeFoc, tofRange, binTOF, detRange, NumOfPixel, timeRange, frameBoundary)

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


def GetHistToDTconstNeunetPsd(runNo=0, isTimeFoc=True, tofRange="0.0 40000.0", racio=0.01, detRange="-1 -1", NumOfPixel=-1, timeRange="-1 -1", frameBoundary=0.0):
    """
    Load EventData produced Neunet PSD and convert to histograms with T over deltaT const.
    GetHistToDTconstNeunetPsd( runNo=0,isTimeFoc=True,tofRange="0.0 40000.0",racio=0.01,
                               detRange="-1 -1",NumOfPixel=-1,
                               timeRange="-1 -1",frameBoundary=0.0 )

    @param runNo     (int) RunNumber
    @param isTimeFoc (bool) True: use Time Focusing
    @param tofRange  (string) startTOF,endTOF
    @param racio     (flaot)  dT/T const value
    @param detRange  (string) first Detector, last Detector
    @param NumOfPixel (int) number of pixels on a detector
    @param timeRange (string) start time, end time [seconds]
    @param frameBoundary (int)
    @retval DAT
    """
    return BaseCom.GetHistToDTconstNeunetPsd(runNo, isTimeFoc, tofRange, racio, detRange, NumOfPixel, timeRange, frameBoundary)

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


def GetHistDQconstNeunetPsd(runNo=0, Qrange="0.1 10.0", deltaQ=0.1, detRange="-1 -1", NumOfPixel=-1, timeRange="-1 -1", frameBoundary=0.0, inVect="0.0 0.0 1.0"):
    """
    Load EventData produced Neunet PSD and convert to histograms with deltaQ const.
    GetHistDQconstNeunetPsd( runNo=0,Qrange="0.1 10.0",deltaQ=0.1,
                             detRange="-1 -1",NumOfPixel=-1,
                             timeRange="-1 -1",frameBoundary=0.0, inVect="0.0 0.0 1.0" )

    @param runNo     (int) RunNumber
    @param QRange  (string) Q min , Q max
    @param deltaQ  (int)    delta Q
    @param detRange  (string) first Detector, last Detector
    @param NumOfPixel (int) number of pixels on a detector
    @param timeRange (string) start time, end time [seconds]
    @param frameBoundary (int)
    @param inVect  (string) incident beam vector "vx,vy,vz"
    @retval DAT
    """
    return BaseCom.GetHistDQconstNeunetPsd(runNo, Qrange, deltaQ, detRange, NumOfPixel, timeRange, frameBoundary, inVect)

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


def GetHistDTconstGatenetMon(runNo=0, tofRange="0.0 40000.0", binTOF=10.0, timeRange="-1 -1", frameBoundary=0.0):
    """
    Load EventData produced GateNET monitor and convert to histograms with deltaT const.
    GetHistDTconstGatenetMon( runNo=0,tofRange="0.0 40000.0",binTOF=10.0,
                              timeRange="-1 -1",frameBoundary=0.0 )

    @param runNo     (int) RunNumber
    @param tofRange  (string) startTOF,endTOF
    @param binTOF    (int)    bin width
    @param timeRange (string) start time, end time [seconds]
    @param frameBoundary (int)
    @retval DAT
    """
    return BaseCom.GetHistDTconstGatenetMon(runNo, tofRange, binTOF, "-1 -1", -1, timeRange, frameBoundary)

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


def GetHistToDTconstGatenetMon(runNo=0, tofRange="0.0 40000.0", racio=0.01, timeRange="-1 -1", frameBoundary=0.0):
    """
    Load EventData produced GateNET monitor and convert to histograms with T over deltaT const.
    GetHistToDTconstGatenetMon( runNo=0,tofRange="0.0 40000.0",racio=0.01,
                                timeRange="-1 -1",frameBoundary=0.0 )

    @param runNo     (int) RunNumber
    @param tofRange  (string) startTOF,endTOF
    @param racio     (flaot)  dT/T const
    @param detRange  (string) first Detector, last Detector
    @param NumOfPixel (int) number of pixels on a detector
    @param timeRange (string) start time, end time [seconds]
    @param frameBoundary (int)
    @retval DAT
    """
    return BaseCom.GetHistToDTconstGatenetMon(runNo, tofRange, racio, "-1 -1", 4, timeRange, frameBoundary)

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


def AverageAll(dat=DAT, maskfile="None"):
    """
    Calculates average intensity of ElementContainerMatrix

    @param dat [Def:DAT]  (ElementContainerMatrix)
    @param maskfile (string)
    @retval EC      (ElementContainer)
    """
    return BaseCom.AverageAll(dat, maskfile)

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


def SaveDataToNVASQ(dat=EC, path="./", filename="Sample.nx", L1=25000.0, px=1500.0, py=0.0, pz=0.0):
    """
    Save ElementContainer to NeXus file with nvaSp.py format.
    @param  dat [Def:EC]      (ElementContainer)
    @param  path     (String) path to data file
    @param  filename (String) data file name
    @param  L1 (Double)
    @param  px (Double) x position of a pixel
    @param  py (Double) y position of a pixel
    @param  pz (Double) z position of a pixel
    @retval None
    """
    BaseCom.SaveDataToNVASQ(dat, path, filename, L1, px, py, pz)

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


def AppendRawDataFiles(OutRunNo=990000, outDataPath="-", RunNo1=0, RunNo2=0, RunNo3=0, RunNo4=0, RunNo5=0, RunNo6=0):
    """
    append several EventData iles into one

    @param OutRunNo (int) output run number
    @param outDataPath (string) output data path (default is '-')
    @param RunNo1   (int) run number 1
    @param RunNo2   (int) run number 2
    @param RunNo3   (int) run number 3
    @param RunNo4   (int) run number 4
    @param RunNo5   (int) run number 5
    @param RunNo6   (int) run number 6
    @retval None
    """
    BaseCom.AppendRawDataFiles(
        OutRunNo, outDataPath, RunNo1, RunNo2, RunNo3, RunNo4, RunNo5, RunNo6)

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


def NormByBeamCurrent(dat=DAT, factor=10000000.0, offset_sec=0.0, isCT8n=True, isTagCorrect=True):
    """
    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 [Def:DAT]        (ElementContainer,-Array,-Matrix)
    @param factor     (double) normalize factor data*factor/beamCurrent
    @param offset_sec (double) offset time
    @param isCT8n (bool) use CT8Neutron (corrected by muon target effect) or not
    @param isTagCorrect (bool) use corrected proton current by shot tags
    @retval None
    """
    BaseCom.NormByBeamCurrent(dat, factor, offset_sec, isCT8n, isTagCorrect)

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


def DoMask(dat=DAT, filename="mask.txt"):
    """
    MASKED flag controled by file.
    @param dat [Def:DAT] (ElementContainerMatrix)
    @param filename (string) filename of mask information
    """
    BaseCom.DoMask(dat, filename)

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


def SolidAngleCorrection(dat=DAT):
    """
    Correction for solid angle of pixel
    Each intensity is devided by solid angle * default value
    @param dat [Def:DAT] (ElementContainerMatrix)
    """

    BaseCom.SolidAngleCorrection(dat)

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


def FlexCalc(dat=DAT, Intensity="I", Error="Err"):
    """
    Flexible calculation of S(Q,hw) on ElementContainerMatrix.
    @param dat [Def:DAT] (ElementContainerMatrix)
    @param Intensity (string) the expression of Intensity calculation
    @param Error     (string) the expression of Error calculation
    @retval dat (ElementContainerMatrix)
    """

    return BaseCom.FlexCalc(dat, Intensity, Error)

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


def NormByBeam(dat=DAT, start_day="2009/5/30", start_time="10:00:00", end_day="2009/5/30", end_time="11:00:00", factor=10000000.0, offset_sec=0.0, isCT8n=True, isTagCorrect=True):
    """
    Normailze by Beam current from web and calculate summation of the number of shots and protons
    @param dat [Def:DAT]        (ElementContainer,-Array,-Matrix)
    @param start_day  (string) the day of measurement start [yyyy/mm/dd]
    @param start_time (string) the time of measurement start [hh:mm:ss]
    @param end_day    (string) the day of measurement end [yyyy/mm/dd]
    @param end_time   (string) the time of measurement end [hh:mm:ss]
    @param factor     (float) normalize factor data*factor/beamCurrent
    @param offset_sec (float) offset second for Measurement Period to get protons
    @param isCT8n (bool) use CT8Neutron (corrected by muon target effect) or not
    @param isTagCorrect (bool) use corrected proton current by shot tags
    @retval None
    """
    try:
        BaseCom.NormByBeam(dat, start_day, start_time, end_day,
                           end_time, factor, offset_sec, isCT8n, isTagCorrect)
    except:
        msg = "Normalize by Proton Current is disable."
        raise UserWarning(msg)

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


def SumOfTOF(Target=DAT, PSD=1, tof_min=0, tof_max=40000):
    """
    Put summation of intensity along TOF
    @param  Target [Def:DAT]     (ElementContainerMatrix)
    @param  PSD        (int) PSD for summation
    @param tof_min     (int) Minimum point of TOF for summation
    @param tof_max     (int) Maximum point of TOF for summation
    @retval EC         (ElementContainer)
    """
    return BaseCom.SumOfTOF(Target, PSD, tof_min, tof_max)


#########################################
def SumOfPixel(Target=DAT, PSD_min=1, PSD_max=1, Pixel_min=1, Pixel_max=1):
    """
    Put summation of intensity along Pixel
    @param Target [Def:DAT]     (ElementContainerMatrix)
    @param PSD_min    (int) lower limit of PSD range
    @param PSD_max    (int) upper limit of PSD range
    @param Pixel_min  (int) lower limit of Pixel range
    @param Pixel_max  (int) upper limit of Pixel range
    @retval EC        (ElementContainer)
    """
    return BaseCom.SumOfPixel(Target, PSD_min, PSD_max, Pixel_min, Pixel_max)


#########################################
def PickUpRegion(Target=DAT, PSD_min=1, PSD_max=1, Pixel_min=1, Pixel_max=1):
    """
    Put summation of intensity along Pixel
    @param Target [Def:DAT]     (ElementContainerMatrix)
    @param PSD_min    (int) lower limit of PSD range
    @param PSD_max    (int) upper limit of PSD range
    @param Pixel_min  (int) lower limit of Pixel range
    @param Pixel_max  (int) upper limit of Pixel range
    @retval ECM       (ElementContainerMatrix)
    """
    return BaseCom.PickUpRegion(Target, PSD_min, PSD_max, Pixel_min, Pixel_max)


#########################################
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 [Def: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 [Def: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", offset_sec=0, isCT8n=False):
    """
    get Beam current from web and calculate summation of the number of shots and protons
    @param start_day  (String) the day of measurement start
    @param start_time (String) the time of measurement start
    @param end_day    (String) the day of measurement end
    @param end_time   (String) the time of measurement end
    @param offset_sec the offset value of the time [seconds]
    @param isCT8n (bool) use CT8Neutron ( corrected by muon target effect ) or not
    @retval ret       the number of protons [TelaProtons]
    """
    return BaseCom.getBeamCurrent(start_day, start_time, end_day, end_time, offset_sec, isCT8n)

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


def OutPutAllPixelToTxt(dat=DAT, filepath=""):
    """
    Output all pixels to text.

    @param dat [Def:DAT] (ElementContainerMatrix)
    @param filepath (string)
    @retval None
    """
    BaseCom.OutPutAllPixelToTxt(dat, filepath)

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


def SaveDataToText(ec=EC, path="./", filename="sample.txt"):
    """
    Save ElementContainer to text file.
    @param  dat      (ElementContainerMatrix)
    @param  path     (String) path to data file
    @param  filename (String) text file name
    @retval None
    """
    HPNCom.SaveDataToText(ec, path, filename)

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


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 [Def:DAT] (ElementContainerMatrix) Loaded ElementContainerMatrix.
    @param  binSize (UInt4)
    @retval ECS    ElementContainer or list of ElementContainers of pulse height profile
    """
    return BaseCom.GetPH(dat, binSize)


#########################################
# Dictionary for entry the name of functions
_functions = {
    "GetNeunetHist": GetNeunetHist,
    # 151023 mod by AS
    #              "GetHistDTconstNeunetPsd":GetHistDTconstNeunetPsd,
    #              "GetHistToDTconstNeunetPsd":GetHistToDTconstNeunetPsd,
    #              "GetHistDQconstNeunetPsd":GetHistDQconstNeunetPsd,
    #              "GetHistDTconstGatenetMon":GetHistDTconstGatenetMon,
    #              "GetHistToDTconstGatenetMon":GetHistToDTconstGatenetMon,
    "AverageAll": AverageAll,
    "SaveDataToNVASQ": SaveDataToNVASQ,
    "NormByBeamCurrent": NormByBeamCurrent,
    "DoMask": DoMask,
    "AppendRawDataFiles": AppendRawDataFiles,
    "SolidAngleCorrection": SolidAngleCorrection,
    "FlexCalc": FlexCalc,
    "SumOfTOF": SumOfTOF,
    "SumOfPixel": SumOfPixel,
    "PickUpRegion": PickUpRegion,
    "GetPH": GetPH,
    "NormByBeam": NormByBeam,
    "getBeamCurrent": getBeamCurrent,
    "SaveDataToDump": SaveDataToDump,
    "LoadDataFromDump": LoadDataFromDump,
    "SaveDataToNeXus": SaveDataToNeXus,
    "GetDataFromNeXus": GetDataFromNeXus,
    "OutPutAllPixelToTxt": OutPutAllPixelToTxt,
    "SaveDataToText": SaveDataToText
}

_functionsOrder = [
    # 151023 mod by AS
    #    "GetHistDTconstNeunetPsd",
    #    "GetHistToDTconstNeunetPsd",
    #    "GetHistDQconstNeunetPsd",
    #    "GetHistDTconstGatenetMon",
    #    "GetHistToDTconstGatenetMon",
    "GetNeunetHist",
    "AverageAll",
    "SaveDataToText",
    "SaveDataToNVASQ",
    "SaveDataToNeXus",
    "GetDataFromNeXus",
    "NormByBeamCurrent",
    "NormByBeam",
    "getBeamCurrent",
    "PickUpRegion",
    "DoMask",
    "AppendRawDataFiles",
    "SolidAngleCorrection",
    "FlexCalc",
    "SumOfTOF",
    "SumOfPixel",
    "GetPH",
    "SaveDataToDump",
    "LoadDataFromDump",
    "OutPutAllPixelToTxt",
]
