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

from __future__ import print_function
import time
import os
import Manyo
import Manyo.MLF as mm
import Manyo.Utsusemi as mu
import utsusemi.ana.Reduction.NexusChoppers as NX
import utsusemi.ana.Reduction.FlexCalc as FC
import utsusemi.ana.Reduction.ECMSerialize as ECMS
from utsusemi.ana.Reduction import PutSum
import utsusemi.ana.Reduction.getNeutronSourceInfo as NSI
import utsusemi.ana.Reduction.AppendRawDataFiles as ADF
import utsusemi.vis.UtilQt as UtilQt
import math
import glob

# from utsusemi.ana.Reduction.DefaultInstParams import *   #[inamura 120806]

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


def CopyData(first_run=10, last_run=-1, flag=0, target="-"):
    """
    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
    @param target (string) ex. "/data/AMR02" "/data/ifs_SIK"
    @retval None
    """
    if target == "-":
        target = ""
    print("------------ target={}".format(target))
    import utsusemi.ana.Reduction.CopyEventData as CP
    if last_run == -1:
        last_run = first_run
    ret = CP.CopyEventData(first_run, last_run, flag, target)
    if ret[0] == -1:
        raise UserWarning("No data in DAQ CPU")
    if ret[0] == -2:
        raise UserWarning("False to make directory")
    if ret[0] == -3:
        raise UserWarning("False to copy data file / make symbolic link")
    if ret[0] == -4:
        raise UserWarning(
            "Not agreement between origin data files and copied files")

    if "UTSUSEMI_INST_CODE" in os.environ:
        for runno in range(first_run, (last_run + 1)):
            ss = os.environ["UTSUSEMI_INST_CODE"]
            ss = ss + "%06d" % runno
            com = "rm ~/ana/tmp/" + ss + "_*.t0b"
            print(com)
            os.system(com)

    # copy Iroha2 params and logs
    CopyIroha2Params(first_run, last_run, flag, target)

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


def CopyIroha2Params(first_run=10, last_run=-1, flag=0, target=""):
    """
    Copy Iroha2 Params and Log file from Iroha2 server into /data/Iroha2
    @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
    """
    # [inamura 151105]-->
    import glob
    print("IROHA2 Log and params copy start ...")
    if last_run == -1:
        last_run = first_run
    if "UTSUSEMI_DATA_DIR" in os.environ:
        iroha2_dir = os.path.join(os.environ["UTSUSEMI_DATA_DIR"], "Iroha2")
        if os.path.exists(iroha2_dir):
            for runno in range(first_run, (last_run + 1)):
                run_dir = os.path.join(
                    iroha2_dir, "%3s%06d_*" % (os.environ["UTSUSEMI_INST_CODE"], runno))
                iroha2_dir_list = glob.glob(run_dir)
                if len(iroha2_dir_list) != 0:
                    iroha2_dir_list.sort()
                    iroha2_dirpath = iroha2_dir_list[-1]
                    iroha2_dirname = os.path.basename(iroha2_dirpath)
                    if target == "":
                        target_path = os.path.join(
                            os.environ["UTSUSEMI_DATA_DIR"], os.environ["UTSUSEMI_INST_CODE"], iroha2_dirname)
                    else:
                        target_path = os.path.join(target, iroha2_dirname)
                    print("target_path=" + target_path)
                    if os.path.exists(target_path):
                        com = "cp -r %s/* %s" % (iroha2_dirpath, target_path)
                    else:
                        com = "mkdir -p %s; cp -r %s/* %s" % (
                            target_path, iroha2_dirpath, target_path)
                    print(com)
                    os.system(com)
                else:
                    msg = "There is no folder in %d" % (run_dir)
                    print(msg)
                    UserWarning(msg)
        else:
            msg = "There is no folder named as %s" % (iroha2_dir)
            print(msg)
            UserWarning(msg)
    else:
        msg = "Your environment is no Utsusemi"
        print(msg)
        UserWarning(msg)

    # <--[inamura 151105]

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


def GetNeunetHist(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,-,-", Options="-"):
    """
    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,-,-",
                  Options="-"
                  )

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

        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>,<ratio>

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

        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
    -----------------------
    Options format
        "<KEY>:<VALUE>[,<KEY>:<VALUE>,..]"
             KEY                VALUE example       descriptions
             "ISCHECKPULSEID"   "True"    [bool]    Set flag to check T0 between neutron data and trignet data.
             "ADDTOFBIN"        "True"    [bool]    Set flag to add TOF binning vector to each ElementContainer
             "L1"               "18030.0" [mm]      Change L1
             "SX"               "5.0"     [mm]      Set x axis of sample position
             "SY"               "-1.0"    [mm]      Set y axis of sample position
             "SZ"               "2.0"     [mm]      Set z axis of sample position

    @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", "<FrameNumber>, <boudaryTime>" or "<type>,<boundaryValue>" where type="tof", "Ei", "Energy", "Lambda"
    @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>, where "TimeDep" can be replaced with "TOF" or "TimeIndep"
    @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 Options   (string)
    @retval DAT (ElementContainerMatrix)
    """
    UGH = mu.UtsusemiGetNeunetHistogram()

    # if (not UGH.GetStatus()):
    #    raise UserWarning, " Some Environment Variables are Wrong."

    # Set Run Number
    if type(runNo) == int:
        runNo = str(runNo)
    if type(AnaMode) == int:
        AnaMode = str(AnaMode)

    ParamFiles = "-,-"
    ana_mode_list = AnaMode.split(",")
    if len(ana_mode_list) == 1:
        pass
    elif len(ana_mode_list) == 3:
        AnaMode = ana_mode_list[0]
        ParamFiles = "%s,%s" % (
            ana_mode_list[1].strip(), ana_mode_list[2].strip())
    else:
        del UGH
        raise UserWarning("AnaMode is invalid.")

    isOK = False
    if ParamFiles == "-,-":
        isOK = UGH.SetRunNo(runNo, AnaMode)
    else:
        pfiles = ParamFiles.split(",")
        if len(pfiles) < 2 or len(pfiles) > 2:
            del UGH
            raise UserWarning("ParamFiles are invalid.")
        isOK = UGH.SetRunNo(
            runNo, pfiles[0].strip(), pfiles[1].strip(), AnaMode)

    if not isOK:
        # msgs = UGH.GetErrorMessages()
        msgs = mu.UtsusemiPutErrorMessages()
        for i in range(msgs.size()):
            mu.UtsusemiError(msgs[i])
        del UGH
        raise UserWarning(" RunNo param is invalid.")

    # Set Histogram Parameters
    isOK = UGH.SetConversionParameter(HistParam)
    if not isOK:
        del UGH
        raise UserWarning(" HistParam is invalid.")

    # Set Detector Parameters
    isOK = UGH.SetDetParam(DetParam)
    if not isOK:
        del UGH
        raise UserWarning(" DetParam is invalid.")

    # Set detector range Parameters
    isOK = UGH.SetDetRange(DetRange)
    if not isOK:
        del UGH
        raise UserWarning(" DetRange param is invalid.")

    # Set time range Parameters
    isOK = UGH.SetTimeRange(TimeRange)
    if not isOK:
        del UGH
        raise UserWarning(" TimeRange param is invalid.")

    # Set frame info Parameters
    isOK = UGH.SetFrameInfo(FrameInfo)
    if not isOK:
        del UGH
        raise UserWarning(" FrameInfo param is invalid.")

    # Set Mask Info Parameters
    isOK = UGH.SetMaskInfo(MaskInfo)
    if not isOK:
        del UGH
        raise UserWarning(" MaskInfo param is invalid.")

    # Set CaseInfo Parameters
    isOK = UGH.SetCaseInfo(CaseInfo)
    if not isOK:
        del UGH
        raise UserWarning(" CaseInfo param is invalid.")

    # Set BackGround Info Parameters
    TINDEP_KEY = ""
    if BGInfo.upper().find("TIMEDEP:") >= 0:
        TINDEP_KEY = "TIMEDEP:"
    elif BGInfo.upper().find("TIMEINDEP:") >= 0:
        TINDEP_KEY = "TIMEINDEP:"
    elif BGInfo.upper().find("TOF:") >= 0:
        TINDEP_KEY = "TOF:"
    else:
        pass
    # if BGInfo.upper().find("TIMEDEP:") < 0:
    #    pass
    # else:
    #    ind = BGInfo.upper().find("TIMEDEP:")
    if TINDEP_KEY != "":
        ind = BGInfo.upper().find(TINDEP_KEY)
        ind1 = BGInfo.upper().find("(")
        ind2 = BGInfo.upper().find(")")
        # BGInfo = "TIMEDEP:xxx-yyy"
        if ind1 < 0:
            param = BGInfo[(ind + len(TINDEP_KEY)):]
            if not UGH.SetTimeDependBackGroundInfo(param):
                del UGH
                raise UserWarning(
                    " BGInfo >>> TimeInDep parameter is invalid.(" + param + ")")
        # BGInfo = "TIMEDEP:xxx-yyy(<filepath>)" Save the dark BG data as a file.
        elif ind1 >= 0 and ind2 > ind1:
            param = BGInfo[(ind + len(TINDEP_KEY)):ind1]
            filepath = BGInfo[(ind1 + 1):ind2]
            if param != "":
                if filepath != "" and filepath.upper() != "NONE":
                    UGH.SetSaveFileOfTimeDependBackGround(filepath)
                if not UGH.SetTimeDependBackGroundInfo(param):
                    del UGH
                    raise UserWarning(
                        " BGInfo >>> TimeInDep parameter is invalid.(" + param + ")")
            else:
                if filepath != "" and filepath.upper() != "NONE":
                    if not UGH.SetFileOfTimeDependBackGround(filepath):
                        del UGH
                        raise UserWarning(
                            " BGInfo >>> TimeInDep parameter is invalid.(" + param + ")")
        else:
            del UGH
            raise UserWarning(
                " BGInfo >>> TimeDep parameter is invalid.(" + param + ")")

    # Set TofShift Parameters
    if TofShift.upper().find("NONE") == 0:
        pass
    else:
        isOK = UGH.SetTofShiftInfo(TofShift)
        if not isOK:
            del UGH
            raise UserWarning(" TofShift param is invalid.")

    # Other Options
    options_list = Options.split(",")
    sx = 0.0
    sy = 0.0
    sz = 0.0
    for a_option in options_list:
        tmp = a_option.strip().upper()
        if tmp.find("ISCHECKPULSEID:") == 0:
            if tmp[15:] == "FALSE":
                UGH.SetFlagOfPulseIdCheck(False)
            elif tmp[15:] == "TRUE":
                UGH.SetFlagOfPulseIdCheck(True)
        elif tmp.find("ADDTOFBIN:") == 0:
            if tmp[10:] == "TRUE":
                UGH.SetFlagToAddTofBin(True)
        elif tmp.find("L1:") == 0:
            UGH.SetL1(float(tmp[3:]))  # [mm]
        elif tmp.find("SX:") == 0:
            sx = float(tmp[3:])
        elif tmp.find("SY:") == 0:
            sy = float(tmp[3:])
        elif tmp.find("SZ:") == 0:
            sz = float(tmp[3:])

    if (sx != 0.0) or (sy != 0.0) or (sz != 0.0):
        mu.UtsusemiMessage("Do SetSamplePosition ")
        UGH.SetSamplePosition(sx, sy, sz)

    # Set Data Folder from environment variable
    dataPath = "/data"
    if "UTSUSEMI_DATA_DIR" in os.environ:
        dataPath = os.environ["UTSUSEMI_DATA_DIR"]

    dat_list = []

    if UGH.LoadEventDataFiles(dataPath, ""):
        v_cases = UGH.PutListOfCases()
        caselist = []
        if v_cases.size() == 0:
            caselist = [1]
        else:
            for i in range(v_cases.size()):
                caselist.append(v_cases[i])
        for caseId in caselist:
            dat = Manyo.ElementContainerMatrix()
            if UGH.SetElementContainerMatrix(dat, caseId):
                dat_list.append(dat)
            else:
                del UGH
                del dat
                msgs = mu.UtsusemiPutErrorMessages()
                last_message = ""
                if not msgs.empty():
                    last_message = str(msgs.back())
                last_message += "\nBaseCommands::GetNeunetHist : failed to make histograms (runNo=%s)" % (
                    runNo)
                raise UserWarning(last_message)
    else:
        del UGH
        msgs = mu.UtsusemiPutErrorMessages()
        last_message = ""
        if not msgs.empty():
            last_message = str(msgs.back())
        last_message += "\nBaseCommands::GetNeunetHist : failed to read event data (runNo=%s)" % (
            runNo)
        raise UserWarning(last_message)
    """
    if CaseInfo.upper()=="NONE":
        dat = Manyo.ElementContainerMatrix()
        if UGH.SetElementContainerMatrix( dat, dataPath ):
            dat_list.append(dat)
        else:
            del UGH
            del dat
            msgs = mu.UtsusemiPutErrorMessages()
            raise UserWarning(str(msgs.back()))
    else:
        if UGH.LoadEventDataFiles( dataPath, "" ):
            v_cases = UGH.PutListOfCases()
            caselist = []
            for i in range(v_cases.size()):
                caselist.append( v_cases[i] )
            for caseId in caselist:
                dat = Manyo.ElementContainerMatrix()
                if UGH.SetElementContainerMatrix( dat, caseId ):
                    dat_list.append(dat)
                else:
                    del UGH
                    del dat
                    msgs = mu.UtsusemiPutErrorMessages()
                    raise UserWarning(str(msgs.back()))
        else:
            del UGH
            msgs = mu.UtsusemiPutErrorMessages()
            raise UserWarning(str(msgs.back()))
    """

    # msgs = mu.UtsusemiPutErrorMessages()
    # for i in range(msgs.size()):
    #    print("BaseCommands : ERROR :%s"%msgs[i])

    del UGH

    if len(dat_list) == 1:
        return dat_list[0]
    else:
        return dat_list

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


def SplitStringParameters(conts="", numOfParams=2, cont_type="float"):
    if not (cont_type in ["float", "int"]):
        return -1

    cont_list = conts.split()
    if len(cont_list) != numOfParams:
        cont_list = conts.split(',')
        if len(cont_list) != numOfParams:
            cont_list = conts.split(':')
            if len(cont_list) != numOfParams:
                return -2

    ret = []
    for ii in cont_list:
        if cont_type == "float":
            ret.append(float(ii))
        else:
            ret.append(int(ii))

    return ret

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


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

    @param dat      (ElementContainerMatrix)
    @param maskfile (string)
    @retval ec      (ElementContainer)
    """

    if not isinstance(dat, Manyo.ElementContainerMatrix):
        raise UserWarning("dat must be ElementContainerMatrix")
    if maskfile != "None":
        DoMask(dat, maskfile)

    AVC = mm.AverageElementContainerMatrix(dat)
    ec = Manyo.ElementContainer()
    if AVC.GetAverage(ec):
        pass
    else:
        raise UserWarning("AverageAll >> Failed GetAverage.")
    del AVC
    return ec

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


def GetPH(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 not isinstance(dat, Manyo.ElementContainerMatrix):
        raise UserWarning("This Data must be ElementContainerMatrix")

    if dat(0).PutHeader().CheckKey("PulseHeight") == 0:
        raise UserWarning("This Data has no Pulse Height info")

    ev_ph = mu.UtsusemiEventDataConverterNeunetWithPH()
    ret_eca = Manyo.ElementContainerArray()
    if ev_ph.PutPulseHeightAll(dat, ret_eca, binSize):
        return ret_eca
    else:
        raise UserWarning("Failed PutPulseHeightAll")

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


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
    """
    nx = NX.NexusChopper()
    DAT = nx.ReadECM(path, filename)
    return DAT

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


def SaveDataToManyoBinary(dat, path="./", filename="Sample.mdb"):
    """
    Save ElementContainerMatrix to manyo binary data file
    This is the binary format for storing ElementContainers using HDF5
    @param  dat      (ElementContainer, -Array, -Matrix)
    @param  path     (String) path to data file
    @param  filename (String) data file name
    @retval None
    """
    if path == "":
        out_filepath = os.path.join('./', filename)
    else:
        out_filepath = os.path.join(path, filename)

    mdb = Manyo.ManyoDataIO()
    mdb.Write(dat, out_filepath, mu.UtsusemiEnvGetInstCode())
    del mdb

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


def LoadDataFromManyoBinary(path="./", filename="Sample.mdb"):
    """
    Load ElementContainerMatrix from manyo binary data file
    which is the binary format for storing ElementContainers usign HDF5
    @param  path     (String) path to data file
    @param  filename (String) data file name
    @retval  data (ElementContaienr, -Array, -Matrix)
    """
    if path == "":
        filepath = os.path.join("./", filename)
    else:
        filepath = os.path.join(path, filename)

    if not os.path.exists(filepath):
        messages = "Not Found : %s" % (filepath)
        raise UserWarning(messages)

    mdb = Manyo.ManyoDataIO()
    DataType = mdb.PutDataType(str(filepath))
    ret_dat = None
    if DataType == "ElementContainerMatrix":
        ret_dat = mdb.ReadElementContainerMatrix(str(filepath))
    elif DataType == "ElementContainerArray":
        ret_dat = mdb.ReadElementContainerArray(str(filepath))
    elif DataType == "ElementContainer":
        ret_dat = mdb.ReadElementContainer(str(filepath))
    else:
        raise UtilQt.PlotException('Common', 'C015', (filepath,))
    del mdb

    return ret_dat

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


def SaveDataToNeXus(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
    """
    nx = NX.NexusChopper()
    nx.WriteECM(dat, name, path, filename)


#########################################
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
    """
    ecms = ECMS.ECMSerialize()
    filepath = os.path.join(path, filename)

    if os.path.exists(filepath):
        DAT = ecms.Decode(filepath)
        del ecms
        return DAT
    else:
        err_message = "LoadDataFromDump >>> Could not find such file." + filepath
        del ecms
        raise UserWarning(err_message)
        return None


#########################################
def SaveDataToDump(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
    """
    ecms = ECMS.ECMSerialize()
    filepath = os.path.join(path, filename)
    if os.path.exists(filepath):
        mu.UtsusemiWarning(
            "SaveDataFromDump >>> This file is already existed." + filepath)
        os.system("mv " + filepath + " " + filepath + ".pre")
        mu.UtsusemiWarning(
            "SaveDataFromDump >>> Original data was moved to." + (filepath + ".pre"))

    ecms.Encode(dat, filepath)
    del ecms
    return


#########################################
def SumOfTOF(Target, PSD=1, tof_min=0, tof_max=40000):
    """
    Put summation of intensity along TOF
    @param  Target (ElementContainerMatrix)
    @param  PSD    (int) PSD-ID 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
    """
    SIH = Manyo.SearchInHeader(Target)
    SIH.SearchArray("PSDID", PSD)
    psds = SIH.PutResultIndex()
    del SIH  # [inamura 120630]
    if psds.size() == 0:
        EC = None
        mu.UtsusemiMessage("can not find such PSDs as {}".format(PSD))
    else:
        if psds.size() > 1:
            mu.UtsusemiMessage(
                "SumOfTOF >> There are several ElementContainer with same PSD-ID.")
            mu.UtsusemiMessage("SumOfTOF >> Use first one.")
        psd = psds[0]
        ps = PutSum.PutSum(Target)
        EC = ps.PutSumEC(psd, tof_min, tof_max)

    # Add Header Info
    SS = "SumOfTOF(Target, PSD=%d, tof_min=%d, tof_max=%d)" % (
        PSD, tof_min, tof_max)
    hh = EC.PutHeaderPointer()
    if hh.CheckKey("DATAPROCESSED") == 0:
        process_vect = Manyo.StringVector()
        process_vect.append(SS)
        hh.Add("DATAPROCESSED", process_vect)
    else:
        process_vect = hh.PutStringVector("DATAPROCESSED")
        process_vect.append(SS)
        hh.OverWrite("DATAPROCESSED", process_vect)

    return EC

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


def SumOfPixelOld(Target, PSD_min=1, PSD_max=1, Pixel_min=1, Pixel_max=1):
    """
    Put summation of intensity along Pixel
    @param Target    (ElementContainerMatrix)
    @param PSD_min   (int) lower limit of PSD-ID range
    @param PSD_max   (int) upper limit of PSD-ID range
    @param Pixel_min (int) lower limit of Pixel range
    @param Pixel_max (int) upper limit of Pixel range
    @retval EC
    """
    def sumECA(eca_in, pmin, pmax):
        ec_out = eca_in.Put(pmin)
        if pmin == pmax:
            return ec_out
        for pixel in range((pmin + 1), (pmax + 1)):
            # [inamura 120128]--> To Boost Manyo
            # ec_out = ec_out + eca_in.Put(pixel)
            ec_out += eca_in.Put(pixel)
            # <--[inamura 120128]
        return ec_out

    if PSD_min > PSD_max:
        temp = PSD_max
        PSD_max = PSD_min
        PSD_min = temp
    if Pixel_min > Pixel_max:
        temp = Pixel_max
        Pixel_max = Pixel_min
        Pixel_min = temp

    SIH = Manyo.SearchInHeader(Target)
    if PSD_min == PSD_max:
        SIH.SearchArray("PSDID", PSD_min)
    else:
        SIH.SearchArray("PSDID", PSD_min, PSD_max)
    psdv = SIH.PutResultIndex(0)
    del SIH  # [inamura 120630]
    psds = []

    if psdv.size() == 0:
        EC = None
        mu.UtsusemiWarning(
            "can not find such PSDs as {} to {}".format(PSD_min, PSD_max))
    else:
        for i in range(psdv.size()):
            psds.append(psdv[i])
        eca = Target.Put(psds[0])
        EC = sumECA(eca, Pixel_min, Pixel_max)
        for psd in psds[1:]:
            eca = Target.Put(psd)
            # [inamura 120128]--> To Boost Manyo
            # EC = EC + sumECA(eca,Pixel_min,Pixel_max)
            EC += sumECA(eca, Pixel_min, Pixel_max)
            # <--[inamura 120128]

        EC.ReSetUnit("Intensity", "neutrons")
        EC.ReSetUnit("Error", "neutrons")
    """
    eca = Target.Put(PSD_min)
    EC = sumECA(eca)
    if PSD_max>PSD_min:
        for psd in range((PSD_min+1),PSD_max):
            eca = Target.Put(psd)
            EC = EC + sumECA(eca)
    EC.ReSetUnit("Intensity","neutrons")
    EC.ReSetUnit("Error","neutrons")
    """

    # Add Header Info
    SS = "SumOfPixel(Target, PSD_min=%d, PSD_max=%d, Pixel_min=%d, Pixel_max=%d)" % (
        PSD_min, PSD_max, Pixel_min, Pixel_max)
    hh = EC.PutHeaderPointer()
    if hh.CheckKey("DATAPROCESSED") == 0:
        process_vect = Manyo.StringVector()
        process_vect.append(SS)
        hh.Add("DATAPROCESSED", process_vect)
    else:
        process_vect = hh.PutStringVector("DATAPROCESSED")
        process_vect.append(SS)
        hh.OverWrite("DATAPROCESSED", process_vect)

    return EC

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


def SumOfPixel(Target, PSD_min=1, PSD_max=1, Pixel_min=1, Pixel_max=1):
    """
    Put summation of intensity along Pixel
    @param Target    (ElementContainerMatrix)
    @param PSD_min   (int) lower limit of PSD-ID range
    @param PSD_max   (int) upper limit of PSD-ID range
    @param Pixel_min (int) lower limit of Pixel range
    @param Pixel_max (int) upper limit of Pixel range
    @retval EC
    """
    def sumECA(eca_in, pmin, pmax):
        hh0 = eca_in.PutHeader()
        if hh0.CheckKey(mu.UTSUSEMI_KEY_HEAD_MASKED) == 0:
            pass
        elif hh0.PutInt4(mu.UTSUSEMI_KEY_HEAD_MASKED) == 1:
            return None
        ec_out = None
        for p in range(pmin, pmax + 1):
            hh = eca_in.Put(p).PutHeader()
            if hh.CheckKey(mu.UTSUSEMI_KEY_HEAD_MASKED) == 0:
                pass
            elif hh.PutInt4(mu.UTSUSEMI_KEY_HEAD_MASKED) == 0:
                if ec_out is None:
                    ec_out = eca_in.Put(p)
                else:
                    ec_out += eca_in.Put(p)
            else:
                pass
        return ec_out

    if PSD_min > PSD_max:
        temp = PSD_max
        PSD_max = PSD_min
        PSD_min = temp
    if Pixel_min > Pixel_max:
        temp = Pixel_max
        Pixel_max = Pixel_min
        Pixel_min = temp

    SIH = Manyo.SearchInHeader(Target)
    if PSD_min == PSD_max:
        SIH.SearchArray("PSDID", PSD_min)
    else:
        SIH.SearchArray("PSDID", PSD_min, PSD_max)
    psdv = SIH.PutResultIndex(0)
    del SIH  # [inamura 120630]
    psds = []

    if psdv.size() == 0:
        EC = None
        mu.UtsusemiWarning(
            "can not find such PSDs as {} to {}".format(PSD_min, PSD_max))
    else:
        for i in range(psdv.size()):
            psds.append(psdv[i])

        EC = None
        for psd in psds:
            ret = sumECA(Target.Put(psd), Pixel_min, Pixel_max)
            if ret is not None:
                if EC is None:
                    EC = ret
                else:
                    EC += ret
        if EC is None:
            mu.UtsusemiWarning(
                "can not find Pixels with the given parameters.")
        else:
            EC.ReSetUnit("Intensity", "neutrons")
            EC.ReSetUnit("Error", "neutrons")

    if EC is None:
        UserWarning("SumOfPixes >> False.")

    # Add Header Info
    SS = "SumOfPixel(Target, PSD_min=%d, PSD_max=%d, Pixel_min=%d, Pixel_max=%d)" % (
        PSD_min, PSD_max, Pixel_min, Pixel_max)
    hh = EC.PutHeaderPointer()
    if hh.CheckKey("DATAPROCESSED") == 0:
        process_vect = Manyo.StringVector()
        process_vect.append(SS)
        hh.Add("DATAPROCESSED", process_vect)
    else:
        process_vect = hh.PutStringVector("DATAPROCESSED")
        process_vect.append(SS)
        hh.OverWrite("DATAPROCESSED", process_vect)

    return EC

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


def IntegPixels(Target, PSD_min=1, PSD_max=1, Pixel_min=1, Pixel_max=1, isAve=True):
    """
    Put summation of intensity along Pixel
    @param Target [Def:DAT] (ElementContainerMatrix)
    @param PSD_min   (int) lower limit of PSD-ID range
    @param PSD_max   (int) upper limit of PSD-ID range
    @param Pixel_min (int) lower limit of Pixel range
    @param Pixel_max (int) upper limit of Pixel range
    @param isAve     (bool) averaging or summation
    @retval EC ElementContainer
    """

    if not isinstance(Target, Manyo.ElementContainerMatrix):
        raise UserWarning("Target must be ElementContainerMatrix")

    if PSD_min > PSD_max:
        temp = PSD_max
        PSD_max = PSD_min
        PSD_min = temp
    if Pixel_min > Pixel_max:
        temp = Pixel_max
        Pixel_max = Pixel_min
        Pixel_min = temp

    if Pixel_max >= (Target(0).PutSize()):
        raise UserWarning(
            "Pixel max is out of range ( < {} )".format(Target(0).PutSize()))

    SIH = Manyo.SearchInHeader(Target)
    if PSD_min == PSD_max:
        SIH.SearchArray("DETID", PSD_min)
    else:
        SIH.SearchArray("DETID", PSD_min, PSD_max)
    psdv = SIH.PutResultIndex(0)
    del SIH  # [inamura 120630]
    psds = []

    if psdv.size() == 0:
        EC = None
        raise UserWarning(
            "can not find such PSDs as {} to {}".format(PSD_min, PSD_max))
    else:
        detv = Manyo.MakeUInt4Vector()
        pixv = Manyo.MakeUInt4Vector()
        for i in range(psdv.size()):
            for j in range(Pixel_min, (Pixel_max + 1)):
                detv.append(psdv[i])
                pixv.append(int(j))
        AVE = mm.AverageElementContainerMatrix(Target, detv, pixv)
        EC = Manyo.ElementContainer()
        if isAve:
            if AVE.GetAverage(EC):
                pass
            else:
                raise UserWarning("IntegPixels ERROR")
        else:
            if AVE.GetSum(EC):
                pass
            else:
                raise UserWarning("IntegPixels ERROR")
        del AVE

    # Add Header Info
    SS = "IntegPixels(Target, PSD_min=%d, PSD_max=%d, Pixel_min=%d, Pixel_max=%d)" % (
        PSD_min, PSD_max, Pixel_min, Pixel_max)
    hh = EC.PutHeaderPointer()
    if hh.CheckKey("DATAPROCESSED") == 0:
        process_vect = Manyo.StringVector()
        process_vect.append(SS)
        hh.Add("DATAPROCESSED", process_vect)
    else:
        process_vect = hh.PutStringVector("DATAPROCESSED")
        process_vect.append(SS)
        hh.OverWrite("DATAPROCESSED", process_vect)

    return EC

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


def PickUpRegion(Target, PSD_min=1, PSD_max=1, Pixel_min=1, Pixel_max=1):
    """
    Put summation of intensity along Pixel
    @param Target    (ElementContainerMatrix)
    @param PSD_min   (int) lower limit of PSD-ID range
    @param PSD_max   (int) upper limit of PSD-ID range
    @param Pixel_min (int) lower limit of Pixel range
    @param Pixel_max (int)  upper limit of Pixel range
    @retval ElementContainerMatrix
    """
    if PSD_min > PSD_max:
        temp = PSD_max
        PSD_max = PSD_min
        PSD_min = temp
    if Pixel_min > Pixel_max:
        temp = Pixel_max
        Pixel_max = Pixel_min
        Pixel_min = temp

    hh = Target.PutHeader()
    NewECM = Manyo.ElementContainerMatrix(hh)

    SIH = Manyo.SearchInHeader(Target)
    SIH.SearchArray("PSDID", PSD_min, PSD_max)
    psds = SIH.PutResultIndex(0)
    del SIH  # [inamura 120630]
    if psds.size() == 0:
        newECM = None
        mu.UtsusemiWarning(
            "can not find such PSDs as {} to {}".format(PSD_min, PSD_max))
    else:
        for i in range(psds.size()):
            eca = Target.Put(psds[i])
            hh_eca = eca.PutHeader()
            newECA = Manyo.ElementContainerArray(hh_eca)
            for pixel in range(Pixel_min, (Pixel_max + 1)):
                newECA.Add(eca.Put(pixel))
            NewECM.Add(newECA)

    # Add Header Info
    SS = "PickUpRegion(Target, PSD_min=%d, PSD_max=%d, Pixel_min=%d, Pixel_max=%d)" % (
        PSD_min, PSD_max, Pixel_min, Pixel_max)
    hh = NewECM.PutHeaderPointer()
    process_vect = hh.PutStringVector("DATAPROCESSED")
    process_vect.append(SS)
    if hh.CheckKey("DATAPROCESSED") == 0:
        hh.Add("DATAPROCESSED", process_vect)
    else:
        hh.OverWrite("DATAPROCESSED", process_vect)

    return NewECM

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


def NormByBeam(dat, start_day="2009/5/30", start_time="10:00:00", end_day="2009/5/30", end_time="11:00:00", factor=1.0, offset_sec=0.0, isCT8n=False, isTagCorrect=True):
    """
    Normailze by Beam current from web and calculate summation of the number of shots and protons
    @param 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

    """
    PROCESS = "NormByBeam"
    ret = CheckDataProcess(dat, PROCESS)

    bc = getBeamCurrent(start_day, start_time, end_day,
                        end_time, offset_sec, isCT8n, isTagCorrect)
    if bc < 0:
        mu.UtsusemiWarning("BeamCurrent is invalid.")
        return dat
    dat.MulMySelf(float(factor) / float(bc))

    # Add Header Info
    SS = PROCESS + "(dat,start_day='%s', start_time='%s', end_day='%s', end_time='%s', factor=%d )" % (
        start_day, start_time, end_day, end_time, factor)
    hh = dat.PutHeaderPointer()
    process_vect = hh.PutStringVector("DATAPROCESSED")
    process_vect.append(SS)
    if hh.CheckKey("DATAPROCESSED") == 0:
        hh.Add("DATAPROCESSED", process_vect)
    else:
        hh.OverWrite("DATAPROCESSED", process_vect)

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


def GetBeamCurrentFromECM(dat, offset_sec=0.0, isCT8n=False, isTagCorrect=True):
    """

    @param dat (ElementContainerMatrix)
    @param offset (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
    @return beamCorrent
    """
    runNos = dat.PutHeader().PutString("RUNNUMBER")
    runNo_list = runNos.split("+")

    mpv = None
    if dat.PutHeader().CheckKey("MEASPERIOD") == 1:
        mpv = dat.PutHeader().PutDoubleVector("MEASPERIOD")
        if ((mpv.size()) % 14) != 0:
            mpv = None

    if (mpv is None):
        for runNo_s in runNo_list:
            runNo = int(runNo_s)
            TT = mu.T0TreatToolsPsd()
            st_RUNNO = "%3s%06d" % (os.environ["UTSUSEMI_INST_CODE"], runNo)

            st_XXXdir = os.path.join(
                os.environ["UTSUSEMI_DATA_DIR"], os.environ["UTSUSEMI_INST_CODE"])
            list_DATA = os.listdir(st_XXXdir)
            target_dir = ""
            for data_dir in list_DATA:
                if st_RUNNO in data_dir:
                    target_dir = data_dir
                    break
            if target_dir == "":
                err_message = "There is no data;" + st_RUNNO
                raise UserWarning(err_message)
            edb_list = os.listdir(os.path.join(st_XXXdir, target_dir))
            edb_list.sort()
            target_edb = ""
            for a_edb in edb_list:
                if ".edb" in a_edb:
                    target_edb = a_edb
                    break
            if target_edb == "":
                err_message = "There is no edb data;" + st_RUNNO
                raise UserWarning(err_message)
            TT.readOrgEvent(os.path.join(st_XXXdir, target_dir, target_edb))
            mpv_tmp = TT.putMeasPeriodFromT0()
            del TT  # [inamura 120630]

            for i in range(mpv_tmp.size()):
                mpv.push_back(mpv_tmp[i])

    if ((mpv.size()) % 14) != 0:
        err_message = "False to get measuring period from Event Data"
        raise UserWarning(err_message)

    bc = 0
    for i in range(int(mpv.size() / 14)):
        offset = i * 14
        start_date = "%04d/%02d/%02d" % (int(mpv[0 + offset]),
                                         int(mpv[1 + offset]), int(mpv[2 + offset]))
        start_time = "%02d:%02d:%02d" % (
            int(mpv[3 + offset]), int(mpv[4 + offset]), int(mpv[5 + offset]))
        end_date = "%04d/%02d/%02d" % (int(mpv[7 + offset]),
                                       int(mpv[8 + offset]), int(mpv[9 + offset]))
        end_time = "%02d:%02d:%02d" % (
            int(mpv[10 + offset]), int(mpv[11 + offset]), int(mpv[12 + offset]))

        mu.UtsusemiMessage("NormByBeamCurrent(runNo=%s)" % runNo_list[i])
        # print("     begin date and time = {} {}".format(start_date,start_time))
        # print("       end date and time = {} {}".format(end_date,end_time))

        bc_tmp = getBeamCurrent(
            start_date, start_time, end_date, end_time, offset_sec, isCT8n, isTagCorrect)
        if bc_tmp < 0:
            msg = "BeamCurrent is invalid for RunNo= {}".format(runNo_list[i])
            mu.UtsusemiError(msg)
            raise UserWarning(msg)
        else:
            bc += bc_tmp

    return bc

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


def NormByBeamCurrent(dat, factor=1000.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        (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
    """
    import datetime
    PROCESS = "NormByBeamCurrent"
    ret = CheckDataProcess(dat, "NormByBeam")

    if factor == 0:
        return

    if factor < 0:
        dat.MulMySelf(1.0 / float(abs(factor)))
        return

    bc = GetBeamCurrentFromECM(dat, offset_sec, isCT8n, isTagCorrect)
    if bc < 0:
        msg = "Normalize by Proton Current is disable. Argument of Norm Factor must be 0 or minus"
        raise UserWarning(msg)

    if bc == 0:
        msg = "Normalize by Proton Current fails. Maybe the period of measurements is invalid. Check event data or the slicing time region"
        raise UserWarning(msg)

    dat.MulMySelf(float(factor) / float(bc))

    # Add Header Info
    SS = PROCESS + "(dat, factor=%d )" % (factor)
    hh = dat.PutHeaderPointer()
    process_vect = hh.PutStringVector("DATAPROCESSED")
    process_vect.append(SS)
    if hh.CheckKey("DATAPROCESSED") == 0:
        hh.Add("DATAPROCESSED", process_vect)
    else:
        hh.OverWrite("DATAPROCESSED", process_vect)


#########################################
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.0, isCT8n=True, isTagCorrect=True):
    """
    get Beam current from web and calculate summation of the number of shots and protons
    @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 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 beamCurrent        the number of protons [TelaProtons]
    """
    GBC = NSI.getNeutronSourceInfo()
    bc, ratio, org_bc = GBC.getBeamCurrent(
        start_day, start_time, end_day, end_time, offset_sec, isCT8n)

    if isTagCorrect:
        return bc
    else:
        return org_bc

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


def getBeamCurrentWithCorrectRatio(start_day="2009/5/30", start_time="10:00:00", end_day="2009/5/30", end_time="11:00:00", offset_sec=0.0, isCT8n=False):
    """
    get Beam current, min(tag), max(tag) and counts from web and calculate summation of the number of shots and protons
    @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 offset_sec (float) offset second for Measurement Period to get protons
    @param isCT8n (bool) use CT8Neutron ( corrected by muon target effect ) or not
    @retval (corrected beamCurrent,ratio,original beamCurrent)   the number of protons [TelaProtons]
    """
    GBC = NSI.getNeutronSourceInfo()
    return GBC.getBeamCurrent(start_day, start_time, end_day, end_time, offset_sec, isCT8n)

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


def NormByKickers(dat, factor=1.0):
    """
    Normalize data intensity by the number of kickers

    @params dat (ElementContainerMatrix)
    @params factor (double) <Intensity>/<kickers>*<factor> when factor>0.0, <Intensity>/<kickers>/<|factor|> when factor<0.0
    @retval None
    """
    NBK = mu.UtsusemiReductionCommon()
    NBK.NormByKickers(dat)
    del NBK
    if factor < 0.0:
        dat.MulMySelf(-1.0 / float(factor))
    elif factor > 0.0:
        dat.MulMySelf(float(factor))

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


def CalcPhi(dat):
    """
    Calculate polar-angle and azim-angle of each Pixel from Pixel Position
    @param dat (ElementContainerMatrix)
    """
    URI = mu.UtsusemiReductionInEla(dat)
    URI.CalcPhi()
    del URI

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


def SolidAngleCorrection(dat, dS=-1.0):
    """
    Correction for solid angle of pixel
    Each intensity is devided by solid angle * default value
    @param dat (ElementContainerMatrix)
    @param dS (Double) the area of 1 pixel on PSD. -1.0 means default value.
    """
    PROCESS = "SolidAngleCorrection"
    ret = CheckDataProcess(dat, PROCESS)

    mu.UtsusemiMessage("SolidAngleCorrection >>> executing...")
    hh = dat.PutHeaderPointer()
    L2 = hh.PutDouble("TypicalL2")
    if dS == -1.0:
        dS = hh.PutDouble("TypicalDS")
    # L2 = Def_L2*1000.0     # [mm]
    # if dS==-1.0:
    #    dS = Def_dS        # [mm]

    dOmega = dS / (L2 * L2)

    start = time.time()
    for psd in range(dat.PutTableSize()):
        if dat(psd).PutHeaderPointer().PutString("TYPE") == "PSD":
            for pixel in range(dat(psd).PutTableSize()):
                ec = dat(psd, pixel)
                sa = ec.PutHeaderPointer().PutDouble("PixelSolidAngle")
                sa = sa / dOmega
                if sa == 0:
                    mu.UtsusemiWarning(
                        "Solid Angle=0 at {}".format(psd, pixel))
                else:
                    ec.MulMySelf(1.0 / sa)

    # Add Header Info
    SS = PROCESS + "(dat, dS=%f)" % (dS)
    hh = dat.PutHeaderPointer()
    process_vect = hh.PutStringVector("DATAPROCESSED")
    process_vect.append(SS)
    if hh.CheckKey("DATAPROCESSED") == 0:
        hh.Add("DATAPROCESSED", process_vect)
    else:
        hh.OverWrite("DATAPROCESSED", process_vect)

    mu.UtsusemiMessage(
        "SolidAngleCorrection >>> Cost of time : {}".format(time.time() - start))

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


def DoMask(dat, filename="mask.txt"):
    """
    MASKED flag controled by file.
    @param dat (ElementContainerMatrix)
    @param filename (string) filename of mask information
    """
    PROCESS = "DoMask"
    ret = CheckDataProcess(dat, PROCESS, False)

    mu.UtsusemiMessage("DoMask >>> executing...")
    SM = mu.UtsusemiSetMask(dat)
    if SM.ReadFile(filename):
        pass
    else:
        raise UserWarning("DoMask : Failed to read mask file = {}".format(filename))
    if SM.Execute():
        pass
    else:
        raise UserWarning(
            "DoMask : Failed to mask >> mask file is invalid ({})".format(filename))

    # Add Header Info
    SS = PROCESS + "(dat, filename={})".format(filename)
    hh = dat.PutHeaderPointer()
    process_vect = hh.PutStringVector("DATAPROCESSED")
    process_vect.append(SS)
    if hh.CheckKey("DATAPROCESSED") == 0:
        hh.Add("DATAPROCESSED", process_vect)
    else:
        hh.OverWrite("DATAPROCESSED", process_vect)

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


def FlexCalc(dat, Intensity="", Error=""):
    """
    Flexible calculation of S(Q,hw) on ElementContainerMatrix.
    @param dat (ElementContainerMatrix)
    @param Intensity (string) the expression of Intensity calculation
    @param Error     (string) the expression of Error calculation
    @retval (ElementContainerMatrix) Calcurated data
    """
    mu.UtsusemiMessage("FlexCalc >>> executing...")
    ffunc = FC.FlexCalc(dat, Intensity, Error)
    ret = ffunc.DoFunc()
    ffunc.finish()
    return ret

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


def CheckDataProcess(dat, process="", ErrorFlag=True):
    """
    Check DATAPROCESSED
    If given process had already been executed, raise error or warning.
    @param process (string) process string to be searched
    @param ErrorFlag (Boolen) if True, raise error. if False, show Warning.
    @retval True or False
    """
    # print "CheckProcess"
    CDP = mu.UtsusemiCheckDataProcess()
    return CDP.CheckProcess(dat, process, False)
    """
    D_Processed = dat.PutHeaderPointer().PutStringVector("DATAPROCESSED")
    for i in range(D_Processed.size()):
        if D_Processed[i].find(process)!=-1:
            if ErrorFlag:
                raise UserWarning("This process had already been executed.")
            else:
                print("WARNING!! Maybe you did this process before.")
                return False

    return True
    """

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


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
    """
    ADF.AppendRawDataFiles(OutRunNo, outDataPath, RunNo1,
                           RunNo2, RunNo3, RunNo4, RunNo5, RunNo6)


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

    @param dat (ElementContainerMatrix)
    @param filepath (string)
    @retval None
    """
    import os
    if not os.path.exists(filepath):
        messages = "Not found file path (%s)" % (filepath)
        raise UserWarning(messages)

    hh = dat.PutHeader()
    runNo = int(hh.PutString("RUNNUMBER"))
    for psd in range(dat.PutSize()):
        eca = dat(psd)
        for pix in range(eca.PutSize()):
            ec = eca(pix)
            filename = "run%06d_%03d_%03d.txt" % (runNo, psd, pix)
            savefilepath = os.path.join(filepath, filename)
            ec.SaveTextFile(savefilepath)


############################################
def SaveDataToSrlz(dat, path="./", filename="Sample.srlz"):
    """
    Serialize ElementContainerMatrix to dump file using Boost Serialize class.
    Data File from this function has the operation system dependency.
    @param  dat      (ElementContainer, -Array, -Matrix)
    @param  path     (String) path to data file
    @param  filename (String) data file name
    @retval None
    """
    out_filepath = os.path.join(path, filename)
    wb = Manyo.WriteSerializationFileBinary(str(out_filepath))
    wb.Save(dat)
    del wb

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


def LoadDataFromSrlz(path="./", filename="Sample.srlz", DataType="ECM"):
    """
    Serialize ElementContainerMatrix to dump file using Boost Serialize class.
    Data File from this function has the operation system dependency.
    @param  path     (String) path to data file
    @param  filename (String) data file name
    @param  DtaType  (String) "EC" or "ECA" or "ECM"
    @retval None
    """
    filepath = os.path.join(path, filename)
    if not os.path.exists(filepath):
        messages = "Not Found : %s" % (filepath)
        raise UserWarning(messages)

    ret_dat = None
    if DataType == "EC":
        ret_dat = Manyo.ElementContainer()
    elif DataType == "ECA":
        ret_dat = Manyo.ElementContainerArray()
    elif DataType == "ECM":
        ret_dat = Manyo.ElementContainerMatrix()
    else:
        raise UserWarning(
            "Wrong DataType : Data Type must be EC or ECA or ECM")

    rb = Manyo.ReadSerializationFileBinary(str(filepath))
    rb.Load(ret_dat)
    del rb

    return ret_dat

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


def DetectorEffiBase(dat, detInfo_file="DetectorInfo_Det.xml", det_name="SUS304-3He-PSD"):
    """
    DetectorEfficiency correction
    @param dat [Def:DAT] (ElementContainerMatrix)
    @param detInfo_file (string)
    @param det_name (string)
    @return None
    """
    tt = mu.UtsusemiDetectorEfficiencyCorrection()
    if tt.Initialize(detInfo_file, det_name):
        tt.Execute(dat)
    else:
        raise UserWarning("Invalid Parameters")
#########################################


def DetectorEffi(dat, dataFile="DetEffiData.dat"):
    """
    DetectorEfficiency correction
    @param dat [Def:DAT] (ElementContainerMatrix)
    @param dataFile (string)
    @return None
    """
    tt = mu.UtsusemiDetectorEfficiencyCorrection()
    if tt.LoadDataFile(dataFile):
        tt.Execute(dat)
    else:
        raise UserWarning("Invalid Parameters")

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


def ArrayDataCut(Dat, Axis="X", Xkey="Default", IntegRange="All", Ave=True, AxisRange="All"):
    """
    Cut the given data (ElementContainerArray)
    If given data is ElementContainerMatrix, first ElementContainerArray is used for cutting
    @param  Dat [Def:DAT]   data
    @param  AxisX (string) axis of cut data. can use a key of vector stored in header of ElementContainer
    @param  IntegRange (string) range of integral on data "All" or "<min>,<max>"
    @param  Ave (bool) True : cut intensity is averaging, False : summation.
    @param  AxisRange (string) : range of axis "All" or "<min>,<max>"
    @retval EC (ElementContaienr)
    """
    dat = None
    runNo_s = None
    if isinstance(Dat, Manyo.ElementContainerMatrix):
        dat = Dat.Put(0)
    elif isinstance(Dat, Manyo.ElementContainerArray):
        dat = Dat
    else:
        raise UserWarning("Given data is not ElementContainerArray or -Matrix")

    if Dat.PutHeader().CheckKey("RUNNUMBER") == 1:
        runNo_s = Dat.PutHeader().PutString("RUNNUMBER")

    AS = mm.MlfArraySlicer(dat)
    if Xkey.upper() == "DEFAULT":
        Xkey = ""
    elif AS.SetAxes(Xkey):
        pass
    else:
        raise UserWarning("Given Xkey is invalid.")

    if Axis.upper() not in ["X", "Y"]:
        raise UserWarning("Given Axis is invalid.")
    Axis = Axis.upper()

    x0 = -1.0e32
    y0 = -1.0e32
    x1 = 1.0e32
    y1 = 1.0e32
    if IntegRange.upper() != "ALL":
        t_range = IntegRange.split(",")
        if len(t_range) != 2:
            raise UserWarning("IntegRange is invalid.")
        y0 = float(t_range[0])
        y1 = float(t_range[1])
        if y0 > y1:
            tmp = y0
            y0 = y1
            y1 = tmp

    if AxisRange.upper() != "ALL":
        t_range = AxisRange.split(",")
        if len(t_range) != 2:
            raise UserWarning("IntegRange is invalid.")
        x0 = float(t_range[0])
        x1 = float(t_range[1])
        if x0 > x1:
            tmp = x0
            x0 = x1
            x1 = tmp

    AS.SetClipRegion(x0, y0, x1, y1)

    if Axis == "X":
        ret = AS.CutAlongX(Ave)
    elif Axis == "Y":
        ret = AS.CutAlongY(Ave)

    if IntegRange.upper() == "ALL":
        ret(0).PutHeaderPointer().OverWrite("Label", "Integrated All")

    if runNo_s is not None:
        ret(0).PutHeaderPointer().OverWrite("RUNNUMBER", runNo_s)

    return ret.Put(0)


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

def PutLatestDataFolder(dataDir="", runRange=[]):
    """Put latest run number and run data folder
    @param dataDir (string) The path of the folder including run data folder, like "/data/SIK". If empty, use default.
    @param runRange (list of int) The run number range [min_runNo, max_runNo]. Empty list means all run no.
    @retval tupple of runNo(int) and the path to the run data folder(string)
    @retval None when something is wrong.
    """
    if len(runRange) != 0 and len(runRange) != 2:
        print("#ERROR:: Argument run Range is invalid.")
        return None
    if dataDir != "":
        if os.path.exists(dataDir):
            if not os.path.isdir(dataDir):
                print("#ERROR : dataDir {} is not directory.".format(dataDir))
                return None
        else:
            print("#ERROR : not found dataDir {}".format(dataDir))
            return None

    instCode = mu.UtsusemiEnvGetInstCode()    # get "SIK","AMR","SAS"
    dataRootPath = mu.UtsusemiEnvGetDataDir() # get "/data"
    if instCode == "":
        print("#ERROR : Not Utsusemi environment. (Not found UTSUSEMI_INST_CODE environment value")
        return None

    runDirList = glob.glob(os.path.join(dataRootPath, instCode + "*", "{}*_*".format(instCode)))
    if dataDir != "":
        runDirList = glob.glob(os.path.join(dataDir, "{}*_*".format(instCode)))
    runDirList.sort()
    runDirList.reverse()
    for a_path in runDirList:
        if len(os.path.basename(a_path)) != 18:
            continue

        runNo = int(os.path.basename(a_path)[3:9])
        if runNo == 0:
            continue
        if len(runRange) == 2:
            if runNo < runRange[0] or runNo > runRange[1]:
                continue
        return (runNo, a_path)
