// $Id: parsetreewalker.cpp,v 1.12 2018/01/03 21:33:06 mkkuhner Exp $

/*
Copyright 2002-2005 Mary K. Kuhner, Peter Beerli, and Joseph Felsenstein

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

/* Authors: Peter Beerli, Mary Kuhner, Jon Yamato and Joseph Felsenstein */


#include "menu_strings.h"   // for menustr::emptyString
#include "parsetreewalker.h"
#include "stringx.h"        // for StripLeadingSpaces and similar
#include "tinyxml.h"
#include "vectorx.h"        // for StringVec1d
#include "xml.h"
#include "xml_strings.h"

using std::string;

ParseTreeWalker::ParseTreeWalker(XmlParser & parser)
    :
    m_parser(parser)
{
}

ParseTreeWalker::~ParseTreeWalker()
{
}

TiXmlElement *
ParseTreeWalker::getSingleDescendantElement(TiXmlElement* ancestor,
                                            string nodeName,bool required)
{
    TiXmlNode * firstChild = ancestor->IterateChildren(nodeName,NULL);
    if(firstChild == NULL)
    {
        if(required)
        {
            m_parser.ThrowInternalXMLError(xmlstr::XML_ERR_MISSING_TAG_0+nodeName+xmlstr::XML_ERR_MISSING_TAG_1);
        }
        return NULL;
    }
    TiXmlNode * secondChild = ancestor->IterateChildren(nodeName,firstChild);
    if (secondChild != NULL)
    {
        m_parser.ThrowInternalXMLError(
            xmlstr::XML_ERR_EXTRA_TAG_0
            +nodeName
            +xmlstr::XML_ERR_EXTRA_TAG_1
            +ancestor->Value()
            +xmlstr::XML_ERR_EXTRA_TAG_2
            +ToString(ancestor->Row()));
        return NULL;
    }
    return firstChild->ToElement();
}

vector<TiXmlElement *>
ParseTreeWalker::getAllOptionalDescendantElements(TiXmlElement* ancestor,
                                                  string nodeName)
{
    vector<TiXmlElement *> returnVec;
    TiXmlNode * child = NULL;
    while((child = ancestor->IterateChildren(nodeName, child)))
    {
        returnVec.push_back(child->ToElement());
    }
    return returnVec;
}

TiXmlElement *
ParseTreeWalker::singleOptionalChild(TiXmlElement* ancestor, string nodeName)
{
    return getSingleDescendantElement(ancestor,nodeName,false);
}

TiXmlElement *
ParseTreeWalker::singleRequiredChild(TiXmlElement* ancestor, string nodeName)
{
    return getSingleDescendantElement(ancestor,nodeName,true);
}

string
ParseTreeWalker::getNodeText(TiXmlElement * node)
{
    string outstring = "";
    TiXmlNode * child = NULL;
    while((child = node->IterateChildren(child)))
    {
        TiXmlHandle handle(child);
        if(handle.Text())
        {
            outstring += child->Value();
        }
    }
    StripLeadingSpaces(outstring);
    StripTrailingSpaces(outstring);
    return outstring;
}

string
ParseTreeWalker::getGraphMLNodeText(TiXmlElement * node)
{
    string instring = "";
    string outstring = "";
    TiXmlNode * child = NULL;
    while((child = node->IterateChildren(child)))
    {
        TiXmlHandle handle(child);
        if(handle.Text())
        {
            instring += child->Value();
        }
    }
    StripLeadingSpaces(instring);
    StripTrailingSpaces(instring);
    
    // fix GraphML tweaks
    rangeset rset = ToRangeSet(instring);
    rangeset::iterator rpair = rset.begin();
    for ( rpair; rpair != rset.end() ; ++rpair)
    {
        const_cast<long&>(rpair->first) =  rpair->first - 1;   // JRMhack to get around const
        const_cast<long&>(rpair->second) = rpair->second - 1;  // JRMhack to get around const
    }
    outstring = ToString(rset);
    return outstring;
}

StringVec1d
ParseTreeWalker::getNodeTextSplitOnWhitespace(TiXmlElement * node)
{
    string allText = getNodeText(node);
    StringVec1d strings;
    FromString(allText,strings);
    return strings;
}

string
ParseTreeWalker::getNodeAttributeValue(TiXmlElement * node, string attrName)
{
    const std::string * attrValue = node->Attribute(attrName);
    if(attrValue)
    {
        return *attrValue;
    }
    else
    {
        return menustr::emptyString;
    }

}

//____________________________________________________________________________________
