#include "MiniXmlReader.hh"
//////////////////////////////////////////////////////////
MiniXmlReader::MiniXmlReader()
{
    MaxLength = 102400;
}
//////////////////////////////////////////////////////////
MiniXmlReader::MiniXmlReader( string xmlFile, string xmlNickname )
{
    MaxLength = 102400;
    Int4 ret = readXmlFile( xmlFile, xmlNickname );
    if (ret<0){
	_showMsg(" Cannot read XML file.");
    }
}
//////////////////////////////////////////////////////////
MiniXmlReader::MiniXmlReader( vector< string > xmlFiles, vector< string > xmlNickname )
{
    MaxLength = 102400;
    clearXmlFiles();
    
    for (UInt4 i=0;i<xmlFiles.size();i++){
	Int4 ret = readXmlFile( xmlFiles[i], xmlNickname[i] );
	if (ret<0){ break; }
    }
}
//////////////////////////////////////////////////////////
MiniXmlReader::~MiniXmlReader()
{
    clearXmlFiles();
}
//////////////////////////////////////////////////////////
void MiniXmlReader::clearXmlFiles()
{
    for (UInt4 i=0; i<vXmlParsers.size(); i++){
	delete vXmlParsers[i];
	vNameXmlFiles[i].clear();
    }
    vNameXmlFiles.clear();
}
//////////////////////////////////////////////////////////
void MiniXmlReader::_showMsg( string message )
{
    cout << "MiniXmlReader ::" << message << endl;
}
//////////////////////////////////////////////////////////
Int4 MiniXmlReader::_searchIndex( string xmlNickname )
{
    Int4 index=-1;
    for (UInt4 i=0; i<vNameXmlFiles.size(); i++){
	if (vNameXmlFiles[i][1]==xmlNickname){
	    index = i;
	    break;
	}
    }
    return index;
}
//////////////////////////////////////////////////////////
mxml_node_t* MiniXmlReader::
_getNode( UInt4 targetId, mxml_node_t* curNode, string pathToContent)
{
    string tmp( pathToContent );
    
    string::size_type ind;
    // If first charactor of path is separator, delete it.
    ind = tmp.find("/");
    if (ind==(string::size_type)(0)){
	tmp = tmp.substr(1);
    }
    
    // If last charactor of path is separator, delete it
    ind = tmp.rfind("/");
    if (ind==(string::size_type)(tmp.size()-1)){
	tmp = tmp.substr(0,ind);
    }
    
    mxml_node_t* ret_node;
    
    ind = tmp.find("/");
    // If this path is last level
    if ( ind==string::npos ){
	// return last node
	ret_node = _getNodeFromAttr( targetId, curNode, tmp );
    }else{
        // If this path is not last one, go next level
	string thisPath = tmp.substr(0,ind);
	string nextPath = tmp.substr(ind+1);
	mxml_node_t *nextNode = _getNodeFromAttr( targetId, curNode, thisPath );
	
	ret_node =  _getNode( targetId, nextNode, nextPath );
    }
    
    return ret_node;
    	
}
//////////////////////////////////////////////////////////
mxml_node_t* MiniXmlReader::
_getNodeFromAttr( UInt4 targetId, mxml_node_t* curNode, string path ){
    string targetTag;
    string attrString;
    string attrName="NULL";
    string attrVal="NULL";
    string::size_type ind1,ind2;

    ind1 = path.find(",");
    if ( ind1==string::npos ){
	targetTag = path;
    }else{
	targetTag = path.substr(0,ind1);
	attrString = path.substr(ind1+1);
	ind2 = attrString.find("=");
	attrName = attrString.substr(0,ind2);
	attrVal = attrString.substr(ind2+1);
	//cout << "targetTag, attrName, attrVal=" << targetTag << "," << attrName <<","<< attrVal << endl;
    }
    
    return vXmlParsers[ targetId ]->FindElement( curNode, curNode, targetTag, attrName, attrVal, MXML_DESCEND);

}
//////////////////////////////////////////////////////////
void MiniXmlReader::
_trimSpaces( string* path ){
    string::size_type ind;
    while((ind = path->find_first_of(" "))!=string::npos){
	path->erase( ind,1 );
    }
}
//////////////////////////////////////////////////////////
Int4 MiniXmlReader::readXmlFile( string xmlFile, string xmlNickname )
{
    // Read XML file
    ifstream ifs(xmlFile.c_str());
    if (!ifs){
        _showMsg( "readXmlFile >> cannot open file. ("+xmlFile+")" );
	return -1;
    }
    ifs.close();
    
    MiniXmlParser *mxmlp = new MiniXmlParser();
    mxml_node_t *tree = mxmlp->ReadXmlTree( xmlFile );
    if (tree==NULL){
	_showMsg( "readXmlFile >> Failed to ReadXmlTree. ("+xmlFile+")" );
	return -1;
    }
    vXmlParsers.push_back( mxmlp );
    vector<string> xmlInfo;
    xmlInfo.push_back( xmlFile );
    xmlInfo.push_back( xmlNickname );
    vNameXmlFiles.push_back( xmlInfo );
    
    return 0;
}
//////////////////////////////////////////////////////////
bool MiniXmlReader::hasPath( string xmlNickname, string pathToContent)
{
    bool ret = false;
    
    Int4 index = _searchIndex( xmlNickname );
    
    _trimSpaces( &pathToContent );
    //cout << "trim=" << pathToContent << endl;
    if (index!=-1){
	mxml_node_t *result = _getNode( index, vXmlParsers[index]->PutXmlTree(), pathToContent );
	if (result==NULL){
	    _showMsg( "hasPath >> Cannot find such path ("+pathToContent+")" );
	}else{
	    ret = true;
	}
    }else{
        _showMsg( "hasPath >> No such nickname ("+xmlNickname+")" );
    }
	
    return ret;
}
//////////////////////////////////////////////////////////
string MiniXmlReader::putTextContent( string xmlNickname, string pathToContent, string attrName )
{
    string ret;
    
    Int4 index = _searchIndex( xmlNickname );
    
    _trimSpaces( &pathToContent );
    //cout << "trim=" << pathToContent << endl;
    if (index!=-1){
	mxml_node_t *tree = vXmlParsers[index]->PutXmlTree();
	mxml_node_t *result = _getNode( index, tree, pathToContent );
	if (result==NULL){
	    _showMsg( "putTextContent >> Cannot find such path ("+pathToContent+")" );
	}else{
	    if (attrName=="NULL"){
		//cout << "attrName=NULL" << endl;
		mxml_node_t *targetNode = vXmlParsers[index]->WalkNext( result, tree );
		ret = vXmlParsers[index]->PutString(targetNode, MaxLength);

	    }else{
		//cout << "attrName=" << attrName << endl;
		ret = vXmlParsers[index]->PutAttr( result, attrName, MaxLength );
	    }
	}
    }else{
        _showMsg( "putTextContent >> No such nickname ("+xmlNickname+")" );
    }	
    
    
    return ret;
}
//////////////////////////////////////////////////////////
UInt4 MiniXmlReader::putNumOfFiles()
{
    return vXmlParsers.size();
}
//////////////////////////////////////////////////////////
