#ifndef UTSUSEMIDETECTORINFOEDITORTEMPLATE_HH
#define UTSUSEMIDETECTORINFOEDITORTEMPLATE_HH

#include "UtsusemiAnaEnvironReader.hh"
#include "UtsusemiHeader.hh"
#include "StringTools.hh"


//////////////////////////////////
// UtsusemiDetectorInfoEditorTemplate
/////////////////////////////////

//!
/*!
 *
 */

template <typename T1>
class UtsusemiDetectorInfoEditorTemplate
{
private:
    std::string _MessageTag;
    void Initialize(){
        _DE = NULL;
        _stools = new StringTools();
        _MessageTag = "UtsusemiDetectorInfoEditorTemplate::";
        _detectorInfoPath = "";

    }
    bool _CheckDEStatus( std::string method ){
        if (_DE==NULL){
            UtsusemiError( _MessageTag+method+" >> SetRunNo is Not done." );
            return false;
        }
        if (_DE->_Status==false){
            UtsusemiError( _MessageTag+method+" >> Not ready " );
            return false;
        }
        return true;
    }

    StringTools* _stools;
    std::string _detectorInfoPath;

protected:
    T1* _DE;

public:
    UtsusemiDetectorInfoEditorTemplate(){
        Initialize();
        _DE = new T1();
    }
    UtsusemiDetectorInfoEditorTemplate(std::string dfile, bool workAsReader){
        Initialize();
        _DE = new T1(dfile, workAsReader);
    }
    ~UtsusemiDetectorInfoEditorTemplate(){
        if (_DE!=NULL) delete _DE;
        delete _stools;
    }

    //////////////////////////////////////////////////////////////////////////
    // public variables
    //////////////////////////////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////////////////
    // public functions
    //////////////////////////////////////////////////////////////////////////

    bool SetRunNo( UInt4 runNo, UInt4 mode_no=0, std::string env_file="" ){
        return SetRunNo( _stools->UInt4ToString( runNo ),
                         _stools->UInt4ToString( mode_no ),
                         env_file );
    }
        //!< sets run No, mode number and environ_ana.xml
        /*!< This set run number and read environ_ana.xml
         *   to select WiringInfo and DetecorInfo sutable for the run number.
         *   If evn_file is empty(), this uses python-utsusemi/XXX/ana/xml(_UtsusemiUserXmlPath)/environ_ana.xml.
         *   If evn_file is set, the path of env_file is used as _UtsusemiUserXmlPath.
         *
         *   @param runNo    (UInt4)  run number
         *   @param mode_no  (UInt4)  mode number
         *   @param env_file (std::string) environ_ana.xml which includes several WiringInfo and DetectorInfo for each run number.
         *   @retval true     : succeeded
         *   @retval false    : failed
         */

    bool SetRunNo( std::string runNos, std::string mode_no="0", std::string env_file="" ){
        bool ret = false;
        if (runNos.empty()){
            return false;
        }

        std::vector<UInt4> vec_runNos = DivMultiContUInt4( runNos );
        if (vec_runNos.empty()){
            UtsusemiError(_MessageTag+"SetRunNo >> given runNo is invalid (params="+runNos+")");
            return false;
        }
        UInt4 runNo = vec_runNos[0];
        UInt4 modeNo = _stools->StringToUInt4( mode_no );
        UtsusemiAnaEnvironReader *UAR = new UtsusemiAnaEnvironReader( runNo, true );
        if (UAR->_Status){
        }else{
            delete UAR;
            UAR = new UtsusemiAnaEnvironReader( env_file );
        }
        if (UAR->_Status){
            std::vector<std::string> pfiles = UAR->PutParamFiles( runNo, modeNo, true );
            if (pfiles.empty()){
            }else{
                _detectorInfoPath = pfiles[1];
                ret = true;
            }
        }else{
            delete UAR;
            return false;
        }
        delete UAR;

        if (_DE!=NULL) delete _DE;
        _DE = new T1();

        UtsusemiMessage( _MessageTag+"SetRunNo >> _detectorfoPath = "+_detectorInfoPath );
        if (_DE->Read(_detectorInfoPath)){
            ret = true;
        }else{
            ret = false;
        }

        return ret;
    }
        //!< sets run No, mode number and environ_ana.xml
        /*!< This set run number and read environ_ana.xml
         *   to select WiringInfo and DetecorInfo sutable for the run number.
         *   If evn_file is empty(), this uses python-utsusemi/XXX/ana/xml(_UtsusemiUserXmlPath)/environ_ana.xml.
         *   If evn_file is set, the path of env_file is used as _UtsusemiUserXmlPath.
         *       bool SetRunNo( std::string runNos, std::string env_file="" )
         *
         *   @param runNos   (std::string) run numbers. format : "1234,1235"
         *   @param mode_no  (std::string) mode number
         *   @param env_file (std::string) environ_ana.xml which includes several WiringInfo and DetectorInfo for each run number.
         *   @retval true     : succeeded
         *   @retval false    : failed
         */
    bool SetRunNo( UInt4 runNo, std::string dfile ){
        if (dfile=="-") return SetRunNo( runNo );

        bool ret = true;

        _detectorInfoPath = FindParamFilePath( dfile );
        if (_detectorInfoPath=="") ret = false;

        if (ret){
            if (_DE->Read(_detectorInfoPath)){
                ret = true;
            }else{
                ret = false;
            }
        }else{
            UtsusemiError( _MessageTag+ "Failed to read DetectorInfo="+_detectorInfoPath );
            _detectorInfoPath = "";
        }

        return ret;
    }
        //!< sets run No and environ_ana.xml
        /*!< This set run number and read environ_ana.xml
         *   to select WiringInfo and DetecorInfo sutable for the run number.
         *
         *   @param runNo    (UInt4)  run number
         *   @param dfile    (std::string) set directly DetectorInfo file
         *   @retval true     : succeeded
         *   @retval false    : failed
         */
    bool SetRunNoWithDetectorInfo( std::string runNos, std::string dfile ){
        if ((dfile=="-")||(dfile=="")) return SetRunNo( runNos );

        bool ret = false;
        if (runNos.empty()){
            return false;
        }

        std::vector<UInt4> vec_runNos = DivMultiContUInt4( runNos );
        if (vec_runNos.empty()){
            UtsusemiError(_MessageTag+"SetRunNo >> given runNo is invalid (params="+runNos+")");
            return false;
        }
        UInt4 runNo = vec_runNos[0];

        _detectorInfoPath = FindParamFilePath( dfile );
        if (_detectorInfoPath!=""){
            if (_DE!=NULL) delete _DE;
            _DE = new T1();

            if (_DE->Read(_detectorInfoPath)){
                ret = true;
            }else{
                ret = false;
            }
        }else{
            UtsusemiError( _MessageTag+ "Failed to read DetectorInfo="+_detectorInfoPath );
            _detectorInfoPath = "";
        }

        return ret;
    }
        //!< sets run No and DetectorInfo
        /*!< This set run number to select WiringInfo sutable for the run number.
         *
         *   @param runNos   (std::string) run numbers "1234,5678"
         *   @param dfile    (std::string) set directly DetectorInfo file
         *   @retval true     : succeeded
         *   @retval false    : failed
         */
    std::string MakeTempDetectorInfo( std::string _path="" ){
        if (!_CheckDEStatus("MakeTempDetectorInfo")) return "";

        if (!UtsusemiEnvGetDebugMode())
            return _DE->OutXml();

        time_t timer;
        time(&timer);
        UInt4 t_timer = ((UInt4)timer)%1000000;

        std::string clock_st( _stools->UInt4ToString(t_timer) );
        pid_t proc_id = getpid();
        UInt4 procid(proc_id);
        std::string procid_st( _stools->UInt4ToString(procid) );

        char pathc[200];
        char temp[100];
        std::snprintf( temp, sizeof(temp), UTSUSEMIUSERPRIVTEMPDETECTORINFOBASE.c_str(), procid_st.c_str(), clock_st.c_str() );
        if (_path==""){
            std::string dir_path = FindTempFilePath();
            if (dir_path=="")
                std::snprintf( pathc, sizeof(pathc), "%s", temp );
            else
                std::snprintf( pathc, sizeof(pathc), "%s/%s", dir_path.c_str(), temp );
        }else
            std::snprintf( pathc, sizeof(pathc), "%s/%s", _path.c_str(), temp );
        std::string path( pathc );
        //std::cout << "Output path="+path<<std::endl;

        if (_DE->Write( path )){
            UtsusemiMessage( _MessageTag+"MakeTempDetectorInfo : Temporal WiringInfo file path = "+path );
        }else{
            UtsusemiError( _MessageTag+" Fails to save temporal detector info file as "+path);
            path = "";
        }

        return path;
    }
        //!< make and save the temporal detector info to create histogram
        /*!< this returns a path of the saved temporal detector info file
         *       std::string MakeTempDetectorInfo()
         *
         *   @param None
         *   @return (std::string) : the path of output detector info file
         */
    T1* PutDE(){ return _DE; }
        //!< Put DetectorInfoEditorXXX
        /*!<
         *
         *   @param None
         *   @return DetectorInfoXXX
         */
    std::vector<Int4> PutBankIdList(){
        if (_CheckDEStatus("PutBankIdList")) return _DE->PutBankIdList();
        std::vector<Int4> empty;
        return empty;
    }
        //!< Put Bank ID list described in the detector info
        /*!<
         *
         *   @param None
         *   @return std::vector<Int4>
         */
    std::vector<std::string> PutBankInfo( UInt4 bankId ){
        if (_CheckDEStatus("PutBankInfo")) return _DE->PutBankInfo(bankId);
        std::vector<std::string> empty;
        return empty;
    }
        //!< Put bank information described in the detector info
        /*!<
         *
         *   @param bankId (UInt4) The id of the bank.
         *   @return std::vector<std::string>
         */
    Double PutInstL1(){
        if (_CheckDEStatus("PutInstL1")) return _DE->PutInstL1();
        return 0.0;
    }
        //!< Put L1 [mm] described in the detector info
        /*!<
         *
         *   @param None
         *   @return double L1 [mm]
         */
    Double PutInstTypicalL2(){
        if (_CheckDEStatus("PutInstTypicalL2")) return _DE->PutInstTypicalL2();
        return 0.0;
    }
        //!< Put the typical L2 [mm] described in the detector info
        /*!<
         *
         *   @param None
         *   @return double L2 [mm]
         */
    Double PutInstTypicalDS(){
        if (_CheckDEStatus("PutInstTypicalDS")) return _DE->PutInstTypicalDS();
        return 0.0;
    }
        //!< Put the typical area of one pixel described in the detector info
        /*!<
         *
         *   @param None
         *   @return double the typical area [mm*mm]
         */
    bool SetInstInfoL1( Double _L1 ){
        if (_CheckDEStatus("SetInstInfoL1")) return _DE->SetInstInfoL1( _L1 );
        return false;
    }
        //!< Set L1 [mm] to be described in the detector info
        /*!<
         *
         *   @param _L1 (Double) L1
         *   @retval true succeeded.
         *   @retval false failed.
         */
    bool SetInstInfoSamplePosition( Double _px, Double _py, Double _pz ){
        if (_CheckDEStatus("SetInstInfoSamplePosition"))
            return _DE->SetInstInfoSamplePosition( _px, _py, _pz );
        return false;
    }
        //!< Set the sample position [mm] to be described in the detector info
        /*!<
         *
         *   @param _px (Double) X position [mm]
         *   @param _py (Double) Y position [mm]
         *   @param _pz (Double) Z position [mm]
         *   @retval true succeeded.
         *   @retval false failed.
         */
};

#endif
