#ifndef UTSUSEMITRIGNETDICTIONARY
#define UTSUSEMITRIGNETDICTIONARY

#include "UtsusemiHeader.hh"
#include "Header.hh"
#include "StringTools.hh"
#include "T0TreatToolsBase.hh"
#include <algorithm>

//////////////////////////////////
// UtsusemiTrignetDictionary
/////////////////////////////////

//! Dictionary for TrigNet and Make Case Table
/*!
 *
 */

class UtsusemiTrignetDictionary
{
private:
    std::vector<std::string> TrigDic;
    std::vector<std::string> TypeDic;
    void Initialize();
    std::string MessageTag;

public:
    UtsusemiTrignetDictionary();
        //!< Constructor
        /*!<
         */
    ~UtsusemiTrignetDictionary();
        //!< Destructor
        /*!<
         */

    std::string PutTrigString( UInt4 sid1 );
        //!< Puts charactors code defined for SID1 in TrigDic.
        /*!<
         *   @param sid1 (UInt4) SID1 number
         *   @retrun code (std::string)
         */
    std::string PutTypeString( UInt4 sid2 );
        //!< Puts charactors code defined for Type in TypeDic.
        /*!< This Type is used to analyze last 3 bites in TrinNET event
         *
         *   @param sid2 (UInt4) SID2 number
         *   @retrun code (std::string)
         */
    Int4 PutTrigIndex( std::string trig );
        //!< Puts index number defined for trig code in TrigDic.
        /*!<
         *
         *   @param trig (std::string) trigger code
         *   @retval >=0  index number
         *   @retval -1   invalid trigger code
         */
    Int4 PutTypeIndex( std::string type );
        //!< Puts index number defined for type code in TypeDic.
        /*!<
         *
         *   @param type (std::string) type code
         *   @retval >=0  index number
         *   @retval -1   invalid trigger code
         */

};

//////////////////////////////////
// UtsusemiTrignetCondition
/////////////////////////////////

//! TrigNET filter Condition
/*!
 *  This stores one filter condition for TrigNET.
 */

class UtsusemiTrignetCondition
{
private:

public:
    UtsusemiTrignetCondition();
        //!< Constructor
        /*!<
         */
    UtsusemiTrignetCondition( const UtsusemiTrignetCondition& obj );
        //!< Copy Constructor
        /*!<
         */
    ~UtsusemiTrignetCondition();
        //!< Destructor
        /*!<
         */

    Int4 Index;                /**< index of TrigNET event file  */
    Int4 Trigger;               /**< trigger condition */
    Int4 Type;                 /**< type condition  */
    std::string Title;              /**< title  */
    std::string Attr;               /**< attribute for this TrigNet condition  */
    bool IsAnd;                /**< AND condition  */
    std::vector<UInt4> Contents;    /**< Contents */
    double IncrementalVal;     /**< Incremental values to counter  */

    Int4 SetIndex( Int4 ind );
        //!< Sets Index
        /*!<
         *   @param ind (Int4)
         *   @retval -1  given ind is invalid
         *   @retval  0
         */
    Int4 SetTrig( std::string trig );
        //!< Sets trigger
        /*!<
         *   @param trig (std::string)
         *   @retval -1  given trig is invalid
         *   @retval  0
         */
    Int4 SetType( std::string type );
        //!< Sets type
        /*!<
         *   @param type (std::string)
         *   @retval -1  given argument is invalid
         *   @retval  0
         */
    Int4 SetTitle( std::string title );
        //!< Sets title
        /*!<
         *   @param title (std::string)
         *   @retval  0
         */
    Int4 SetAttr( std::string attr );
        //!< Sets attribute
        /*!<
         *   @param attr (std::string)
         *   @retval  0
         */
    Int4 SetCont( std::vector<UInt4> cont );
        //!< Sets contents
        /*!<
         *   @param cont (std::vector<std::string>)
         *   @retval -1  if Trigger/Type is not set
         *   @retval  0
         */
    Int4 SetAnd( bool is_and );
        //!< Sets AND condition
        /*!<
         *   @param is_and (bool)
         *   @retval  0
         */
    Int4 Check(UInt4 index, UInt4 trig, UInt4 type, const std::vector<UInt4>* cond, std::string title="");
        //!< Checks parameters sutisfies given conditions.
        /*!<
         *   @param index (UInt4)
         *   @param trig  (UInt4)
         *   @param type  (UInt4)
         *   @param cond  (const std::vector<UInt4>*)
         *   @param title (std::string)
         *   @retval 1  satisfied condition
         *   @retval -1 not satisfied
         *   @retval 0  ignored
         */
    void Dump();
        //!< Shows all conditions
        /*!<
         *   @param None
         *   @return None
         */
};


//////////////////////////////////
// UtsusemiTrignetCondGroup
/////////////////////////////////

//! Group of Conditions for TrigNet
/*!
 *  This stores several conditions for TrigNET.
 */

class UtsusemiTrignetCondGroup
{
private:

public:
    UtsusemiTrignetCondGroup();
        //!< Constructor
        /*!<
         */
    UtsusemiTrignetCondGroup( const UtsusemiTrignetCondGroup& obj );
        //!< Copy Constructor
        /*!<
         */
    ~UtsusemiTrignetCondGroup();
        //!< Destructor
        /*!<
         */
    std::vector<UtsusemiTrignetCondition>  _TriggerCondArray;  /**< storing TrignetConditions  */
    bool _TriggerCondArrayIsAnd;                          /**< storing AND coditions for each TrignetCondition  */
    std::vector< UInt4 > _TriggerCondArrayAndList;             /**< storing list of TrigNET indexes under AND condition*/
    std::vector< std::vector<Double> > _TimeRangeCondArray;        /**< storing Time conditions  */
    std::vector< std::pair<Double,Double> > _TofRangeCondArray;    /**< storing Tof range conditions  */

    void AppendTofRangeCond( std::pair<Double,Double> tofrange );
        //!< Appends TOF range condition
        /*!<
         *   @param tofrange (std::pair<Double,Double>) start tof and end tof
         *   @return None
         */
    void AppendTimeRangeCond( std::string type, std::vector<Double> timerange );
        //!< Appends Time range condition
        /*!<
         *   type="PASS" : start time is zero, end time is passed time
         *   type="MLF"  : start time and end time are given MLF clock
         *   type="DATE" : start time and end time are given DATE format "YYYY","MM","DD","hh","mm","ss","sub-sec"
         *
         *   @param type (std::string)
         *   @param tofrange (std::vector<Double>) start tof and end tof
         *   @return None
         */
    void AppendTrigCond( UtsusemiTrignetCondition trigcond );
        //!< Appends TrigNET condition
        /*!<
         *   @param trigcond (UtsusemiTrignetCondition)
         *   @return None
         */
    Int4 TrigFilter(UInt4 index, UInt4 trig, UInt4 type, const std::vector<UInt4>* cond);
        //!< Checks TrigNET parameters are sutiffied condition(s)
        /*!<
         *   @param index (UInt4)
         *   @param trig  (UInt4)
         *   @param type  (UInt4)
         *   @param cond  (const std::vector<UInt4>*)
         *   @retval 1  satisfied condition
         *   @retval -1 not satisfied
         *   @retval 0  ignored
         */
    Int4 TimeFilter( Double time_in, Double first_clock );
        //!< Checks Time parameters are sutiffied condition(s)
        /*!<
         *   @param time_in (Double) target clock [MLF clock]
         *   @param first_clock (Double) first clock of the measurement [MLF clock]
         *   @retval 1  satisfied condition
         *   @retval -1 not satisfied
         *   @retval 0  ignored
         */
    Int4 TofFilter( Double tof_in );
        //!< Checks Tof parameters are sutiffied condition(s)
        /*!<
         *   @param time_in (Double) clock [MLF clock]
         *   @retval 1  satisfied condition
         *   @retval -1 not satisfied
         *   @retval 0  ignored
         */
    void MakeCondArrayAndList();
        //!< Makes list of TrigNET indexes under AND condition
        /*!<
         *   @param None
         *   @retval None
         */
    void Dump();

};

//////////////////////////////////
// UtsusemiTrignetCounter
/////////////////////////////////

//! TrigNET counter Conditions
/*!
 *  This stores TrigNET counter conditions.
 *
 *  type : 0=Encoder ABphase, 1=1DIO, 2=2DIOs
 *  ABphases : < DIO Number of A phase, that of B phase >
 *
 *  Val = OrgVal + ConvVal*(Counts) [Unit]
 *  ConditionType : 1: condition range with two values for each case
 *                  2: start, end ,step [ caseId = int(( end-start )/step ) ]
 */

class UtsusemiTrignetCounter
{
private:
    StringTools *stools;
    UInt4 _preTrig;
    UInt4 _preCase;
    UInt4 _trigAR, _trigAD, _trigBR, _trigBD;

public:
    UtsusemiTrignetCounter();
        //!< Constructor
        /*!<
         */
    UtsusemiTrignetCounter( const UtsusemiTrignetCounter& obj );
        //!< Copy Constructor
        /*!<
         */
    ~UtsusemiTrignetCounter();
        //!< Destructor
        /*!<
         */
    Int4 Type;                                /**< storing type  */
    std::vector<UtsusemiTrignetCondition> Triggers; /**< storing UtsusemiTrignetConditions  */
    std::pair<Int4,Int4> ABphases;                 /**< storing AB phases information  */

    Double Counts;       /**< Counts */
    Double ConvVal;      /**< Conversion Value to calculate condition */
    Double OrgVal;       /**< Orginal Value to calculate condition */
    std::string Unit;         /**< Unit of condition  */
    Double StartClock;   /**< Clock at beggining on cyclic increment with clock time spliting */
    bool hasFirstTrigerAsTimeStart; /**< true if first trigger signal as start point for cyclic time slicing comes */
    Int4 ConditionType;  /**< Condition format type   */
    std::vector< std::vector<Double>* > ConditionList; /**< storing Conditions   */
    std::pair< Double, Double > ConditionRange;
    bool ignoreKickerInConditionRange;
    std::pair< Double, Double > CyclicRegion;     /**< region of cyclic counting   */
    bool hasCyclicRegion;
    std::string priorityOnVirtualKicker;

    Int4 SetType( std::string type );
        //!< Sets type of condition format
        /*!<
         *   @param type (std::string)
         *   @return condition type
         */
    Int4 AddAsABphase( UtsusemiTrignetCondition trig );
        //!< Sets AB-phases triggers by by UtsusemiTrignetCondition
        /*!< Using attribute of UtsusemiTrignetCondition, A or B is set.
         *
         *   @param trig (UtsusemiTrignetCondition) trigger event
         *   @retval -1  invalid trigger event
         *   @rerval  0  OK
         */
    Int4 AddTriggers( UtsusemiTrignetCondition trig );
        //!< Adds Trigger condition as a trigger for the counter
        /*!<
         *   @param trig (UtsusemiTrignetCondition)
         *   @return condition type
         */
    Int4 SetConvVal( std::string convval );
        //!< Sets ConvVal
        /*!<
         *   @param ConvVal (std::string)
         *   @retval 0
         */
    Int4 SetOrgVal( std::string orgval, std::string unit_in );
        //!< Sets OrgVal
        /*!<
         *   @param OrgVal (std::string)
         *   @param unit_in (std::string) unit of OrgVal
         *   @retval 0
         */
    Int4 SetVirtualKickerPriority( std::string val);
        //!< Sets which has the priority on choosing case ID for virtual kicker mode
        /*!<
         *   @param val (std::string) "case" or "signal"
         *   @retval 0
         */
    Int4 SetConditionType( std::string val );
        //!< Sets type of condition
        /*!<
         *   @param val (std::string)
         *   @return ConditionType
         */
    Int4 SetConditionList( UInt4 caseId, std::string conts );
        //!< Sets contents of condition
        /*!<
         *   @param caseId (UInt4)
         *   @param conts (std::string)
         *   @retval -1  ConditionType is invalid
         *   @retval  0  OK
         */
    Int4 SetCyclicRegion( std::string begin, std::string end );
    UInt4 SetClock( Double clock );
        //!< Sets clock for cyclic time slicing with trignet signal used as start point for time slicing.
        /*!< This returns the caseId calculated from given clock
         *
         *   @param clock (Double)
         *   @retval 0 to (UTSUSEMIMASKVALUEUINT4-1) :Decided CaseId (last caseId)
         *   @retval UTSUSEMIMASKVALUEUINT4          :This condition should be ignored.
         */
    UInt4 CountEvent( UInt4 index, UInt4 trig, UInt4 type, const std::vector<UInt4>* cond, double clock=0.0);
    UInt4 CountEvent( std::vector<UInt4> index, std::vector<UInt4> trig, std::vector<UInt4> type, const std::vector< std::vector<UInt4>* > &cond);
        //!< Sets parameters decoded from TrigNET event(s) to count up.
        /*!< This returns the caseId calculated from given conditions
         *
         *   @param index (UInt4 or std::vector<UInt4>)
         *   @param trig  (UInt4 or std::vector<UInt4>)
         *   @param type  (UInt4 or std::vector<UInt4>)
         *   @param cond  (std::vector<UInt4>* or std::vector< std::vector<UInt4> >)
         *   @param clock (Double)
         *   @retval 0 to (UTSUSEMIMASKVALUEUINT4-1) :Decided CaseId (last caseId)
         *   @retval UTSUSEMIMASKVALUEUINT4          :This condition should be ignored.
         */
    void Dump();
        //!< Shows counter conditions
        /*!<
         *   @param None
         *   @return None
         */
};

#endif
