/** \file
 *
 *  Contains the MissionNode class implementation.
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 *
 */

#include "MissionNode.h"

#include "../../Lib/tinyxml/tinyxml.h"

MissionNode::MissionNode( const char* rootName )
    : xmlNode_( new TiXmlDocument( rootName ) ),
      heldNode_( NULL )
{
    xmlNode_->SetUserData( this );
}

MissionNode::~MissionNode()
{
    TiXmlNode* childXmlNode;
    while( NULL != ( childXmlNode = xmlNode_->FirstChild() ) )
    {
        MissionNode* childMissionNode = dynamic_cast<MissionNode*>( ( MissionNode* )childXmlNode->GetUserData() );
        if( NULL != childMissionNode )
        {
            delete childMissionNode;
        }
        else
        {
            xmlNode_->RemoveChild( childXmlNode );
        }
    }
    TiXmlNode* parentXmlNode = xmlNode_->Parent();
    if( NULL != parentXmlNode )
    {
        parentXmlNode->RemoveChild( xmlNode_ );
        xmlNode_ = NULL;
    }
    else
    {
        delete xmlNode_;
        xmlNode_ = NULL;
    }

    if( NULL != heldNode_ )
    {
        delete heldNode_;
    }
}

const char* MissionNode::getName()
{
    return getTextValue();
}

const char* MissionNode::getTextValue()
{
    return xmlNode_->Value();
}

bool MissionNode::hasChildNodes()
{
    return !xmlNode_->NoChildren();
}

MissionNode* MissionNode::getChild( const char* name )
{
    TiXmlNode* childNode = xmlNode_->FirstChildElement( name );
    while( NULL != childNode )
    {
        MissionNode* missionNode = dynamic_cast<MissionNode*>( ( MissionNode* )childNode->GetUserData() );
        if( NULL != missionNode )
        {
            return missionNode;
        }
        childNode = childNode->NextSiblingElement( name );
    }
    return NULL;
}

MissionNode* MissionNode::getFirstChild( bool ignoreTextNodes )
{
    TiXmlNode* childNode = ignoreTextNodes ? xmlNode_->FirstChildElement() : xmlNode_->FirstChild();
    while( NULL != childNode )
    {
        MissionNode* missionNode = dynamic_cast<MissionNode*>( ( MissionNode* )childNode->GetUserData() );
        if( NULL != missionNode )
        {
            return missionNode;
        }
        childNode = ignoreTextNodes ? childNode->NextSiblingElement() : childNode->NextSibling();
    }
    return NULL;
}

MissionNode* MissionNode::getNextSibling( bool ignoreTextNodes )
{
    TiXmlNode* childNode = ignoreTextNodes ? xmlNode_->NextSiblingElement() : xmlNode_->NextSibling();
    while( NULL != childNode )
    {
        MissionNode* missionNode = dynamic_cast<MissionNode*>( ( MissionNode* )childNode->GetUserData() );
        if( NULL != missionNode )
        {
            return missionNode;
        }
        childNode = ignoreTextNodes ? childNode->NextSiblingElement() : xmlNode_->NextSibling();
    }
    return NULL;
}

bool MissionNode::isElement()
{
    return xmlNode_->Type() == TiXmlNode::ELEMENT;
}

bool MissionNode::isText()
{
    return xmlNode_->Type() == TiXmlNode::TEXT;
}

bool MissionNode::hasAttribute( const char* name )
{
    TiXmlElement* element = xmlNode_->ToElement();
    if( NULL == element )
    {
        return false;
    }

    return NULL != element->Attribute( name );
}

const char* MissionNode::getAttribute( const char* name )
{
    TiXmlElement* element = xmlNode_->ToElement();
    if( NULL == element )
    {
        return NULL;
    }

    return element->Attribute( name );
}

const char* MissionNode::getAttribute( const char* name, int& writeTo )
{
    TiXmlElement* element = xmlNode_->ToElement();
    if( NULL == element )
    {
        return NULL;
    }

    return element->Attribute( name, &writeTo );
}

const char* MissionNode::getAttribute( const char* name, double& writeTo )
{
    TiXmlElement* element = xmlNode_->ToElement();
    if( NULL == element )
    {
        return NULL;
    }

    return element->Attribute( name, &writeTo );
}

bool MissionNode::setAttribute( const char* name, const char* value )
{
    TiXmlElement* element = xmlNode_->ToElement();
    if( NULL == element )
    {
        return false;
    }

    element->SetAttribute( name, value );
    return true;
}

bool MissionNode::setAttribute( const char* name, const int value )
{
    TiXmlElement* element = xmlNode_->ToElement();
    if( NULL == element )
    {
        return false;
    }

    element->SetAttribute( name, value );
    return true;
}

bool MissionNode::setAttribute( const char* name, const double value )
{
    TiXmlElement* element = xmlNode_->ToElement();
    if( NULL == element )
    {
        return false;
    }

    element->SetDoubleAttribute( name, value );
    return true;
}

const char* MissionNode::getChildTextValue()
{
    TiXmlNode* childNode = xmlNode_->FirstChild();
    if( NULL != childNode )
    {
        return childNode->Value();
    }
    return "";
}

void MissionNode::setName( const char* name )
{
    xmlNode_->SetValue( name );
}

MissionNode* MissionNode::appendChild( const char* name )
{
    TiXmlElement* newXmlElement = new TiXmlElement( name );
    MissionNode* newMissionNode = new MissionNode( newXmlElement );
    xmlNode_->LinkEndChild( newXmlElement );
    return newMissionNode;
}

MissionNode* MissionNode::appendChildText( const char* text )
{
    TiXmlText* newXmlText = new TiXmlText( text );
    xmlNode_->LinkEndChild( newXmlText );
    return this;
}

MissionNode* MissionNode::insertChildBefore( MissionNode* insertBefore, const char* name )
{
    TiXmlElement xmlElement( name );
    TiXmlNode* beforeNode = insertBefore->xmlNode_;
    TiXmlNode* newXmlNode = xmlNode_->InsertBeforeChild( beforeNode, xmlElement );
    MissionNode* newMissionNode( NULL );
    if( NULL != newXmlNode )
    {
        newMissionNode = new MissionNode( newXmlNode );
    }
    return newMissionNode;
}

MissionNode* MissionNode::insertChildAfter( MissionNode* insertAfter, const char* name )
{
    TiXmlElement xmlElement( name );
    TiXmlNode* afterNode = insertAfter->xmlNode_;
    TiXmlNode* newXmlNode = xmlNode_->InsertAfterChild( afterNode, xmlElement );
    MissionNode* newMissionNode( NULL );
    if( NULL != newXmlNode )
    {
        newMissionNode = new MissionNode( newXmlNode );
    }
    return newMissionNode;
}

void MissionNode::debugPrint()
{
    TiXmlDocument* doc = xmlNode_->ToDocument();
    if( NULL != doc )
    {
        doc->Print();
    }
}

MissionNode::MissionNode( TiXmlNode* xmlNode )
    : xmlNode_( xmlNode ),
      heldNode_( NULL )
{
    xmlNode_->SetUserData( this );
    if( xmlNode->Type() == TiXmlNode::ELEMENT || xmlNode->Type() == TiXmlNode::DOCUMENT )
    {
        TiXmlNode* childXmlNode = xmlNode_->FirstChild();
        while( NULL != childXmlNode )
        {
            new MissionNode( childXmlNode );
            childXmlNode = childXmlNode->NextSibling();
        }
    }
}
