#include "UtsusemiAnaEnvironReader.hh"

//////////////////////////////////////////////////////////
AnaEnvironPeriodInfo::AnaEnvironPeriodInfo(){
    Period.first=0;
    Period.second=0;
    WiringInfoList.clear();
    DetectorInfoList.clear();
    MaskInfoList.clear();
}
//////////////////////////////////////////////////////////
AnaEnvironPeriodInfo::AnaEnvironPeriodInfo( const AnaEnvironPeriodInfo& obj ){
    Period.first = obj.Period.first;
    Period.second = obj.Period.second;
    WiringInfoList.resize( obj.WiringInfoList.size(),"" );
    DetectorInfoList.resize( obj.DetectorInfoList.size(),"" );
    MaskInfoList.resize( obj.DetectorInfoList.size(),"" );
    copy( obj.WiringInfoList.begin(), obj.WiringInfoList.end(), WiringInfoList.begin() );
    copy( obj.DetectorInfoList.begin(), obj.DetectorInfoList.end(), DetectorInfoList.begin() );
    copy( obj.MaskInfoList.begin(), obj.MaskInfoList.end(), MaskInfoList.begin() );

}
//////////////////////////////////////////////////////////
AnaEnvironPeriodInfo::~AnaEnvironPeriodInfo(){
}

//////////////////////////////////////////////////////////
UtsusemiAnaEnvironReader::UtsusemiAnaEnvironReader( std::string envFileName, std::string UtsusemiUserXmlPath ){
    _Status = false;
    Initialize();
    if (Read( envFileName, UtsusemiUserXmlPath )){
        _Status = true;
    }else{
        UtsusemiError(_MessageTag+"constructor >>  ana_environ is not found. PATH="+envFileName);
    }
}
//////////////////////////////////////////////////////////
UtsusemiAnaEnvironReader::UtsusemiAnaEnvironReader( UInt4 runNo, bool isQuiet ){
    _Status = false;
    _isQuiet = isQuiet;
    Initialize();
    if (Read( runNo, isQuiet )){
        _Status = true;
    }else{
        if (!_isQuiet)
            UtsusemiError(_MessageTag+"constructor >>  ana_environ is not found in given runNo folder");
    }
}
//////////////////////////////////////////////////////////
UtsusemiAnaEnvironReader::~UtsusemiAnaEnvironReader(){
    if (_parser!=NULL) delete _parser;
    if (_stools!=NULL) delete _stools;
}
const std::string UtsusemiAnaEnvironReader::KEY_READ_XML="KEYREADXML";

const std::string UtsusemiAnaEnvironReader::ENV="/environ";
const std::string UtsusemiAnaEnvironReader::ENV_ANA="analysis";
const std::string UtsusemiAnaEnvironReader::ENV_ANA_INSTCODE="instcode";
const std::string UtsusemiAnaEnvironReader::ENV_ANA_ORGWIRINGINFO="originwiringfile";
const std::string UtsusemiAnaEnvironReader::ENV_ANA_ORGDETECTORINFO="positioningfile";
const std::string UtsusemiAnaEnvironReader::ENV_ANA_FILEHISTORY="infofilehistory";
const std::string UtsusemiAnaEnvironReader::ENV_ANA_FILEHISTORY_PERIOD="period";
const std::string UtsusemiAnaEnvironReader::ENV_ANA_FILEHISTORY_PERIOD_STARTRUN="startrun";
const std::string UtsusemiAnaEnvironReader::ENV_ANA_FILEHISTORY_PERIOD_ENDRUN="endrun";
const std::string UtsusemiAnaEnvironReader::ENV_ANA_FILEHISTORY_PERIOD_WIRINGINFO="wiringinfo";
const std::string UtsusemiAnaEnvironReader::ENV_ANA_FILEHISTORY_PERIOD_DETECTORINFO="detectorinfo";
const std::string UtsusemiAnaEnvironReader::ENV_ANA_FILEHISTORY_PERIOD_MASKINFO="maskinfo";
const std::string UtsusemiAnaEnvironReader::ENV_ANA_FILEHISTORY_PERIOD_PARAMS="params";
const std::string UtsusemiAnaEnvironReader::ENV_ANA_FILEHISTORY_PERIOD_PARAMS_AT_MODE="mode";

//////////////////////////////////////////////////////////
void UtsusemiAnaEnvironReader::Initialize(){
    _parser = NULL;
    _stools = new StringTools();
    _MessageTag = "UtsusemiAnaEnvironReader::";
    _InstCode = "";
    _OrgWiringInfoFile = "";
    _OrgDetectorInfoFile = "";
    _OrgMaskInfoFile = "";

    _AnaEnvironFile = "";
    _UtsusemiParamFolder = "";
    _isQuiet = false;
}
//////////////////////////////////////////////////////////
bool UtsusemiAnaEnvironReader::Read( std::string envFileName, std::string UtsusemiUserXmlPath ){
    _AnaEnvironFile = "";
    if (envFileName=="") envFileName=UTSUSEMIDEFAULTANAENVIRONFILE;

    // if envFileName includes full path to file.
    std::string::size_type ind_sl = envFileName.find_last_of("/");
    if (ind_sl!=std::string::npos){
        UtsusemiUserXmlPath = envFileName.substr(0, ind_sl);
        envFileName = envFileName.substr(ind_sl);
        UtsusemiMessage( _MessageTag+"introduced Xml Path = "+UtsusemiUserXmlPath);
        UtsusemiMessage( _MessageTag+"introduced environ_ana.xml="+envFileName);
    }

    std::string path = FindParamFilePath( envFileName, UtsusemiUserXmlPath );
    if (path==""){
        UtsusemiError(_MessageTag+"Read >> cannot find file in given path ["+UtsusemiUserXmlPath+"/"+envFileName);
        return false;
    }
    _AnaEnvironFile = path;
    _UtsusemiParamFolder = UtsusemiUserXmlPath;
    //std::cout << "_AnaEnvironFile ="+_AnaEnvironFile<<std::endl;

    return Parse( _AnaEnvironFile );
}
//////////////////////////////////////////////////////////
bool UtsusemiAnaEnvironReader::Read( UInt4 runNo, bool isQuiet ){
    _AnaEnvironFile = "";
    _UtsusemiParamFolder = "";
    _isQuiet=isQuiet;

    std::string path = "";
    std::string utsusemi_path = FindEnvironFolderInRunData( runNo );
    if (utsusemi_path!=""){
        const boost::filesystem::path dpath( utsusemi_path.c_str() );
        if ((boost::filesystem::exists( dpath ))&&(boost::filesystem::is_directory( dpath ))){
            BOOST_FOREACH( const boost::filesystem::path& p,
                           std::make_pair( boost::filesystem::directory_iterator( dpath ),
                                           boost::filesystem::directory_iterator())){
                if (!boost::filesystem::is_directory(p)){
                    //std::cout << "found file p.string()="<<p.string()<<std::endl;
                    if (p.filename()==UTSUSEMIDEFAULTANAENVIRONFILE) path = p.string();
                }
            }
        }
    }

    if (path==""){
        if (!_isQuiet)
            UtsusemiWarning(_MessageTag+"Read >> Cannot Found "+UTSUSEMIDEFAULTANAENVIRONFILE+" in run folder");
        //return false;
        return Read("","");
    }
    _AnaEnvironFile = path;
    _UtsusemiParamFolder = utsusemi_path;
    //std::cout << "_AnaEnvironFile = "+_AnaEnvironFile<<std::endl;
    //std::cout << "_UtsusemiParamFolder = "+_UtsusemiParamFolder;
    return Parse( _AnaEnvironFile );
}
//////////////////////////////////////////////////////////
bool UtsusemiAnaEnvironReader::Parse( std::string envFilePath ){
    if (_parser!=NULL) delete _parser;
    _parser = new BoostXmlParser();
    _parser->SetQuiet( !(UtsusemiEnvGetDebugMode()) );
    if (_parser->Load( KEY_READ_XML, envFilePath ) ){
        if (_parser->hasPath( KEY_READ_XML, ENV )){
            std::string env_ana = ENV+"/"+ENV_ANA;
            if (_parser->hasPath( KEY_READ_XML, env_ana )){
                std::string instcode = env_ana+"/"+ENV_ANA_INSTCODE;
                if (_parser->hasPath( KEY_READ_XML, instcode )){
                    _InstCode = _parser->PutContent( KEY_READ_XML, instcode, "" );
                }else{
                    UtsusemiError(_MessageTag+"Read >> "+ENV_ANA_INSTCODE+" not found.");
                    return false;
                }

                std::string orgwiringfile = env_ana+"/"+ENV_ANA_ORGWIRINGINFO;
                if (_parser->hasPath( KEY_READ_XML, orgwiringfile )){
                    _OrgWiringInfoFile = _parser->PutContent( KEY_READ_XML, orgwiringfile, "" );
                }else{
                    UtsusemiError(_MessageTag+"Read >> "+ENV_ANA_ORGWIRINGINFO+" not found.");
                    return false;
                }

                std::string orgdetectfile = env_ana+"/"+ENV_ANA_ORGDETECTORINFO;
                if (_parser->hasPath( KEY_READ_XML, orgdetectfile )){
                    _OrgDetectorInfoFile = _parser->PutContent( KEY_READ_XML, orgdetectfile , "" );
                }else{
                    UtsusemiError(_MessageTag+"Read >> "+ ENV_ANA_ORGDETECTORINFO +" not found.");
                    return false;
                }

                std::string filehistory = env_ana+"/"+ENV_ANA_FILEHISTORY;
                if (_parser->hasPath( KEY_READ_XML, filehistory )){
                    std::string period = filehistory+"/"+ENV_ANA_FILEHISTORY_PERIOD;
                    std::vector<std::string> startrun_list_s = _parser->PutAttValList( KEY_READ_XML, period, ENV_ANA_FILEHISTORY_PERIOD_STARTRUN );
                    if (startrun_list_s.empty()){
                        UtsusemiError(_MessageTag+"Read >> "+period+" not found.");
                        return false;
                    }else{
                        for (std::vector<std::string>::iterator it=startrun_list_s.begin(); it!=startrun_list_s.end(); ++it){
                            std::string a_period = period+","+ENV_ANA_FILEHISTORY_PERIOD_STARTRUN+"="+(*it);
                            AnaEnvironPeriodInfo hist;
                            hist.Period.first = _stools->StringToUInt4( *it );
                            hist.Period.second= _stools->StringToUInt4( _parser->PutContent( KEY_READ_XML, a_period, ENV_ANA_FILEHISTORY_PERIOD_ENDRUN ) );

                            std::string a_period_params = a_period+"/"+ENV_ANA_FILEHISTORY_PERIOD_PARAMS;
                            if (_parser->hasPath( KEY_READ_XML,a_period_params)){
                                std::vector<std::string> pattern_list = _parser->PutAttValList( KEY_READ_XML, a_period_params, ENV_ANA_FILEHISTORY_PERIOD_PARAMS_AT_MODE );
                                for (std::vector<std::string>::iterator it_pat=pattern_list.begin(); it_pat!=pattern_list.end(); ++it_pat ){
                                    UInt4 pattern_no = _stools->StringToUInt4( *it_pat );
                                    if ((pattern_no+1)>(hist.WiringInfoList.size())){
                                        hist.WiringInfoList.resize( pattern_no+1, "");
                                        hist.DetectorInfoList.resize( pattern_no+1, "");
                                        hist.MaskInfoList.resize( pattern_no+1, "");
                                    }
                                    std::string a_pattern = a_period_params+","+ENV_ANA_FILEHISTORY_PERIOD_PARAMS_AT_MODE+"="+(_stools->UInt4ToString( pattern_no ));
                                    hist.WiringInfoList[ pattern_no ] = _parser->PutContent( KEY_READ_XML, a_pattern+"/"+ENV_ANA_FILEHISTORY_PERIOD_WIRINGINFO, "" );
                                    hist.DetectorInfoList[ pattern_no ] = _parser->PutContent( KEY_READ_XML, a_pattern+"/"+ENV_ANA_FILEHISTORY_PERIOD_DETECTORINFO, "" );
                                    if (_parser->hasPath( KEY_READ_XML,a_period_params+"/"+ENV_ANA_FILEHISTORY_PERIOD_MASKINFO))
                                        hist.MaskInfoList[ pattern_no ] = _parser->PutContent( KEY_READ_XML, a_pattern+"/"+ENV_ANA_FILEHISTORY_PERIOD_MASKINFO, "" );
                                }
                            }else{
                                hist.WiringInfoList.clear();
                                hist.DetectorInfoList.clear();
                                hist.MaskInfoList.clear();
                                hist.WiringInfoList.push_back( _parser->PutContent( KEY_READ_XML, a_period+"/"+ENV_ANA_FILEHISTORY_PERIOD_WIRINGINFO, "" ) );
                                hist.DetectorInfoList.push_back( _parser->PutContent( KEY_READ_XML, a_period+"/"+ENV_ANA_FILEHISTORY_PERIOD_DETECTORINFO, "" ) );
                                hist.MaskInfoList.push_back( "" );
                                if (_parser->hasPath( KEY_READ_XML,a_period+"/"+ENV_ANA_FILEHISTORY_PERIOD_MASKINFO))
                                    hist.MaskInfoList[0] = _parser->PutContent( KEY_READ_XML, a_period+"/"+ENV_ANA_FILEHISTORY_PERIOD_MASKINFO, "" );
                            }
                            _FileHistory.push_back( hist );
                        }
                    }
                }else{
                    UtsusemiError(_MessageTag+"Read >> "+filehistory +" not found.");
                    return false;
                }
            }else{
                UtsusemiError(_MessageTag+"Read >> analysis not found.");
                return false;
            }
        }else{
            UtsusemiError(_MessageTag+"Read >> environ not found.");
            return false;
        }
    }else{
        UtsusemiError(_MessageTag+"Read >> file not found.");
        return false;
    }
    return true;
}
//////////////////////////////////////////////////////////
std::vector<std::string> UtsusemiAnaEnvironReader::
PutParamFiles( UInt4 runNo, UInt4 mode_no, bool isFullPath ){
    std::vector<std::string> ret;
    if (_FileHistory.empty()){
        UtsusemiError(_MessageTag+"PutParamFiles : no param file history.");
        return ret;
    }
    bool isFound = false;
    UInt4 target_i = 0;
    if (runNo!=0){
        for (UInt4 i=0; i<(_FileHistory.size()); i++){
            if ( (runNo>=(_FileHistory[i].Period.first))&&(runNo<=(_FileHistory[i].Period.second)) ){
                target_i = i;
                isFound = true;
                break;
            }
        }
    }else{
        UInt4 last_period=0;
        for (UInt4 i=0; i<(_FileHistory.size()); i++){
            if (last_period<=_FileHistory[i].Period.second){
                last_period = _FileHistory[i].Period.second;
                target_i=i;
            }
        }
        if (last_period!=0) isFound = true;
    }

    if (isFound){
        if (_FileHistory[target_i].WiringInfoList.empty()){
        }else{
            if ( mode_no>=(_FileHistory[target_i].WiringInfoList.size()) ) mode_no = 0;

            ret.push_back( _FileHistory[target_i].WiringInfoList[mode_no] );
            ret.push_back( _FileHistory[target_i].DetectorInfoList[mode_no] );
            if ( _FileHistory[target_i].MaskInfoList[mode_no]!="" )
                ret.push_back( _FileHistory[target_i].MaskInfoList[mode_no] );
        }
        if (isFullPath){
            for (UInt4 i=0; i<ret.size(); i++){
                std::string path = FindParamFilePath( ret[i], _UtsusemiParamFolder );
                if (path!="") ret[i] = path;
            }
        }
    }

    return ret;
}
//////////////////////////////////////////////////////////
void UtsusemiAnaEnvironReader::Dump(){
    std::cout << "InstCode= "+_InstCode << std::endl;
    std::cout << "original wiringInfo = "+_OrgWiringInfoFile << std::endl;
    std::cout << "original detectorInfo = "+_OrgDetectorInfoFile << std::endl;
    for (UInt4 i=0; i<_FileHistory.size(); i++){
        std::cout << "------------------------" << std::endl;
        std::cout << "run range = "<< _FileHistory[i].Period.first << " - " << _FileHistory[i].Period.second << std::endl;
        UInt4 num_mode = (UInt4)(_FileHistory[i].WiringInfoList.size());
        for (UInt4 j=0; j<num_mode; j++){
            std::cout << "-----------" << std::endl;
            std::cout << "  mode No = "<<j<<std::endl;
            std::cout << "     WiringInfo = "<< _FileHistory[i].WiringInfoList[j] << std::endl;
            std::cout << "     DetectorInfo = " << _FileHistory[i].DetectorInfoList[j] << std::endl;
            std::cout << "     MaskInfo = "<<_FileHistory[i].MaskInfoList[j] << std::endl;
        }
    }
}
