#ifndef UTSUSEMIEVENTDATACONVERTERTEMPLATEWITHPHDEP_HH
#define UTSUSEMIEVENTDATACONVERTERTEMPLATEWITHPHDEP_HH

#include "UtsusemiEventDataConverterTemplate.hh"

////////////////////////////////////////////
// UtsusemiEventDataConverterTemplateWithPHDep
////////////////////////////////////////////

//! Expansion of Template class for Convesion with Pulse Height Dependency
/*! from EventData to Histogram on offline.
 *  - read EvnetDataFile
 *  - Decode Event data using Decode module
 *  - Increment to gls histogram and make Pulse Height
 *  - Put Pulse Height into HeaderBase for each ElementContainer
 *  This template requires the instanse successing UtsusemiNeutronEventDecorder.
 */

template <typename T1, typename T2>
class UtsusemiEventDataConverterTemplateWithPHDep:
    public UtsusemiEventDataConverterTemplate<T1,T2>
{
private:
protected:
    bool _isGateNet;
    std::vector<UInt4> _PulseHeightBin;
    UInt4 _PulseHeightMin;
    UInt4 _PulseHeightMax;
    UInt4 _PulseHeightStep;
    UInt4 _PulseHeightNum;
public:
    UtsusemiEventDataConverterTemplateWithPHDep()
        //!< Constructor
        /*!<
         *
         */
    {
        _isGateNet = false;
    }

    ~UtsusemiEventDataConverterTemplateWithPHDep()
        //!< Destructor
        /*!<
         */
    {
    }

    void SetPulseHeightRange( UInt4 ph_min, UInt4 ph_max, UInt4 ph_bin )
    {
        if (ph_min>ph_max){
            UInt4 tmp = ph_max;
            ph_max = ph_min;
            ph_min = tmp;
        }

        _PulseHeightBin.clear();
        for (UInt4 ph=ph_min; ph<(ph_max+1); ph+=ph_bin)
            _PulseHeightBin.push_back( ph );

        _PulseHeightMin = ph_min;
        _PulseHeightMax = _PulseHeightBin.back();
        _PulseHeightStep = ph_bin;
        _PulseHeightNum = (UInt4)(_PulseHeightBin.size())-1;
    }
    void SetHistAllocation()
        //!< Allocation of GSL-Histogram and SetHistBin
        /*!< This executes simple allocation as AllocateGslHist(); SethistBin();
         *   @param None
         *   @return None
         */
    {
        UInt4 numOfPixel = (this->_numOfInnerPixels)*((UInt4)(_PulseHeightBin.size())-1);
        this->AllocateGslHist(numOfPixel,1);

        //this->SetHistBin();
        std::vector<UInt4> outerPixelIdList = this->_EventDecoder->PutPixelIdList(true);
        for (UInt4 i=0; i<outerPixelIdList.size(); i++){
            for (UInt4 j=0; j<(_PulseHeightBin.size()-1); j++){
                UInt4 inner_id = (this->_EventDecoder->ConvertPixelIdToInnerId(outerPixelIdList[i]))*((UInt4)(_PulseHeightBin.size())-1) + j;
                this->SetHistBin( inner_id, this->_EventDecoder->PutHistBin( outerPixelIdList[i] ));
            }
        }
        this->InitTimeDependBackGroundList();
    }

    void Increment(UInt4 daqId, UInt4 moduleNo, const UChar* data, UInt4 size, UInt4 ThNum, std::vector<Double>* Offset, std::vector<UInt4>* Case )
        //!< Increment intensity with Pulse Height
        /*!< Increment intensity of histogram by using information from decoded event
         *
         *   @param daqId (UInt4) DAQ id
         *   @param moduleNo (UInt4) module No
         *   @param data (UChar*) event data
         *   @param size (UInt4) size of event data
         *   @param ThNum (UInt4) thread number
         *   @param Offset (Double) offset value
         *   @retval None
         */
    {
        UInt4 index = 0;
        UInt4 pixelId = 0;
        Double tof = 0.0;
        UInt4 caseId = 0;
        UInt4 histId = 0;
        UInt4 ret = 0;

        this->_EventDecoder->ClearPrevT0Event(ThNum);
        for (UInt4 i=0; i<size; i++){
            index = i*(this->_eventSize);

            ret = this->_EventDecoder->DecodeEventData( daqId, moduleNo, (data+index), &pixelId, &tof, Offset, ThNum );

            if (this->_EventDecoder->IsNeutronEvent(ret)){

            if (Case==NULL) caseId = 1;
                else if (Case->size()==1) caseId = Case->at(0);
                else caseId = this->_CaseDecoder->GetCaseFromTof( pixelId, &tof, Case );

                if (caseId!=0){
                    histId = this->_numOfInnerPixels*(caseId-1) + this->_EventDecoder->ConvertPixelIdToInnerId( pixelId );
                    if ((histId+1)>(this->_EventDecoder->PutNumOfInnerPixels())){
                        std::cout << this->_MessageTag << " Increment : histId is too large; histId(size)=" << histId << "(" << this->_EventDecoder->PutNumOfInnerPixels() << ")"<< std::endl;
                    }else{
                        //std::cout << "histid="<<histId <<",tof="<< tof <<",tof="<<_CaseDecoder->CalcIncrementPosi( &tof, &pixelId, &caseId )<<std::endl;
                        UInt4 k = 0;
                        UInt4 ph = 0;
                        if (_isGateNet){
                            k = (UInt4)( *(data+index+5)&0xc0 )*64;
                            ph = k + (UInt4)( *(data+index+6)&0x0f )*256
                               + (UInt4)( *(data+index+7) );
                        }else{
                            // decode neutron event of NeuNET
                            k = (UInt4)( *(data+index+6) )/16;
                            ph = (UInt4)( *(data+index+5) ) * 16 +  k
                               + (UInt4)( *(data+index+7) ) + 256 * ( (UInt4( *(data+index+6) ) )-(k*16) );
                        }
                        if ((ph>=_PulseHeightMin)&&(ph<=_PulseHeightMax)){
                            histId = (ph - _PulseHeightMin)/_PulseHeightStep + histId*_PulseHeightNum;
                            //std::cout << "## histId="<<histId<<std::endl;
                        }else{
                            //std::cout << "#### Pulse Height is out of range" << std::endl;
                            continue;
                        }
                        if (histId<(*(this->_gslHist)).size()){
                            UInt4 isOn = this->_gslHist->at(histId)->Increment( this->_CaseDecoder->CalcIncrementPosi( &tof, &pixelId, &caseId ),
                                                                                ThNum,
                                                                                this->_EventDecoder->CalcIncrementVal( &tof, &pixelId ) );
                            //if (isOn!=0) std::cout << "#### TOF is out of range"<<std::endl;
                        }else{
                            std::cout << "#### HistId is Over "<<histId<< " ("<< this->_gslHist->size() <<")"<<std::endl;
                        }
                    }
                }else{
                    //std::cout << "caseId=" << caseId << std::endl;
                }
            }else{
                //std::cout << "ret=" << ret << std::endl;
            }
        }
    }

void SetIsGateNet( bool isGateNet=false){ _isGateNet = isGateNet; }
    //!< Sets maximum number of channels for Pulse Height
    /*!<
     *   @param isGateNet   (bool)  whether this data comes from GateNET or not.
     *   @retval None
     */

};
#endif
