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

from __future__ import print_function
import time
import os
import Manyo
import Manyo.Utsusemi as mu
import math
from utsusemi.ana.Reduction.BaseCommands import *

#########################################
# BaseCommands for Elastic
#########################################


def GetHistDTconstNeunetPsd(runNo=0, isTimeFoc=True, tofRange="0.0 40000.0", binTOF=10.0, detRange="-1 -1", NumOfPixel=100, 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=Def_NumOfPixel,
                             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 ElementContainerMatrix
    """
    if isinstance(isTimeFoc, bool):
        raise UserWarning("isTimeFoc is unknown.")
    ConvType = 2
    if isTimeFoc:
        ConvType = 12
    tof_range = SplitStringParameters(tofRange, 2, "float")
    if isinstance(tof_range, int) and tof_range < 0:
        raise UserWarning("tofRange is invalid.")
    det_range = SplitStringParameters(detRange, 2, "int")
    if isinstance(det_range, int) and det_range < 0:
        raise UserWarning("detRange is invalid.")
    time_range = SplitStringParameters(timeRange, 2, "float")
    if isinstance(time_range, int) and time_range < 0:
        raise UserWarning("timeRange is invalid.")

    fInfo = [0, 0.0]
    if frameBoundary != 0.0:
        if frameBoundary <= 40000.0:
            fInfo[0] = 2
            fInfo[1] = frameBoundary
        elif frameBoundary <= 80000.0:
            fInfo[0] = 3
            fInfo[1] = frameBoundary - 40000.0
        else:
            raise UserWarning("Invalid frameBoundary.")

    runNo = str(runNo)
    key_hist = ""
    if isTimeFoc:
        key_hist = "tf-tof"
    else:
        key_hist = "tof"
    HistParam = "%s,%f,%f,%f" % (key_hist, tof_range[0], tof_range[1], binTOF)
    DetParam = "psd"
    DetRange = ""
    if det_range[0] == -1 and det_range[1] == -1:
        DetRange = "All"
    else:
        DetRange = "%d-%d" % (det_range[0], det_range[1])
    TimeRange = "%f,%f" % (time_range[0], time_range[1])
    FrameInfo = "%d,%f" % (fInfo[0], fInfo[1])

    return GetNeunetHist(runNo=runNo,
                         HistParam=HistParam,
                         DetParam=DetParam,
                         DetRange=DetRange,
                         TimeRange=TimeRange,
                         FrameInfo=FrameInfo)

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


def GetHistToDTconstNeunetPsd(runNo=0, isTimeFoc=True, tofRange="0.0 40000.0", racio=0.01, detRange="-1 -1", NumOfPixel=100, 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=Def_NumOfPixel,
                               timeRange="-1 -1",frameBoundary=0.0 )

    @param runNo     (int) RunNumber
    @param isTimeFoc (bool) True: use Time Focusing
    @param tofRange  (string) startTOF,endTOF
    @param racio     (float)  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 ElementContainerMatrix
    """
    if isinstance(isTimeFoc, bool):
        raise UserWarning("isTimeFoc is unknown.")
    ConvType = 3
    if isTimeFoc:
        ConvType = 13
    tof_range = SplitStringParameters(tofRange, 2, "float")
    if isinstance(tof_range, int) and tof_range < 0:
        raise UserWarning("tofRange is invalid.")
    det_range = SplitStringParameters(detRange, 2, "int")
    if isinstance(det_range, int) and det_range < 0:
        raise UserWarning("detRange is invalid.")
    time_range = SplitStringParameters(timeRange, 2, "float")
    if isinstance(time_range, int) and time_range < 0:
        raise UserWarning("timeRange is invalid.")

    fInfo = [0, 0.0]
    if frameBoundary != 0.0:
        if frameBoundary <= 40000.0:
            fInfo[0] = 2
            fInfo[1] = frameBoundary
        elif frameBoundary <= 80000.0:
            fInfo[0] = 3
            fInfo[1] = frameBoundary - 40000.0
        else:
            raise UserWarning("Invalid frameBoundary.")

    runNo = str(runNo)
    key_hist = ""
    if isTimeFoc:
        key_hist = "tf-rtof"
    else:
        key_hist = "rtof"
    HistParam = "%s,%f,%f,%f" % (key_hist, tof_range[0], tof_range[1], racio)
    DetParam = "psd"
    DetRange = ""
    if det_range[0] == -1 and det_range[1] == -1:
        DetRange = "All"
    else:
        DetRange = "%d-%d" % (det_range[0], det_range[1])
    TimeRange = "%f,%f" % (time_range[0], time_range[1])
    FrameInfo = "%d,%f" % (fInfo[0], fInfo[1])

    return GetNeunetHist(runNo=runNo,
                         HistParam=HistParam,
                         DetParam=DetParam,
                         DetRange=DetRange,
                         TimeRange=TimeRange,
                         FrameInfo=FrameInfo)


#########################################
def GetHistDQconstNeunetPsd(runNo=0, Qrange="0.1 10.0", deltaQ=0.1, detRange="-1 -1", NumOfPixel=100, 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=Def_NumOfPixel,
                             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 ElementContainerMatrix
    """
    Q_range = SplitStringParameters(Qrange, 2, "float")
    if isinstance(Q_range, int) and Q_range < 0:
        raise UserWarning("Q Range is invalid.")
    det_range = SplitStringParameters(detRange, 2, "int")
    if isinstance(det_range, int) and det_range < 0:
        raise UserWarning("detRange is invalid.")
    time_range = SplitStringParameters(timeRange, 2, "float")
    if isinstance(time_range, int) and time_range < 0:
        raise UserWarning("timeRange is invalid.")
    in_vect = SplitStringParameters(inVect, 3, "float")
    if isinstance(in_vect, int) and in_vect < 0:
        raise UserWarning("in vect is invalid.")

    fInfo = [0, 0.0]
    if frameBoundary != 0.0:
        if frameBoundary <= 40000.0:
            fInfo[0] = 2
            fInfo[1] = frameBoundary
        elif frameBoundary <= 80000.0:
            fInfo[0] = 3
            fInfo[1] = frameBoundary - 40000.0
        else:
            raise UserWarning("Invalid frameBoundary.")

    params = [Q_range[0], Q_range[1], deltaQ,
              in_vect[0], in_vect[1], in_vect[2]]

    runNo = str(runNo)
    HistParam = "q,%f,%f,%f,%f,%f,%f" % (
        Q_range[0], Q_range[1], deltaQ, in_vect[0], in_vect[1], in_vect[2])
    DetParam = "psd"
    DetRange = ""
    if det_range[0] == -1 and det_range[1] == -1:
        DetRange = "All"
    else:
        DetRange = "%d-%d" % (det_range[0], det_range[1])
    TimeRange = "%f,%f" % (time_range[0], time_range[1])
    FrameInfo = "%d,%f" % (fInfo[0], fInfo[1])

    return GetNeunetHist(runNo=runNo,
                         HistParam=HistParam,
                         DetParam=DetParam,
                         DetRange=DetRange,
                         TimeRange=TimeRange,
                         FrameInfo=FrameInfo)

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


def GetHistDTconstGatenetMon(runNo=0, tofRange="0.0 40000.0", binTOF=10.0, detRange="-1 -1", NumOfPixel=4, 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,
                              detRange="-1 -1",NumOfPixel=4,
                              timeRange="-1 -1",frameBoundary=0.0 )

    @param runNo     (int) RunNumber
    @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 ElementContainerMatrix
    """

    tof_range = SplitStringParameters(tofRange, 2, "float")
    if isinstance(tof_range, int) and tof_range < 0:
        raise UserWarning("tofRange is invalid.")
    det_range = SplitStringParameters(detRange, 2, "int")
    if isinstance(det_range, int) and det_range < 0:
        raise UserWarning("detRange is invalid.")
    time_range = SplitStringParameters(timeRange, 2, "float")
    if isinstance(time_range, int) and time_range < 0:
        raise UserWarning("timeRange is invalid.")

    fInfo = [0, 0.0]
    if frameBoundary != 0.0:
        if frameBoundary <= 40000.0:
            fInfo[0] = 2
            fInfo[1] = frameBoundary
        elif frameBoundary <= 80000.0:
            fInfo[0] = 3
            fInfo[1] = frameBoundary - 40000.0
        else:
            raise UserWarning("Invalid frameBoundary.")

    runNo = str(runNo)
    HistParam = "tof,%f,%f,%f" % (tof_range[0], tof_range[1], binTOF)
    DetParam = "n2mon"
    DetRange = ""
    if det_range[0] == -1 and det_range[1] == -1:
        DetRange = "All"
    else:
        DetRange = "%d-%d" % (det_range[0], det_range[1])
    TimeRange = "%f,%f" % (time_range[0], time_range[1])
    FrameInfo = "%d,%f" % (fInfo[0], fInfo[1])

    return GetNeunetHist(runNo=runNo,
                         HistParam=HistParam,
                         DetParam=DetParam,
                         DetRange=DetRange,
                         TimeRange=TimeRange,
                         FrameInfo=FrameInfo)

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


def GetHistToDTconstGatenetMon(runNo=0, tofRange="0.0 40000.0", racio=0.01, detRange="-1 -1", NumOfPixel=4, 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,
                                detRange="-1 -1",NumOfPixel=4,
                                timeRange="-1 -1",frameBoundary=0.0 )

    @param runNo     (int) RunNumber
    @param tofRange  (string) startTOF,endTOF
    @param racio     (float)  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 ElementContainerMatrix
    """

    tof_range = SplitStringParameters(tofRange, 2, "float")
    if isinstance(tof_range, int) and tof_range < 0:
        raise UserWarning("tofRange is invalid.")
    det_range = SplitStringParameters(detRange, 2, "int")
    if isinstance(det_range, int) and det_range < 0:
        raise UserWarning("detRange is invalid.")
    time_range = SplitStringParameters(timeRange, 2, "float")
    if isinstance(time_range, int) and time_range < 0:
        raise UserWarning("timeRange is invalid.")

    fInfo = [0, 0.0]
    if frameBoundary != 0.0:
        if frameBoundary <= 40000.0:
            fInfo[0] = 2
            fInfo[1] = frameBoundary
        elif frameBoundary <= 80000.0:
            fInfo[0] = 3
            fInfo[1] = frameBoundary - 40000.0
        else:
            raise UserWarning("Invalid frameBoundary.")

    runNo = str(runNo)
    HistParam = "rtof,%f,%f,%f" % (tof_range[0], tof_range[1], racio)
    DetParam = "n2mon"
    DetRange = ""
    if det_range[0] == -1 and det_range[1] == -1:
        DetRange = "All"
    else:
        DetRange = "%d-%d" % (det_range[0], det_range[1])
    TimeRange = "%f,%f" % (time_range[0], time_range[1])
    FrameInfo = "%d,%f" % (fInfo[0], fInfo[1])

    return GetNeunetHist(runNo=runNo,
                         HistParam=HistParam,
                         DetParam=DetParam,
                         DetRange=DetRange,
                         TimeRange=TimeRange,
                         FrameInfo=FrameInfo)
#########################################


def SaveDataToNVASQ(dat, path="./", filename="Sample.nx", L1=25000.0, px=15000.0, py=0.0, pz=0.0):
    """
    Save ElementContainer to NeXus file with nvaSp.py format.(for BL11 only)
    @param  dat      (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
    """
    if not isinstance(dat, Manyo.ElementContainer):
        raise UserWarning(" dat argument must be ElementContainer.")

    ec = Manyo.ElementContainer()
    ec.Add("TOF", dat.PutX(), dat.PutUnit(ec.PutXKey()))
    ec.Add("Intensity", dat.PutY(), dat.PutUnit(ec.PutYKey()))
    ec.Add("Error", dat.PutE(), dat.PutUnit(ec.PutEKey()))
    ec.SetKeys("TOF", "Intensity", "Error")
    eca = Manyo.ElementContainerArray()
    eca.Add(ec)

    hh = eca.PutHeaderPointer()
    hh.Add("L1", L1)

    pv = Manyo.MakeDoubleVector()
    pv.append(float(px))
    pv.append(float(py))
    pv.append(float(pz))

    hh1 = eca(0).PutHeaderPointer()
    hh1.Add("PixelPosition", pv)
    # hh1.Add("Lsintheta",17677.67)
    hh1.Add("Lsintheta", (L1 + 1500.0) * 0.707106781)
    hh1.Add("ttheta", 1.5708)
    hh1.Add("L2", 1500.0)

    nexusIO = Manyo.NeXusFileIO()
    nexusIO.Write(eca, os.path.join(path, filename), "BL11", 0)
    del nexusIO
