#ifndef UTSUSEMIONETRIGNETSORAGE
#define UTSUSEMIONETRIGNETSORAGE

#include "Header.hh"
#include "UtsusemiHeader.hh"
#include <algorithm>
class UtsusemiOneCase
{
public:
    UtsusemiOneCase();
    UtsusemiOneCase(UInt4 _tof, std::vector<UInt4>* _cases );
    UtsusemiOneCase( const UtsusemiOneCase& obj );
    ~UtsusemiOneCase();
    void SetCases( std::vector<UInt4> _cases );
    UInt4 TOF;
    std::vector<UInt4> Cases;
};

////////////////////////////////////
// UtsusemiOneTrignetStorage
///////////////////////////////////

//!  Class to storage the case table for TrigNET
/*!
 *
 */
class UtsusemiOneTrignetStorage
{
private:
    void Initialize(UInt4 _num_of_multh, UInt4 _dio, UInt4 _adc1, UInt4 _adc2, UInt4 _count );
protected:
    std::vector< std::vector< std::vector< UtsusemiOneCase* >* >* > *_DIOCaseTableMulTh; /** [MULTH][frame][Cases] */
    std::vector< std::vector< std::vector< UtsusemiOneCase* >* >* > *_ADC1CaseTableMulTh;
    std::vector< std::vector< std::vector< UtsusemiOneCase* >* >* > *_ADC2CaseTableMulTh;
    std::vector< std::vector< std::vector< UtsusemiOneCase* >* >* > *_COUNTCaseTableMulTh;
    std::vector< std::vector<UInt8> >  _PulseIdTableMulTh;        /** [MULTH][frame] pulseId */
    std::vector< std::vector<Double> > _InstClockTableMulTh;      /** [MULTH][frame] InstClock  */
    std::vector<UInt4> _PulseIdTableMulThIndex;              /** [frame] MulTh index */


    std::vector< std::vector< UtsusemiOneCase* >* >* _DIOCaseTable; /** [frame][Cases]*/
    std::vector< std::vector< UtsusemiOneCase* >* >* _ADC1CaseTable;
    std::vector< std::vector< UtsusemiOneCase* >* >* _ADC2CaseTable;
    std::vector< std::vector< UtsusemiOneCase* >* >* _COUNTCaseTable;

    void ClearTable( std::vector< std::vector< UtsusemiOneCase* >* >* _table );
    void ClearTableMulTh( std::vector< std::vector< std::vector< UtsusemiOneCase* >* >* >* _table );
    void ClearTableMulThAll();
    void Clear();
        //!< Clears all inner tables
        /*!<
         *
         *   @param None
         *   @return None
         */
    std::vector<UInt8> SortPulseIdIndex();
    void _MergeTableOnMulTh( std::vector< std::vector< std::vector< UtsusemiOneCase* >* >* >* _table1,
                             std::vector< std::vector< UtsusemiOneCase* >* >* _table2,
                             UInt4 &_firstCase );

    bool _isUsedFilterCase;
    bool _isUsedCounterCase;
    UInt4 _FrameIndex;
    UInt4 _firstDIOcase;
    UInt4 _firstADC1case;
    UInt4 _firstADC2case;
    UInt4 _firstCOUNTcase;
    bool _isDebug;

public:
    UtsusemiOneTrignetStorage( UInt4 _num_of_multh=2, UInt4 _dio=0, UInt4 _adc1=0, UInt4 _adc2=0, UInt4 _count=0 );
        //!< Constructor
        /*!<
         */
    ~UtsusemiOneTrignetStorage();
        //!< Destructor
        /*!<
         */
    void SetDebugMode( bool isDebug=false ){ _isDebug=isDebug;}
        //!< Sets Debug mode on
        /*!<
         *
         *   @param isDebug (bool)
         *   @return None
         */

    void StartFrame();
        //!< Reset all inner tables for the beginning of analysis trignet data
        /*!<
         *
         *   @param None
         *   @return None
         */
    void StartAFrame(UInt4 _multh);
        //!< Reset all inner tables for one frame to analysis trignet data
        /*!<
         *
         *   @param _multh (UInt4) the openMP thread number
         *   @return None
         */
    bool AddFilterCaseSort( UInt4 _multh, UInt4 _sid2, UInt4 _tof, std::vector<UInt4> _cases );
        //!< Adds caseID calclated from analysis trignet filter data
        /*!<
         *
         *   @param _multh (UInt4) the openMP thread number
         *   @param _sid2  (UInt4) SID2 of an analyzed TrigNET event
         *   @param _tof   (UInt4) TOF of an analyzed TrigNET event
         *   @param _cases (std::vector<UInt4>) cases of an analyzed TrigNET event
         *   @return true  : succeeded
         *   @return false : failed
         */
    bool AddCounterCaseSort( UInt4 _multh, UInt4 _tof, UInt4 _case );
        //!< Adds caseID calclated from analysis trignet counter data
        /*!<
         *
         *   @param _multh (UInt4) the openMP thread number
         *   @param _tof   (UInt4) TOF of an analyzed TrigNET event
         *   @param _case  (UInt4) case of an analyzed TrigNET event
         *   @return true  : succeeded
         *   @return false : failed
         */
    bool AddPulseId( UInt4 _multh, UInt4 _pulseId, Double _instClock=0. );
        //!< Adds Pulse ID encoded from trignet event data
        /*!<
         *
         *   @param _multh     (UInt4) the openMP thread number
         *   @param _pulseId   (UInt4) Pulse ID of TrigNET event
         *   @param _instClock (Double) Instrument Clock of TrigNET event
         *   @return true  : succeeded
         *   @return false : failed
         */

    bool MergeOnMulTh();
        //!< Merges inner case tables for each thread into one table
        /*!<
         *
         *   @param None
         *   @return true  : succeeded
         *   @return false : failed
         */
    bool Merge( std::vector< std::vector<UInt4>* >* _mergedTable, std::vector<bool> isAndFilter, UInt4 _numOfCounterCase, UInt4 _preCase=0 );
        //!< Merges three Filter cases tables and one Counter cases table into one tables
        /*!<
         *
         *   @param _mergedTable      (std::vector<std::vector<UInt4>*>*) results of this merge
         *   @param isAndFilter       (std::vector<bool>) And/Or condition between trignet cases in a filter
         *   @param _numOfCounterCase (UInt4) total number of counter case
         *   @return true  : succeeded
         *   @return false : failed
         */
    std::vector<UInt4> PutMergedTable(UInt4 frm, std::vector<bool> isAndFilter, UInt4 _numOfCounterCase );
        //!< Puts the result of Merge method
        /*!<
         *
         *   @param frm               (UInt4) frame NO
         *   @param isAndFilter       (std::vector<bool>) And/Or condition between trignet cases in a filter
         *   @param _numOfCounterCase (UInt4) total number of counter case
         *   @return std::vector<UInt4>
         */
    std::vector< UInt8 > PulseIdTable;                      /** [frame]  */
    std::vector<Double> InstClockTable;                     /** [frame]  */
    UInt4 _NumOfMulTh;
};
#endif
