#ifndef UTSUSEMIEVENTDATACONVERTERTEMPLATEWITHPH_HH
#define UTSUSEMIEVENTDATACONVERTERTEMPLATEWITHPH_HH

#include "UtsusemiEventDataConverterTemplate.hh"

////////////////////////////////////////////
// UtsusemiEventDataConverterTemplateWithPH
////////////////////////////////////////////

//! Expansion of Template class for Convesion with Pulse Height
/*! 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 UtsusemiEventDataConverterTemplateWithPH:
    public UtsusemiEventDataConverterTemplate<T1,T2>
{
private:
    std::vector< std::vector< std::vector<Int4>* >* > *_PulseHeight;
    UInt4 _MaxChannel;
    bool _isGateNet;

public:
    UtsusemiEventDataConverterTemplateWithPH()
        //!< Constructor
        /*!<
         *
         */
    {
        _MaxChannel = 10000;
        _isGateNet = false;
        _PulseHeight = new std::vector< std::vector< std::vector<Int4>* >* >();
    }

    ~UtsusemiEventDataConverterTemplateWithPH()
        //!< Destructor
        /*!<
         */
    {
        // Delete _PulseHeight
        for (UInt4 th=0;th<(_PulseHeight->size());th++){
            for (UInt4 i=0; i<(_PulseHeight->at(th)->size()); i++){
                if (_PulseHeight->at(th)->at(i)!=NULL){
                    delete _PulseHeight->at(th)->at(i);
                    _PulseHeight->at(th)->at(i)=NULL;
                }
            }
            delete _PulseHeight->at(th);
        }
        delete _PulseHeight;
    }

    void SetHistAllocation()
        //!< Allocation of GSL-Histogram and SetHistBin
        /*!< This executes simple allocation as AllocateGslHist(); SethistBin();
         *   @param None
         *   @return None
         */
    {
        this->AllocateGslHist();
        this->SetHistBin();
        _PulseHeight->resize( (this->_NumOfMulTh), NULL );
        for (UInt4 i=0;i<(this->_NumOfMulTh);i++){
            _PulseHeight->at(i) = new std::vector<std::vector<Int4>*>;
            //_PulseHeight->at(i)->resize( this->_gslHist->size(), NULL );
            //for (UInt4 j=0; j<(this->_gslHist->size()); j++)
            _PulseHeight->at(i)->resize( (this->_EventDecoder->_wirInfo->MaxDetId)+1, NULL );
            for (UInt4 j=0; j<((this->_EventDecoder->_wirInfo->MaxDetId)+1); j++)
                _PulseHeight->at(i)->at(j) = new std::vector<Int4>( _MaxChannel,0 );
        }
        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->_gslHist)).size()){
                        std::cout << this->_MessageTag << " Increment : histId is too large; histId(size)=" << histId << "(" << this->_gslHist->size() << ")"<< std::endl;
                    }else{
                        //std::cout << "histid="<<histId <<",tof="<< tof <<",tof="<<_CaseDecoder->CalcIncrementPosi( &tof, &pixelId, &caseId )<<std::endl;
                        UInt4 isOn = this->_gslHist->at(histId)->Increment( this->_CaseDecoder->CalcIncrementPosi( &tof, &pixelId, &caseId ),
                                                                            ThNum,
                                                                            this->_EventDecoder->CalcIncrementVal( &tof, &pixelId ) );
                        if (isOn==0){
                            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<_MaxChannel) ) (_PulseHeight->at(ThNum)->at( this->_EventDecoder->ConvertPixelIdToDetId( pixelId ) )->at( ph ) )++;
                        }
                    }
                }else{
                    //std::cout << "caseId=" << caseId << std::endl;
                }
            }else{
                //std::cout << "ret=" << ret << std::endl;
            }
        }
    }

    std::vector<Int4> PutPulseHeight( UInt4 det_id )
        //!< Put Pulse Height data for a PSD
        /*!< Before using this method, target ElementContainer must be created.
         *
         *   @param det_id (UInt4) outer detId id for _PulseHeight
         *   @retval std::vector<Int4>
         */
    {
        std::vector<Int4> ret( _MaxChannel, 0 );
        if (det_id>=(_PulseHeight->at(0)->size()))
            std::cout << "UtsusemiEventDataConverterTemplatePH::PutPulseHeight >> detId is invalid(" << det_id << ":" << _PulseHeight->at(0)->size() << ")" << std::endl;
        else{
            for (UInt4 j=0;j<_MaxChannel;j++)
                for (UInt4 th=0;th<(this->_NumOfMulTh);th++)
                    ret[j] += _PulseHeight->at(th)->at(det_id)->at(j);
        }
        return ret;
    }

    void SetMaxOfChannels( UInt4 max_channel=4096 ){ _MaxChannel = max_channel; }
        //!< Sets maximum number of channels for Pulse Height
        /*!<
         *   @param max_channels (UInt4) maximum number of channels
         *   @retval None
         */
    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
