#include "UtsusemiSetMask.hh"
//////////////////////////////////////////////////////////
UtsusemiSetMask::
UtsusemiSetMask(){
    Initialize();
}
//////////////////////////////////////////////////////////
UtsusemiSetMask::
UtsusemiSetMask( ElementContainerMatrix* ecm ){
    Initialize();
    SetTarget( ecm );
}
//////////////////////////////////////////////////////////
UtsusemiSetMask::
UtsusemiSetMask( ElementContainerMatrix* ecm, std::string filename ){
    Initialize();
    SetTarget( ecm );
    ReadFile( filename );
}
//////////////////////////////////////////////////////////
UtsusemiSetMask::
UtsusemiSetMask( ElementContainerMatrix* ecm, std::string filename, std::string key ){
    Initialize();
    SetTarget( ecm );
    ReadFile( filename );
    SetAxisKey( key );
}
//////////////////////////////////////////////////////////
UtsusemiSetMask::
~UtsusemiSetMask(){
    delete _Parser;
    delete stools;
}
//////////////////////////////////////////////////////////
void UtsusemiSetMask::
Initialize(){
    _Parser = new BoostXmlParser();
    _Parser->SetQuiet( !(UtsusemiEnvGetDebugMode()) );
    _AxisKey = "";
    stools = new StringTools();
    _MessageTag = "_UtsusemiSetMask >>";
    _MaskTxtPath = "";
    _isMaskXml = false;
}
//////////////////////////////////////////////////////////
bool UtsusemiSetMask::
ReadFile( std::string filename ){
    if (filename=="") return true;
    std::string::size_type i = filename.find_last_of(".");
    if (i==std::string::npos) return false;
    if (filename.substr(i,4)==".txt"){
        std::ifstream ifs(filename.c_str());
        if (ifs.fail()){
            std::string search_path = FindParamFilePath( filename );
            if (search_path==""){
                UtsusemiError(_MessageTag+"ReadFile >>  Failed to read "+filename);
                _MaskTxtPath = "";
                ifs.close();
                return false;
            }else{
                filename = search_path;
            }
        }
        ifs.close();
        _MaskTxtPath = filename;
        _isMaskXml = false;
        return true;
    }else if (filename.substr(i,4)==".xml"){
        std::ifstream ifs(filename.c_str());
        if (ifs.fail()){
            std::string search_path = FindParamFilePath( filename );
            if (search_path==""){
                UtsusemiError(_MessageTag+"ReadFile >>  Failed to read "+filename);
                ifs.close();
                return false;
            }else{
                filename = search_path;
            }
        }
        ifs.close();
        _isMaskXml = _Parser->Load( filename );
        return _isMaskXml;
    }else{
        UtsusemiError(_MessageTag + "ReadFile fails to read "+filename);
        return false;
    }
}
//////////////////////////////////////////////////////////
void UtsusemiSetMask::
SetAxisKey( std::string a_key ){
    _AxisKey = a_key;
}
//////////////////////////////////////////////////////////
bool UtsusemiSetMask::
Execute(){
    if (_isMaskXml){
        if (_Parser->PutSize()==0){
            UtsusemiError(_MessageTag+"Execute > Mask file is not loaded correctly.");
            return false;
        }else{
            return ExecuteXmlMask();
        }
    }else{
        return ExecuteTxtMask();
    }
    return true;
}
//////////////////////////////////////////////////////////
bool UtsusemiSetMask::
ExecuteXmlMask(){
    ElementContainerMatrix* ecm = Put();
    SearchInHeader* SIH = new SearchInHeader( ecm );

    if (_Parser->hasPath( "maskInfo" )){
        if (_Parser->hasPath( "maskInfo/masklist" )){
            boost::property_tree::ptree* curNode = _Parser->PutNode("maskInfo/masklist","");
            std::vector<boost::property_tree::ptree*> masks = _Parser->PutFoundChildNodes( curNode, "mask" );
            for (UInt4 ind=0; ind<masks.size(); ind++){
                bool isAllDetMask = false;
                bool isAllPixMask = false;
                bool isAllAxMask = false;

                std::string s_path = "mask,i="+(stools->Int4ToString(ind));
                //std::cout << "@@@ ind=" << ind << "," << s_path << std::endl;
                if (true){
                    boost::property_tree::ptree* curNode2 = masks[ind];

                    std::string pid_path = "pixelid";
                    std::string det_path = "detector";
                    std::string pix_path = "pixelno";
                    std::string ax_path = "axis";
                    //if (_AxisKey!="") std::cout << "ax_path = " + ax_path + ",key=" + _AxisKey;

                    std::vector<Double> ax_range_list;
                    std::string ax_info=_Parser->PutContent( curNode2, ax_path, "" );
                    if (_AxisKey==""){
                        _AxisKey = _Parser->PutContent( curNode2, ax_path, "key" );
                        //std::cout << _MessageTag+" AxisKey is set to "+_AxisKey << std::endl;
                    }

                    if (ax_info==""){
                        isAllAxMask = true;
                    }else{
                        ax_range_list = DivMultiContDouble( ax_info );
                        if (ax_range_list.empty()) isAllAxMask = true;
                    }

                    std::vector<UInt4> pid_index_list;
                    std::vector<UInt4> det_index_list;

                    if (_Parser->hasPath( curNode2, pid_path )){
                        std::string pid_info = _Parser->PutContent( curNode2, pid_path, "" );
                        //std::cout << ">>>>> MASK pid_info="+pid_info << std::endl;
                        if (pid_info!=""){
                            pid_index_list = DivMultiContUInt4( pid_info );
                            if (pid_index_list.empty()){
                                UtsusemiWarning(_MessageTag+"Execute >> MASK pid_info is empty");
                            }else{
                                // Search PixelId to be masked
                                for (UInt4 i=0; i<pid_index_list.size(); i++){
                                    UInt4 pid = pid_index_list[i];
                                    if (SIH->Search(UTSUSEMI_KEY_HEAD_PIXELID, pid)){
                                        std::vector< std::vector<UInt4> > res = SIH->PutResults();
                                        if (res.empty()){
                                        }else{
                                            for( UInt4 i=0; i<res.size(); i++){
                                                ElementContainer* ec = ecm->PutPointer(res[i][0])->PutPointer(res[i][1]);
                                                if (isAllAxMask){
                                                    HeaderBase* hh = ec->PutHeaderPointer();
                                                    if (hh->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==1)
                                                        hh->OverWrite(UTSUSEMI_KEY_HEAD_MASKED,1);
                                                    else
                                                        hh->Add(UTSUSEMI_KEY_HEAD_MASKED,1);
                                                }else
                                                    MaskRange( ec, _AxisKey, ax_range_list );
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if (pid_index_list.empty()){
                        std::string det_info = _Parser->PutContent( curNode2, det_path, "" );
                        if (det_info==""){
                            isAllDetMask = true;
                        }else{
                            det_index_list = DivMultiContUInt4( det_info );
                            if (det_index_list.empty()) isAllDetMask = true;
                        }

                        std::vector<UInt4> pix_index_list;
                        std::string pix_info = _Parser->PutContent( curNode2, pix_path, "" );
                        if (pix_info==""){
                            isAllPixMask = true;
                        }else{
                            pix_index_list = DivMultiContUInt4( pix_info );
                            if (pix_index_list.empty()) isAllPixMask = true;
                        }

                        if (isAllDetMask){
                            for (UInt4 i=0; i<ecm->PutSize(); i++){
                                ElementContainerArray* eca=ecm->PutPointer(i);
                                if (isAllPixMask){
                                    for (UInt4 j=0; j<eca->PutSize(); j++){
                                        MaskRange( eca->PutPointer(j), _AxisKey, ax_range_list );
                                    }
                                    if (isAllAxMask){
                                        HeaderBase* hh = eca->PutHeaderPointer();
                                        if (hh->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==1)
                                            hh->OverWrite(UTSUSEMI_KEY_HEAD_MASKED,1);
                                        else
                                            hh->Add(UTSUSEMI_KEY_HEAD_MASKED,1);
                                    }
                                }else{
                                    for (UInt4 j=0; j<pix_index_list.size(); j++){
                                        MaskRange( eca->PutPointer(pix_index_list[j]), _AxisKey, ax_range_list );
                                    }
                                }
                            }
                        }else{
                            for (UInt4 i=0; i<det_index_list.size(); i++){
                                if (SIH->SearchArray( UTSUSEMI_KEY_HEAD_DETID, det_index_list[i] ) ){
                                    std::vector< std::vector<UInt4> > res = SIH->PutResults();
                                    if (res.empty()){
                                    }else{
                                        for( UInt4 i=0; i<res.size(); i++){
                                            //std::cout << "## res=" << res[i][0] << std::endl;
                                            ElementContainerArray* eca = ecm->PutPointer(res[i][0]);
                                            if (isAllPixMask){
                                                //std::cout << "## isAllPixMask" << std::endl;
                                                for (UInt4 j=0; j<eca->PutSize(); j++){
                                                    MaskRange( eca->PutPointer(j), _AxisKey, ax_range_list );
                                                }
                                                if (isAllAxMask){
                                                    HeaderBase* hh = eca->PutHeaderPointer();
                                                    if (hh->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==1)
                                                        hh->OverWrite(UTSUSEMI_KEY_HEAD_MASKED,1);
                                                    else
                                                        hh->Add(UTSUSEMI_KEY_HEAD_MASKED,1);
                                                }
                                            }else{
                                                //std::cout << "## not AllPixMsk" << std::endl;
                                                for (UInt4 j=0; j<pix_index_list.size(); j++){
                                                    //std::cout << "---- j, pix_index_list[j]=" << j << "," << pix_index_list[j] << std::endl;
                                                    MaskRange( eca->PutPointer(pix_index_list[j]), _AxisKey, ax_range_list );
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }else{
            UtsusemiError(_MessageTag+" Mask file has no maskInfo/masklist tag.");
            delete SIH;
            return false;
        }
    }else{
        UtsusemiError(_MessageTag+" Mask file has no maskInfo tag.");
        delete SIH;
        return false;
    }
    delete SIH;
    return true;
}
//////////////////////////////////////////////////////////
bool UtsusemiSetMask::
ExecuteTxtMask(){
    ElementContainerMatrix* ecm = Put();
    SearchInHeader* SIH = new SearchInHeader( ecm );

    if (_MaskTxtPath!=""){
        std::ifstream ifs(_MaskTxtPath.c_str());
        std::string tmp;
        if (ifs.fail()){
            UtsusemiError(_MessageTag+"ExecuteTxtMask > Failed to read "+_MaskTxtPath);
            return false;
        }
        while (getline(ifs,tmp)){
            if (tmp.substr(0,1)!="#"){
                // Trim
                /*
                std::string::size_type left = tmp.find_first_not_of("\t\v\r\n");
                if (left !=std::string::npos){
                    std::string::size_type right = tmp.find_last_not_of("\t\v\r\n");
                    tmp = tmp.substr(left,right-left+1);
                }
                */
                std::vector<std::string> conts = stools->SplitString( tmp, " " );
                if (conts.empty()){
                }else{
                    for (UInt4 i=0; i<conts.size(); i++){
                        std::vector<std::string> a_info = stools->SplitString( conts[i], "." );
                        if (a_info.size()==1){
                            UInt4 detId = stools->StringToUInt4( a_info[0] );
                            if (SIH->SearchArray(UTSUSEMI_KEY_HEAD_DETID,detId)){
                                std::vector< std::vector<UInt4> > res = SIH->PutResults();
                                if (res.empty()){
                                }else{
                                    for (UInt4 i=0; i<res.size(); i++){
                                        ElementContainerArray* eca = ecm->PutPointer(res[i][0]);
                                        HeaderBase* hh_eca = eca->PutHeaderPointer();
                                        if (hh_eca->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==1)
                                            hh_eca->OverWrite(UTSUSEMI_KEY_HEAD_MASKED,1);
                                        else
                                            hh_eca->Add(UTSUSEMI_KEY_HEAD_MASKED,1);

                                        for (UInt4 j=0; j<(eca->PutSize()); j++){
                                            HeaderBase* hh = eca->PutPointer(j)->PutHeaderPointer();
                                            if (hh->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==1)
                                                hh->OverWrite(UTSUSEMI_KEY_HEAD_MASKED,1);
                                            else
                                                hh->Add(UTSUSEMI_KEY_HEAD_MASKED,1);
                                        }
                                    }
                                }
                            }
                        }else if (a_info.size()==2){
                            UInt4 detId = stools->StringToUInt4( a_info[0] );
                            UInt4 pixNo = stools->StringToUInt4( a_info[1] );
                            if (SIH->SearchArray( UTSUSEMI_KEY_HEAD_DETID, detId )){
                                std::vector< std::vector<UInt4> > res = SIH->PutResults();
                                if (res.empty()){
                                }else{
                                    for (UInt4 j=0;j<res.size();j++){
                                        ElementContainerArray* eca = ecm->PutPointer(res[j][0]);
                                        if (pixNo<eca->PutSize()){
                                            HeaderBase* hh = eca->PutPointer(pixNo)->PutHeaderPointer();
                                            if (hh->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==1)
                                                hh->OverWrite(UTSUSEMI_KEY_HEAD_MASKED,1);
                                            else
                                                hh->Add(UTSUSEMI_KEY_HEAD_MASKED,1);
                                        }
                                    }
                                }
                            }
                        }else{
                            UtsusemiError(_MessageTag+"ExecuteTxtMask > mask format ("+conts[i]+") is invalid ");
                            return false;
                        }
                    }
                    /*
                    if ((conts.size()==1)&&(conts[0].find(".")==std::string::npos)){
                        UInt4 detId = stools->StringToUInt4( conts[0] );
                        if (SIH->SearchArray(UTSUSEMI_KEY_HEAD_DETID,detId)){
                            std::vector< std::vector<UInt4> > res = SIH->PutResults();
                            if (res.empty()){
                            }else{
                                for (UInt4 i=0; i<res.size(); i++){
                                    ElementContainerArray* eca = ecm->PutPointer(res[i][0]);
                                    HeaderBase* hh_eca = eca->PutHeaderPointer();
                                    if (hh_eca->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==1)
                                        hh_eca->OverWrite(UTSUSEMI_KEY_HEAD_MASKED,1);
                                    else
                                        hh_eca->Add(UTSUSEMI_KEY_HEAD_MASKED,1);

                                    for (UInt4 j=0; j<(eca->PutSize()); j++){
                                        HeaderBase* hh = eca->PutPointer(j)->PutHeaderPointer();
                                        if (hh->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==1)
                                            hh->OverWrite(UTSUSEMI_KEY_HEAD_MASKED,1);
                                        else
                                            hh->Add(UTSUSEMI_KEY_HEAD_MASKED,1);
                                    }
                                }
                            }
                        }
                    }else{
                        for (UInt4 i=0; i<conts.size(); i++){
                            std::vector<std::string> a_info = stools->SplitString( conts[i], "." );
                            if (a_info.size()==2){
                                UInt4 detId = stools->StringToUInt4( a_info[0] );
                                UInt4 pixNo = stools->StringToUInt4( a_info[1] );
                                if (SIH->SearchArray( UTSUSEMI_KEY_HEAD_DETID, detId )){
                                    std::vector< std::vector<UInt4> > res = SIH->PutResults();
                                    if (res.empty()){
                                    }else{
                                        for (UInt4 j=0;j<res.size();j++){
                                            ElementContainerArray* eca = ecm->PutPointer(res[j][0]);
                                            if (pixNo<eca->PutSize()){
                                                HeaderBase* hh = eca->PutPointer(pixNo)->PutHeaderPointer();
                                                if (hh->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==1)
                                                    hh->OverWrite(UTSUSEMI_KEY_HEAD_MASKED,1);
                                                else
                                                    hh->Add(UTSUSEMI_KEY_HEAD_MASKED,1);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    */
                }

            }

        }
    }else{
        UtsusemiError(_MessageTag+"ExecuteTxtMask > Mask file is not set");
        delete SIH;
        return false;
    }
    delete SIH;

    return true;
}
//////////////////////////////////////////////////////////
void UtsusemiSetMask::
MaskRange( ElementContainer* ec, std::string key, std::vector<Double> axrange ){
    if (key==""){
        key = ec->PutXKey();
    }else if (ec->CheckKey( key )==0){
        //std::cout << _MessageTag+"MaskRange : EC has no key="+key << std::endl;
        return;
    }
    std::vector<Double> xaxis = ec->Put(key);
    std::vector<Double> errors = ec->PutE();
    bool isHist=true;
    if (xaxis.size()==errors.size()) isHist=false;

    std::string key_x = ec->PutXKey();
    std::string key_y = ec->PutYKey();
    std::string key_err = ec->PutEKey();
    std::string unit_err = ec->PutUnit( key_err );

    if (axrange.empty()){
        HeaderBase* hh=ec->PutHeaderPointer();
        if (hh->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==1)
            hh->OverWrite(UTSUSEMI_KEY_HEAD_MASKED,1);
        else
            hh->Add(UTSUSEMI_KEY_HEAD_MASKED,1);
    }else{
        for (UInt4 i=0; i<axrange.size(); i+=2){
            for (UInt4 j=0; j<errors.size(); j++){
                Double XX = xaxis[j];
                if (isHist) {
                    if ( (axrange[i]<=xaxis[j])&&(xaxis[j+1]<=axrange[i+1]) ){//XX = (xaxis[j]+xaxis[j+1])/2.0;
                        if (errors[j]==0.0) errors[j] = -1.0E-32;
                        else errors[j]=-1.0*fabs( errors[j] );
                    }
                }else{
                    if ( (XX>axrange[i])&&(XX<axrange[i+1]) ){
                        if (errors[j]==0.0) errors[j] = -1.0E-32;
                        else errors[j]=-1.0*fabs( errors[j] );
                    }
                }
            }
        }
        ec->Remove( key_err );
        ec->Add( key_err, errors, unit_err );
        ec->SetKeys( key_x, key_y, key_err );
    }
}

//////////////////////////////////////////////////////////
void UtsusemiSetMask::
UnmaskAll(){
    ElementContainerMatrix* ecm = Put();

    for (UInt4 i=0;i<(ecm->PutSize()); i++){
        ElementContainerArray* eca = ecm->PutPointer(i);
        HeaderBase* hh_eca=eca->PutHeaderPointer();
        if (hh_eca->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==1)
            hh_eca->OverWrite(UTSUSEMI_KEY_HEAD_MASKED,0);
        else
            hh_eca->Add(UTSUSEMI_KEY_HEAD_MASKED,0);
        for (UInt4 j=0; j<eca->PutSize(); j++){
            ElementContainer* ec = eca->PutPointer(j);
            HeaderBase* hh=ec->PutHeaderPointer();
            if (hh->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==1)
                hh->OverWrite(UTSUSEMI_KEY_HEAD_MASKED,0);
            else
                hh->Add(UTSUSEMI_KEY_HEAD_MASKED,0);

            std::vector<Double> xaxis = ec->Put(_AxisKey);
            std::vector<Double> errors = ec->PutE();
            bool isHist=true;
            if (xaxis.size()==errors.size()) isHist=false;

            std::string key_x = ec->PutXKey();
            std::string key_y = ec->PutYKey();
            std::string key_err = ec->PutEKey();
            std::string unit_err = ec->PutUnit( key_err );

            for (UInt4 i=0; i<errors.size(); i++)
                errors[i] = fabs(errors[i]);

            ec->Remove( key_err );
            ec->Add( key_err, errors, unit_err );
            ec->SetKeys( key_x, key_y, key_err );
            }
    }
}
//////////////////////////////////////////////////////////
bool UtsusemiSetMask::
PutListOfTxtMask( std::vector< std::vector< std::vector<Double>* >* > *list ){
    if (_MaskTxtPath!=""){
        std::ifstream ifs(_MaskTxtPath.c_str());
        std::string tmp;
        if (ifs.fail()){
            UtsusemiError(_MessageTag+"ExecuteTxtMask > Failed to read "+_MaskTxtPath);
            return false;
        }
        while (getline(ifs,tmp)){
            if (tmp.substr(0,1)!="#"){
                std::vector<std::string> conts = stools->SplitString( tmp, " " );
                if (conts.empty()){
                }else{
                    if (conts.size()==1){
                        UInt4 detId = stools->StringToUInt4( conts[0] );
                        if ( detId >= list->size() ) list->resize( detId+1, NULL );
                        if ( list->at(detId)==NULL ) list->at(detId) = new std::vector< std::vector<Double>* > ();
                    }else{
                        for (UInt4 i=0; i<conts.size(); i++){
                            std::vector<std::string> a_info = stools->SplitString( conts[i], "." );
                            if (a_info.size()==2){
                                UInt4 detId = stools->StringToUInt4( a_info[0] );
                                UInt4 pixNo = stools->StringToUInt4( a_info[1] );
                                if ( detId >= list->size() ) list->resize( detId+1, NULL );
                                if ( list->at(detId)==NULL ) list->at(detId) = new std::vector< std::vector<Double>* > ();

                                if ( pixNo >= (list->at(detId)->size()) ) list->at(detId)->resize( pixNo+1, NULL );
                                if ( list->at(detId)->at(pixNo)==NULL ) list->at(detId)->at(pixNo) = new std::vector<Double> ();
                            }
                        }
                    }
                }
            }
        }
    }else{
        UtsusemiError(_MessageTag+"ExecuteTxtMask > Mask file is not set");
        return false;
    }
    return true;
}
