#include "BoostXmlParser.hh"
//////////////////////////////////////////////////////////
BoostXmlParser::
BoostXmlParser(){
    Initialize();
}
//////////////////////////////////////////////////////////
BoostXmlParser::
BoostXmlParser( std::string xmlfile ){
    Initialize();
    Load(xmlfile);
}
//////////////////////////////////////////////////////////
BoostXmlParser::
BoostXmlParser( std::string key, std::string xmlfile ){
    Initialize();
    Load(key,xmlfile);
}
//////////////////////////////////////////////////////////
BoostXmlParser::
~BoostXmlParser(){
    Clear();
    delete _TreeMap;
    delete _st;
}
//////////////////////////////////////////////////////////
void BoostXmlParser::
Initialize(){
    _MessageTag = "BoostXmlParser::";
    _TreeMap = new Map< boost::property_tree::ptree* >;
    _CurrentKey = "";
    _isQuietMode = false;
    _isLoadXmlString = false;
    _st = new StringTools();
}
//////////////////////////////////////////////////////////
void BoostXmlParser::
Clear( std::string key, bool isForced ){
    if (key==""){
        std::vector<std::string> keys = PutKeys();
        if (keys.empty()){
        }else{
            std::vector<std::string>::iterator it = keys.begin();
            while( it!=keys.end() ){
                delete _TreeMap->Put( *it );
                _TreeMap->Remove( *it );
                ++it;
            }
        }
    }else{
        if (_TreeMap->Check( key )==0){
            if (isForced){
            }else{
                if (!_isQuietMode)
                    std::cout << _MessageTag+" No such key ("+key+")" << std::endl;
            }
        }else{
            delete _TreeMap->Put( key );
            _TreeMap->Remove( key );
        }
    }
}
//////////////////////////////////////////////////////////
std::string BoostXmlParser::
_MakeNewKey( std::string path ){
    StringTools st;
    if (path==""){
        _CurrentKey = "BOOSTXMLPARSERKEY"+st.UInt4ToString( PutSize() );
    }else{
        _CurrentKey = path;
    }
    return _CurrentKey;
}
//////////////////////////////////////////////////////////
std::string BoostXmlParser::
_trimPath( std::string path ){
    std::string::size_type ind = 0;
    // triming spaces
    while(ind=path.find(" "), ind!=std::string::npos ) path.erase( ind,1 );

    // replace "/" to "."
    ind = path.find("/");
    while ( ind!=std::string::npos ){
        path.replace( ind, 1, "." );
        ind = path.find("/");
    }

    // convesion XPath to ours
    while(ind=path.find("[@"), ind!=std::string::npos ){
        std::string::size_type ind_end = path.find("]");
        if (ind_end==std::string::npos){
            std::cout << _MessageTag+"Invalid XPath format, not bracket:"+path << std::endl;
            break;
        }
        std::string att_str = path.substr((ind+2),(ind_end-(ind+2)));
        std::string::size_type ind1 = 0;
        while(ind1=att_str.find("'"), ind1!=std::string::npos ) att_str.erase( ind1,1 );
        while(ind1=att_str.find('"'), ind1!=std::string::npos ) att_str.erase( ind1,1 );
        path.replace(ind,(ind_end+1-ind),","+att_str);
    }

    // triming slash at head and tail of given path
    ind = path.find(".");
    if (ind==(std::string::size_type)(0))
        path = path.substr(1);

    ind = path.rfind(".");
    if (ind==(std::string::size_type)(path.size()-1))
        path = path.substr(0,ind);


    return path;
}

//////////////////////////////////////////////////////////
boost::property_tree::ptree& BoostXmlParser::
_getNode( boost::property_tree::ptree& pIn, std::string path, bool& status, bool makeNew ){
    if (path==""){
        status = true;
        return pIn;
    }
    // path is defined as "A.B,C:abc,D:efg.E" or "A.B.C"
    // find attribute part
    std::string::size_type ind=path.find(",");
    if (ind==std::string::npos){ // if no attribute, get child by path. as "A.B.C"
        if ( boost::optional<boost::property_tree::ptree&> child=pIn.get_child_optional( path ) ){
            status = true;
            return child.get();
        }else{
            //std::cout << " Cannot find path = "+path << std::endl;
            if (makeNew){
                status = true;
                return pIn.add( path, "" );
            }
            return pIn;
        }
    }else{  // if attribute is given like "A.B,C:abc,D:efg.E"
        std::string thisPath = path.substr(0,ind);  //thisPath="A.B"
        std::string tmp_path  = path.substr(ind+1); //tmp_path ="C:abc,D:efg.E"
        std::string attr="";
        std::string nextPath="";

        ind=tmp_path.find(".");       // pick up only attributes
        if (ind==std::string::npos) {
            attr = tmp_path;
        }else{
            attr = tmp_path.substr(0,ind);      // attr="C:abc,D:efg.E"
            nextPath = tmp_path.substr(ind+1);  // nextPath = "E"
        }

        // attr is "C:abc,D:efg"
        std::vector<std::string> attr_list = _st->SplitString(attr,",");
        UInt4 num_attr_list = (UInt4)(attr_list.size());
        std::vector<bool> isAttribute( num_attr_list, true ); // attributes or tags
        std::vector<std::string> attr_key( num_attr_list, "" );    // keys
        std::vector<std::string> attr_val( num_attr_list, "" );    // values
        std::vector<bool> isFound( num_attr_list, false);

        for (UInt4 i=0; i<num_attr_list; i++){
            std::string::size_type ind_eq = attr_list[i].find("=");  // attributes
            std::string::size_type ind_tg = attr_list[i].find(":");  // tag

            if (ind_eq!=std::string::npos){
                isAttribute[i] = true;
                attr_key[i] = attr_list[i].substr(0,ind_eq);
                attr_val[i] = attr_list[i].substr(ind_eq+1);
            }else if (ind_tg!=std::string::npos){
                isAttribute[i] = false;
                attr_key[i] = attr_list[i].substr(0,ind_tg);
                attr_val[i] = attr_list[i].substr(ind_tg+1);
            }else{
                return pIn;
            }
        }

        boost::property_tree::ptree* targetTree = NULL;
        std::string targetTag = "";


        //std::cout << "Step 1" << std::endl;
        targetTag = thisPath;
        targetTree = &(pIn);
        ind = thisPath.rfind(".");  // thisPath = "A.B"
        if (ind!=std::string::npos){
            if ( boost::optional<boost::property_tree::ptree&> child=pIn.get_child_optional( thisPath.substr(0,ind) ) ){ // children of "A"
                targetTag = thisPath.substr(ind+1); //targetTag = "B"
                targetTree = &(child.get());
            }
        }

        //std::cout << "Step 2" << std::endl;
        for (boost::property_tree::ptree::iterator it = (*targetTree).begin(); it!=(*targetTree).end(); ++it){
            if ((*it).first==targetTag){  // if a child of "A" is "B"
                for (UInt4 i=0; i<num_attr_list; i++){
                    isFound[i]=false;
                    if (isAttribute[i]){
                        if ( boost::optional<std::string> opt = (*it).second.get_optional<std::string>( "<xmlattr>."+attr_key[i] ) ){
                            if ((attr_val[i]=="")||(opt.get()==attr_val[i])){
                                isFound[i]=true;
                            }
                        }else if ( boost::optional<boost::property_tree::ptree&> child2=(*it).second.get_child_optional( attr_key[i] ) ){
                            if ((*child2).data()==attr_val[i]){
                                isFound[i]=true;
                            }
                        }
                    }else{
                        if ( boost::optional<boost::property_tree::ptree&> child2=(*it).second.get_child_optional( attr_key[i] ) ){
                            if ((*child2).data()==attr_val[i]){
                                isFound[i]=true;
                            }
                        }
                    }
                }

                bool isFoundAll = true;
                for (UInt4 i=0; i<num_attr_list; i++)
                    if (!(isFound[i])) {
                        isFoundAll = false;
                        //std::cout << _MessageTag+" --- isFountAll = false, thisPath="<< thisPath<<std::endl;
                        break;
                    }
                if (isFoundAll){
                    if (nextPath==""){
                        status = true;
                        return (*it).second;
                    }else{
                        return _getNode( (*it).second, nextPath, status, makeNew );
                    }
                }
            }
        }
        //std::cout << _MessageTag+" --- Not found path="+path<<std::endl;

        if (makeNew){
            boost::property_tree::ptree& tmp = pIn.add( thisPath,"" );
            for (UInt4 i=0; i<num_attr_list; i++){
                if (isFound[i]){
                }else{
                    if (isAttribute[i]){
                        tmp.put( "<xmlattr>."+attr_key[i], attr_val[i] );
                        status = true;
                    }else{
                        tmp.put( attr_key[i], attr_val[i] );
                        status = true;
                    }
                }
            }
            if (nextPath=="") return tmp;
            else return _getNode( tmp, nextPath, status, makeNew );
        }

        return pIn;
    }
}

//////////////////////////////////////////////////////////
bool BoostXmlParser::
CreateNewTree( std::string key ){
    if (key=="") key = _MakeNewKey();
    bool ret = false;
    if (_TreeMap->Check( key )==0){
        boost::property_tree::ptree* tmp = new boost::property_tree::ptree;
        _TreeMap->Add( key, tmp );
        _CurrentKey = key;
        ret = true;
    }else{
        std::cout << _MessageTag+" Already this key is used; ( key= "<< key << ")" << std::endl;
    }
    return ret;
}

//////////////////////////////////////////////////////////
bool BoostXmlParser::
AddElement( std::string key, std::string path, std::string cont ){
    if (_TreeMap->Check( key )==0){
        std::cout << _MessageTag+"AddElement:: no key = "<< key << std::endl;
        return false;
    }
    boost::property_tree::ptree* curNode = _TreeMap->Put(key);

    // trimming
    path = _trimPath( path );

    bool status = false;
    boost::property_tree::ptree& retNode = _getNode( *curNode, path, status, true );

    if (status){
        retNode.put_value( cont );
    }else{
        std::cout<< _MessageTag+"AddElement::False to search path=" << path << std::endl;
        return false;
    }

    return true;
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
AddElement( std::string path, std::string cont ){
    if (_CurrentKey=="") {
        std::cout << _MessageTag+"AddElement:: no current tree" << std::endl;
        return false;
    }
    return AddElement( _CurrentKey, path, cont );
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
AddElement( std::string key, std::string path, std::vector<std::string> attr_v, std::vector<std::string> val_v ){
    if (_TreeMap->Check( key )==0){
        std::cout << _MessageTag+"AddToTree:: no key = "<< key << std::endl;
        return false;
    }
    boost::property_tree::ptree* curNode = _TreeMap->Put(key);

    // trimming
    path = _trimPath( path );

    bool status = false;
    boost::property_tree::ptree& retNode = _getNode( *curNode, path, status, true );

    if (status){
        bool isNotSetAttr=true;
        for (boost::property_tree::ptree::iterator it=retNode.begin();it!=retNode.end();++it){
            if ( (*it).first=="<xmlattr>" ){
                isNotSetAttr=false;
                for (UInt4 i=0;i<attr_v.size();i++){
                    (*it).second.put(attr_v[i],val_v[i]);
                }
                break;
            }
        }
        if (isNotSetAttr){
            for (UInt4 i=0; i<attr_v.size(); i++){
                retNode.put( "<xmlattr>."+attr_v[i], val_v[i] );
            }
        }
    }else{
        std::cout<< _MessageTag+"AddElement::False to search path=" << path << std::endl;
        return false;
    }

    return true;
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
AddElement( std::string path, std::vector<std::string> attr_v, std::vector<std::string> val_v ){
    if (_CurrentKey=="") {
        std::cout << _MessageTag+"AddElement:: no current tree " << std::endl;
        return false;
    }
    return AddElement( _CurrentKey, path, attr_v, val_v );
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
_eraseNode( boost::property_tree::ptree& pIn, std::string path, std::string target_attr ){
    if (path=="") return false;

    // path is defined as "A.B,c=abc", "A.B,c:abc" or "A.B"
    // find last node of given path to separate /path/to "A" and node like "B,c=abc" or "B,c:abc"
    std::string::size_type ind = path.rfind(".");
    std::string pre_path = "";
    std::string tag = "";
    if (ind==std::string::npos){
        tag = path;
    }else{
        pre_path = path.substr(0,ind);  //pre_path is "A"
        tag = path.substr(ind+1);       //tag is "B,c:abc", "B,c:abc" or "B"
    }

    bool status = false;
    // get node like "A"
    boost::property_tree::ptree& retNode = _getNode( pIn, pre_path, status, false );
    if (!(status)) return false;

    // find attribute of last node
    ind = tag.find( "," );
    bool isEraced = false;

    // if no attribute, like "B"
    if ( ind==std::string::npos ){
        for (boost::property_tree::ptree::iterator it=retNode.begin(); it!=retNode.end(); ++it){
            if ( (*it).first==tag ){
                if (target_attr=="") {
                    retNode.erase( it );
                    isEraced = true;
                }else{
                    for (boost::property_tree::ptree::iterator it2=(*it).second.begin();it2!=(*it).second.end();++it2){
                        if ( (*it2).first=="<xmlattr>" ){
                            boost::property_tree::ptree::size_type ii = (*it2).second.erase(target_attr);
                            if (ii!=0) isEraced = true;
                        }
                    }
                }
            }
        }
    }else{ // if attribute is given like "B,c:abc" or "B,c=abc"
        std::string body = tag.substr(0,ind);
        std::string attr = tag.substr(ind+1);

        std::vector<std::string> attr_list = _st->SplitString(attr,",");
        UInt4 num_attr_list = (UInt4)(attr_list.size());
        std::vector<bool> isAttribute( num_attr_list, true ); // attributes or tags
        std::vector<std::string> attr_key( num_attr_list, "" );    // keys
        std::vector<std::string> attr_val( num_attr_list, "" );    // values
        std::vector<bool> isFound( num_attr_list, false);

        for (UInt4 i=0; i<num_attr_list; i++){
            std::string::size_type ind_eq = attr.find("=");  // attributes
            std::string::size_type ind_tg = attr.find(":");  // tag

            if (ind_eq!=std::string::npos){
                isAttribute[i] = true;
                attr_key[i] = attr.substr(0,ind_eq);
                attr_val[i] = attr.substr(ind_eq+1);
            }else if (ind_tg!=std::string::npos){
                isAttribute[i] = false;
                attr_key[i] = attr.substr(0,ind_tg);
                attr_val[i] = attr.substr(ind_tg+1);
            }else{
                return false;
            }
        }

        for (boost::property_tree::ptree::iterator it = retNode.begin(); it!=retNode.end(); ++it){
            if ( (*it).first == body ){
                for (UInt4 i=0; i<num_attr_list; i++){
                    if (isAttribute[i]){
                        if ( boost::optional<std::string> opt = (*it).second.get_optional<std::string>( "<xmlattr>."+attr_key[i] ) ){
                            if (opt.get()==attr_val[i]){
                                isFound[i]=true;
                            }
                        }else if ( boost::optional<boost::property_tree::ptree&> child2=(*it).second.get_child_optional( attr_key[i] ) ){
                            if ((*child2).data()==attr_val[i]){
                                isFound[i]=true;
                            }
                        }
                    }else{
                        if ( boost::optional<boost::property_tree::ptree&> child2=(*it).second.get_child_optional( attr_key[i] ) ){
                            if ((*child2).data()==attr_val[i]){
                                isFound[i]=true;
                            }
                        }
                    }
                }

                bool isFoundAll = true;
                for (UInt4 i=0; i<num_attr_list; i++)
                    if (!(isFound[i])) {
                        isFoundAll = false;
                        //std::cout << _MessageTag+" --- isFountAll = false, thisPath="<< thisPath<<std::endl;
                        break;
                    }
                if (isFoundAll){
                    if (target_attr=="") {
                        retNode.erase( it );
                        isEraced=true;
                    }else{
                        boost::property_tree::ptree::assoc_iterator it2 = (*it).second.find( "<xmlattr>" );
                        if (it2!=(*it).second.not_found()){
                            boost::property_tree::ptree::size_type ii = (*it2).second.erase(target_attr);
                            if (ii!=0) isEraced=true;
                        }
                    }
                }
            }
        }
    }
    return isEraced;

}

//////////////////////////////////////////////////////////
bool BoostXmlParser::
RemoveElement( std::string key, std::string path, std::string attr ){
    if (_TreeMap->Check( key )==0){
        if (!_isQuietMode) std::cout << _MessageTag+"AddToTree:: no key = "<< key << std::endl;
        return false;
    }
    boost::property_tree::ptree* curNode = _TreeMap->Put(key);

    // trimming
    path = _trimPath( path );

    return _eraseNode( *curNode, path, attr );
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
RemoveElement( std::string path, std::string attr ){
    if (_CurrentKey=="") {
        if (!_isQuietMode) std::cout << _MessageTag+"RemoveElement:: no current tree" << std::endl;
        return false;
    }
    return RemoveElement( _CurrentKey, path, attr );
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
Save( std::string key, std::string path ){
    using namespace boost::property_tree::xml_parser;

    if (_TreeMap->Check( key )==0){
        if (!_isQuietMode) std::cout << _MessageTag + "Save : invalid key = " << key << std::endl;
        return false;
    }

    const UInt4 indent = 4;

    write_xml( path, *(_TreeMap->Find( key )), std::locale(),
#if BOOST_VERSION < 105600
               xml_writer_make_settings(' ', indent, widen<char>("utf-8")));
#else
               xml_writer_make_settings(' ', indent, widen<std::string>("utf-8")));
#endif
    return true;
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
Save( std::string path ){
    if (_CurrentKey=="") {
        if (!_isQuietMode) std::cout << _MessageTag+"Save:: no current tree" << std::endl;
        return false;
    }else{
        return Save( _CurrentKey, path );
    }
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
Load( std::string key, std::string arg ){
    if (arg.find("<?xml")==0){
        _isLoadXmlString = true;
        return LoadFromString( key, arg );
    }else
        _isLoadXmlString = false;

    boost::property_tree::ptree* pt = new boost::property_tree::ptree;
    UInt4 flag = boost::property_tree::xml_parser::trim_whitespace;
    try{
        boost::property_tree::read_xml( arg, *pt, flag, std::locale() );
    }
    catch (...){
        return false;
    }

    if (_TreeMap->Check( key )!=0) Clear( key );
    _TreeMap->Add( key, pt );
    _CurrentKey = key;

    return true;
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
Load( std::string arg ){
    if (arg.find("<?xml")==0){
        _isLoadXmlString = true;
        return LoadFromString( arg );
    }else{
        _isLoadXmlString = false;
        return Load( _MakeNewKey( arg ), arg );
    }
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
LoadFromString( std::string key, std::string xmlstring ){
    boost::property_tree::ptree* pt = new boost::property_tree::ptree;
    UInt4 flag = boost::property_tree::xml_parser::trim_whitespace;
    std::stringstream ss;
    ss << xmlstring;
    try{
        boost::property_tree::read_xml( ss, *pt, flag );
    }
    catch (...){
        return false;
    }

    if (_TreeMap->Check( key )!=0) Clear( key );
    _TreeMap->Add( key, pt );
    _CurrentKey = key;
    _isLoadXmlString = true;
    return true;
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
LoadFromString( std::string xmlstring ){
    return LoadFromString( _MakeNewKey( "stringxml" ), xmlstring );
}
//////////////////////////////////////////////////////////
std::string BoostXmlParser::
OutToString( std::string key, std::string path, bool withIndent ){
    if (key==""){
        if (_CurrentKey==""){
            if (!_isQuietMode) std::cout << _MessageTag+"OutToString:: no current tree" << std::endl;
            return "";
        }else{
            key=_CurrentKey;
        }
    }

    using namespace boost::property_tree::xml_parser;

    if (_TreeMap->Check( key )==0){
        if (!_isQuietMode) std::cout << _MessageTag + "OutToString : invalid key = " << key << std::endl;
        return "";
    }

    boost::property_tree::ptree retNode;
    if (path=="") retNode = *(_TreeMap->Find( key ));
    else{
        boost::property_tree::ptree* curNode = _TreeMap->Put(key);

        // trimming
        path = _trimPath( path );
        bool status = false;
        retNode = _getNode( *curNode, path, status, false );
        if (!status){
            if (!_isQuietMode) std::cout << _MessageTag + "OutToString : path not found : " << path << std::endl;
            return "";
        }
    }

    std::stringstream ss;
    if (withIndent){
        const UInt4 indent = 4;
        write_xml( ss, retNode,
#if BOOST_VERSION < 105600
               xml_writer_make_settings(' ', indent, widen<char>("utf-8")));
#else
               xml_writer_make_settings(' ', indent, widen<std::string>("utf-8")));
#endif
    }else
        write_xml( ss, retNode );

    return ss.str();
}
//////////////////////////////////////////////////////////
std::string BoostXmlParser::
OutToString( std::string path, bool withIndent ){
    return OutToString( "", path, withIndent );
}
//////////////////////////////////////////////////////////
std::string BoostXmlParser::
OutToString( bool withIndent ){
    return OutToString( "", "", withIndent );
}
//////////////////////////////////////////////////////////
std::string BoostXmlParser::
PutContent( std::string key, std::string path, std::string attr ){
    if (_TreeMap->Check( key )==0){
        if (!_isQuietMode) std::cout << _MessageTag+"PutContent:: no key = "<< key << std::endl;
        return "";
    }
    boost::property_tree::ptree* curNode = _TreeMap->Put(key);

    return PutContent( curNode, path, attr );
}
//////////////////////////////////////////////////////////
std::string BoostXmlParser::
PutContent( boost::property_tree::ptree* curNode, std::string path, std::string attr ){
    std::string ret="";
    // trimming
    path = _trimPath( path );

    bool status = false;
    boost::property_tree::ptree& retNode = _getNode( *curNode, path, status, false );
    bool isFound = false;
    if (status){
        if (attr=="") ret =  retNode.data();
        else{
            if ( boost::optional<std::string> opt = retNode.get_optional<std::string>( "<xmlattr>."+attr ) ){
                ret = opt.get();
            }else{
                if (!_isQuietMode) std::cout << _MessageTag+"PutContent >> attribute("+attr+") is not existed in "+path+"." << std::endl;
            }
        }
    }else{
        if (!_isQuietMode) std::cout<< _MessageTag+"PutContent::False to search path=" << path << std::endl;
    }

    return ret;
}
//////////////////////////////////////////////////////////
std::string BoostXmlParser::
PutContent( std::string path, std::string attr ){
    if (_CurrentKey=="") {
        if (!_isQuietMode) std::cout << _MessageTag+"PutContent:: no current tree" << std::endl;
        return "";
    }
    return PutContent( _CurrentKey, path, attr );
}
//////////////////////////////////////////////////////////
std::string BoostXmlParser::
PutContent( std::string path ){
    if (_CurrentKey=="") {
        if (!_isQuietMode) std::cout << _MessageTag+"PutContent:: no current tree" << std::endl;
        return "";
    }
    return PutContent( _CurrentKey, path, "" );
}
//////////////////////////////////////////////////////////
std::string BoostXmlParser::
putTextContent( std::string key, std::string path, std::string attr){
    return PutContent( key, path, attr );
}
//////////////////////////////////////////////////////////
std::vector<std::string> BoostXmlParser::
PutAttValList( std::string key, std::string path, std::string attr ){
    std::vector<std::string> ret;

    if (_TreeMap->Check( key )==0){
        if (!_isQuietMode) std::cout << _MessageTag+"PutContent:: no key = "<< key << std::endl;
        return ret;
    }
    boost::property_tree::ptree* curNode = _TreeMap->Put(key);

    return PutAttValList( curNode, path, attr );
}
//////////////////////////////////////////////////////////
std::vector<std::string> BoostXmlParser::
PutAttValList( boost::property_tree::ptree* curNode, std::string path, std::string attr ){
    std::vector<std::string> ret;
    // trimming
    path = _trimPath( path );

    std::string::size_type ind = path.rfind(".");
    std::string pre_path="";
    std::string tag="";

    if (ind==std::string::npos){
        tag = path;
    }else{
        pre_path = path.substr(0,ind);
        tag = path.substr(ind+1);
    }

    bool status = false;
    boost::property_tree::ptree &retNode=_getNode( *curNode, pre_path, status, false );

    ret.clear();
    if (status){
        for (boost::property_tree::ptree::iterator it_tag = retNode.begin(); it_tag!=retNode.end(); ++it_tag){
            if ( (*it_tag).first==tag )
                if ( boost::optional<std::string> opt = (*it_tag).second.get_optional<std::string>( "<xmlattr>."+attr ) )
                    ret.push_back( opt.get() );
        }
    }
    return ret;
}
//////////////////////////////////////////////////////////
std::vector<std::string> BoostXmlParser::
PutAttValList( std::string path, std::string attr ){
    if (_CurrentKey=="") {
        if (!_isQuietMode) std::cout << _MessageTag+"AddElement:: no current tree" << std::endl;
        std::vector<std::string> ret;
        return ret;
    }
    return PutAttValList( _CurrentKey, path, attr );
}
//////////////////////////////////////////////////////////
std::vector<std::string> BoostXmlParser::
PutElemContList( std::string key, std::string path, std::string elename ){
    std::vector<std::string> ret;

    if (_TreeMap->Check( key )==0){
        if (!_isQuietMode) std::cout << _MessageTag+"PutElemContList >>> no key = "<< key << std::endl;
        return ret;
    }
    boost::property_tree::ptree* curNode = _TreeMap->Put(key);

    return PutElemContList( curNode, path, elename );
}
//////////////////////////////////////////////////////////
std::vector<std::string> BoostXmlParser::
PutElemContList( boost::property_tree::ptree* curNode, std::string path, std::string elename ){
    std::vector<std::string> ret;
    // trimming
    path = _trimPath( path );

    std::string::size_type ind = path.rfind(".");
    std::string pre_path="";
    std::string tag="";

    if (ind==std::string::npos){
        tag = path;
    }else{
        pre_path = path.substr(0,ind);
        tag = path.substr(ind+1);
    }

    bool status = false;
    boost::property_tree::ptree &retNode=_getNode( *curNode, pre_path, status, false );

    ret.clear();
    if (status){
        for (boost::property_tree::ptree::iterator it_tag = retNode.begin(); it_tag!=retNode.end(); ++it_tag){
            if ( (*it_tag).first==tag )
                for (boost::property_tree::ptree::iterator it_ele = (*it_tag).second.begin(); it_ele!=(*it_tag).second.end(); ++it_ele){
                    if ( (*it_ele).first==elename ) ret.push_back( (*it_ele).second.data() );
                }
        }
    }
    if (_isDebugMode){
        for (UInt4 i=0; i<ret.size(); i++) std::cout << ret[i] << ",";
        std::cout << std::endl;
    }
    return ret;
}
//////////////////////////////////////////////////////////
std::vector<std::string> BoostXmlParser::
PutElemContList( std::string path, std::string elename ){
    if (_CurrentKey=="") {
        if (!_isQuietMode) std::cout << _MessageTag+"PutElemContList >>> no current tree" << std::endl;
        std::vector<std::string> ret;
        return ret;
    }
    return PutElemContList( _CurrentKey, path, elename );
}

//////////////////////////////////////////////////////////
std::vector<std::string> BoostXmlParser::PutChildrenElemNames( std::string key, std::string path ){
    if (_TreeMap->Check( key )==0){
        if (!_isQuietMode) std::cout << _MessageTag+"PutChildrenElemNames >>> no key = "<< key << std::endl;
        std::vector<std::string> ret;
        return ret;
    }
    boost::property_tree::ptree* curNode = _TreeMap->Put(key);
    return PutChildrenElemNames( curNode, path );
}
//////////////////////////////////////////////////////////
std::vector<std::string> BoostXmlParser::PutChildrenElemNames( std::string path ){
    if (_CurrentKey=="") {
        if (!_isQuietMode) std::cout << _MessageTag+"PutChildElemNames >>> no current tree" << std::endl;
        std::vector<std::string> ret;
        return ret;
    }
    return PutChildrenElemNames( _CurrentKey, path );
}
//////////////////////////////////////////////////////////
std::vector<std::string> BoostXmlParser::PutChildrenElemNames( boost::property_tree::ptree* curNode, std::string path ){
    std::vector<std::string> ret;
    // trimming
    path = _trimPath( path );
    bool status = false;
    boost::property_tree::ptree &retNode=_getNode( *curNode, path, status, false );

    ret.clear();
    for (boost::property_tree::ptree::iterator it = retNode.begin(); it!=retNode.end(); ++it)
        ret.push_back( (*it).first );
    if (_isDebugMode){
        for (UInt4 i=0; i<ret.size(); i++) std::cout << ret[i] << ",";
        std::cout << std::endl;
    }
    return ret;
}
//////////////////////////////////////////////////////////
UInt4 BoostXmlParser::
PutNumOfElements( std::string key, std::string path ){
    UInt4 ret = 0;
    if (_TreeMap->Check( key )==0){
        if (!_isQuietMode) std::cout << _MessageTag+"PutContent:: no key = "<< key << std::endl;
        return ret;
    }
    boost::property_tree::ptree* curNode = _TreeMap->Put(key);

    return PutNumOfElements( curNode, path );
}
//////////////////////////////////////////////////////////
UInt4 BoostXmlParser::
PutNumOfElements( boost::property_tree::ptree* curNode, std::string path ){
    UInt4 ret = 0;
    // trimming
    path = _trimPath( path );

    std::string::size_type ind = path.rfind(".");
    std::string pre_path="";
    std::string tag="";

    if (ind==std::string::npos){
        tag = path;
    }else{
        pre_path = path.substr(0,ind);
        tag = path.substr(ind+1);
    }

    bool status = false;
    boost::property_tree::ptree &retNode=_getNode( *curNode, pre_path, status, false );

    if (status){
        ind = tag.rfind(",");
        if (ind==std::string::npos){
            ret = (UInt4)(retNode.count( tag ));
        }else{
            std::string tag_path = tag.substr(0,ind);
            std::string attr_info = tag.substr(ind+1);
            std::string::size_type ind2 = attr_info.find("=");
            if (ind2!=std::string::npos){
                std::string attr_tag = attr_info.substr(0,ind2);
                std::string attr_val = attr_info.substr(ind2+1);
                for (boost::property_tree::ptree::iterator it=retNode.begin(); it!=retNode.end();++it){
                    if( (*it).first==tag_path ){
                        for (boost::property_tree::ptree::iterator it2=(*it).second.begin(); it2!=(*it).second.end();++it2){
                            if ( (*it2).first=="<xmlattr>" ){
                                for (boost::property_tree::ptree::iterator it3=(*it2).second.begin(); it3!=(*it2).second.end();++it3){
                                    if ( ( (*it3).first==attr_tag )&&( (*it3).second.data()==attr_val ) ) ret++;
                                }
                            }
                        }
                    }
                }
            }
        }
    }else{
        if (!_isQuietMode) std::cout << _MessageTag+"PutNumOfElements >> not found path="+pre_path << std::endl;
    }

    return ret;
}
//////////////////////////////////////////////////////////
UInt4 BoostXmlParser::
PutNumOfElements( std::string path ){
    if (_CurrentKey=="") {
        if (!_isQuietMode) std::cout << _MessageTag+"AddElement:: no current tree" << std::endl;
        return 0;
    }
    return PutNumOfElements( _CurrentKey, path );
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
hasPath( std::string key, std::string path ){
    if (_TreeMap->Check( key )==0){
        if (!_isQuietMode) std::cout << _MessageTag+"PutContent:: no key = "<< key << std::endl;
        return false;
    }
    boost::property_tree::ptree* curNode = _TreeMap->Put(key);

    return hasPath( curNode, path );
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
hasPath( boost::property_tree::ptree* curNode, std::string path ){
    // trimming
    path = _trimPath( path );

    bool status = false;
    boost::property_tree::ptree& retNode = _getNode( *curNode, path, status, false );

    return status;
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
hasPath( std::string path ){
    if (_CurrentKey=="") {
        if (!_isQuietMode) std::cout << _MessageTag+"hasPath:: no current tree" << std::endl;
        return false;
    }
    return hasPath( _CurrentKey, path );
}
//////////////////////////////////////////////////////////
std::vector<std::string> BoostXmlParser::
PutKeys(){
    std::vector<std::string> ret;
    if (_TreeMap->Empty()){
        //std::cout << _MessageTag+" No Tree " << std::endl;
    }else{
        for (UInt4 i=0;i<(_TreeMap->Size());i++)
            ret.push_back( _TreeMap->PutKey(i) );
    }
    return ret;
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
hasKey( std::string key ){
    bool isFound = false;
    if (_TreeMap->Empty()){
        //std::cout << _MessageTag+" No Tree " << std::endl;
    }else{
        for (UInt4 i=0;i<(_TreeMap->Size());i++)
            if (key==_TreeMap->PutKey(i)){
                isFound=true;
                break;
            }
    }
    return isFound;
}
//////////////////////////////////////////////////////////
UInt4 BoostXmlParser::
PutSize(){
    if (_TreeMap->Empty()){
        return 0;
    }else{
        return _TreeMap->Size();
    }
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
ChangeCurrent( std::string key ){
    if (_TreeMap->Check( key )==0){
        if (!_isQuietMode) std::cout << _MessageTag+"ChangeCurrent failed : cannot find such a key (" << key << ")" << std::endl;
        return false;
    }else{
        _CurrentKey = key;
        return true;
    }
}
//////////////////////////////////////////////////////////
bool BoostXmlParser::
CopyTree( std::string org_key, std::string new_key ){

    if (_TreeMap->Check( org_key )==0){
        if (!_isQuietMode) std::cout << _MessageTag+"ChangeCurrent failed : cannot find such a key (" << org_key << ")" << std::endl;
        return false;
    }else{
        boost::property_tree::ptree* tmp = new boost::property_tree::ptree( *(_TreeMap->Put( org_key )) );
        _TreeMap->Add( new_key, tmp );
        _CurrentKey = new_key;
        return true;
    }
}
//////////////////////////////////////////////////////////
boost::property_tree::ptree* BoostXmlParser::
PutNode( std::string path, std::string attr ){
    if (_CurrentKey=="") {
        if (!_isQuietMode) std::cout << _MessageTag+"PutContent:: no current tree" << std::endl;
        return NULL;
    }
    return PutNode( _CurrentKey, path, attr );
}
//////////////////////////////////////////////////////////
boost::property_tree::ptree* BoostXmlParser::
PutNode( std::string key, std::string path, std::string attr ){
    if (_TreeMap->Check( key )==0){
        if (!_isQuietMode) std::cout << _MessageTag+"PutContent:: no key = "<< key << std::endl;
        return NULL;
    }
    boost::property_tree::ptree* curNode = _TreeMap->Put(key);
    return PutNode( curNode, path, attr );
}
//////////////////////////////////////////////////////////
boost::property_tree::ptree* BoostXmlParser::
PutNode( boost::property_tree::ptree* curNode, std::string path, std::string attr ){
    std::string ret="";
    // trimming
    path = _trimPath( path );

    bool status = false;
    boost::property_tree::ptree& retNode = _getNode( *curNode, path, status, false );
    bool isFound = false;
    if (status){
        if (attr=="") ret =  retNode.data();
        else{
            if ( boost::optional<std::string> opt = retNode.get_optional<std::string>( "<xmlattr>."+attr ) ){
                ret = opt.get();
            }else{
                if (!_isQuietMode) std::cout << _MessageTag+"PutContent >> attribute("+attr+") is not existed in "+path+"." << std::endl;
            }
        }
    }else{
        if (!_isQuietMode) std::cout<< _MessageTag+"PutContent::False to search path=" << path << std::endl;
    }

    return &retNode;
}
//////////////////////////////////////////////////////////
std::vector<boost::property_tree::ptree*> BoostXmlParser::
PutFoundChildNodes( boost::property_tree::ptree* curNode, std::string path){
    std::vector<boost::property_tree::ptree*> ret;
    // trimming
    path = _trimPath( path );

    std::string::size_type ind = path.rfind(".");
    std::string pre_path="";
    std::string tag="";

    if (ind==std::string::npos){
        tag = path;
    }else{
        pre_path = path.substr(0,ind);
        tag = path.substr(ind+1);
    }

    bool status = false;
    boost::property_tree::ptree &retNode=_getNode( *curNode, pre_path, status, false );

    if (status){
        ind = tag.rfind(",");
        if (ind==std::string::npos){
            for (boost::property_tree::ptree::iterator it=retNode.begin(); it!=retNode.end();++it)
                if( (*it).first==tag )
                    ret.push_back( &((*it).second) );
        }else{
            std::string tag_path = tag.substr(0,ind);
            std::string attr_info = tag.substr(ind+1);
            std::string::size_type ind2 = attr_info.find("=");
            if (ind2!=std::string::npos){
                std::string attr_tag = attr_info.substr(0,ind2);
                std::string attr_val = attr_info.substr(ind2+1);
                for (boost::property_tree::ptree::iterator it=retNode.begin(); it!=retNode.end();++it){
                    if( (*it).first==tag_path ){
                        for (boost::property_tree::ptree::iterator it2=(*it).second.begin(); it2!=(*it).second.end();++it2){
                            if ( (*it2).first=="<xmlattr>" ){
                                for (boost::property_tree::ptree::iterator it3=(*it2).second.begin(); it3!=(*it2).second.end();++it3){
                                    if ( ( (*it3).first==attr_tag )&&( (*it3).second.data()==attr_val ) ) ret.push_back( &((*it).second) );
                                }
                            }
                        }
                    }
                }
            }
        }
    }else{
        if (!_isQuietMode) std::cout << _MessageTag+"PutNumOfElements >> not found path="+pre_path << std::endl;
    }

    return ret;
}
//////////////////////////////////////////////////////////
void BoostXmlParser::SetDebugMode( bool isDebugMode ){
    _isDebugMode=isDebugMode;
    _isQuietMode=!(isDebugMode);
}
