/* Copyright (c) <2003-2011> <Julio Jerez, Newton Game Dynamics>
 * 
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 * 
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 * 
 * 1. The origin of this software must not be misrepresented; you must not
 * claim that you wrote the original software. If you use this software
 * in a product, an acknowledgment in the product documentation would be
 * appreciated but is not required.
 * 
 * 2. Altered source versions must be plainly marked as such, and must not be
 * misrepresented as being the original software.
 * 
 * 3. This notice may not be removed or altered from any source distribution.
 */

#include "dgStdafx.h"
#include "dgNode.h"

dgInitRtti(dgBaseNode);

dgBaseNode::dgBaseNode(const dgBaseNode &clone) :
    dgRef(clone)
{
  dgBaseNode *obj;
  dgBaseNode *newObj;

  Clear();

  for (obj = clone.child; obj; obj = obj->sibling)
  {
    newObj = (dgBaseNode *) obj->CreateClone();
    newObj->Attach(this);
    newObj->Release();
  }
}

dgBaseNode::~dgBaseNode()
{
  dgBaseNode *ptr;
  dgBaseNode *tmp;

  if (child)
  {
    for (ptr = child; ptr && ptr->Release(); ptr = tmp)
    {
      ptr->Kill();
      tmp = ptr->sibling;
      ptr->parent = NULL;
      ptr->sibling = NULL;
    }
  }

  for (ptr = sibling; ptr && ptr->Release(); ptr = tmp)
  {
    ptr->Kill();
    tmp = ptr->sibling;
    ptr->parent = NULL;
    ptr->sibling = NULL;
  }
}

void dgBaseNode::CloneFixUp(const dgBaseNode &clone)
{
  dgBaseNode *obj;
  dgBaseNode *cloneChild;

  _ASSERTE(GetNameID() == clone.GetNameID());

  cloneChild = clone.GetChild();
  for (obj = child; obj; obj = obj->sibling)
  {
    obj->CloneFixUp(*cloneChild);
    cloneChild = cloneChild->GetSibling();
  }
}

/*
 void dgBaseNode::Save (
 dgFile &file, 
 dgSaveType saveType,
 void* context) const
 {
 dgBaseNode *obj;

 for (obj = child; obj; obj = obj->sibling) {
 obj->Save (file, saveType, context);
 }
 }
 */

void dgBaseNode::Attach(dgBaseNode *parentArg, bool addFirst)
{
  dgBaseNode *obj;
  _ASSERTE(!parent);
  _ASSERTE(!sibling);
  _ASSERTE(parentArg);

  parent = parentArg;
  if (parent->child)
  {
    if (addFirst)
    {
      sibling = parent->child;
      parent->child = this;
    }
    else
    {
      for (obj = parent->child; obj->sibling; obj = obj->sibling)
      {

      }
      obj->sibling = this;
    }
  }
  else
  {
    parent->child = this;
  }

  AddRef();
}

void dgBaseNode::Detach()
{
  if (parent)
  {
    if (parent->child == this)
    {
      parent->child = sibling;
    }
    else
    {
      dgBaseNode *ptr;
      for (ptr = parent->child; ptr->sibling != this; ptr = ptr->sibling)
      {

      }
      ptr->sibling = sibling;
    }
    parent = NULL;
    sibling = NULL;
    Release();
  }
}

dgBaseNode* dgBaseNode::GetRoot() const
{
  const dgBaseNode *root;
  for (root = this; root->parent; root = root->parent)
  {

  }
  return (dgBaseNode*) root;
}

dgBaseNode* dgBaseNode::GetFirst() const
{
  dgBaseNode *ptr;

  for (ptr = (dgBaseNode *) this; ptr->child; ptr = ptr->child)
  {

  }
  return ptr;
}

dgBaseNode* dgBaseNode::GetNext() const
{
  dgBaseNode *x;
  dgBaseNode *ptr;

  if (sibling)
  {
    return sibling->GetFirst();
  }

  x = (dgBaseNode *) this;
  for (ptr = parent; ptr && (x == ptr->sibling); ptr = ptr->parent)
  {
    x = ptr;
  }
  return ptr;
}

dgBaseNode* dgBaseNode::GetLast() const
{
  dgBaseNode *ptr;

  for (ptr = (dgBaseNode *) this; ptr->sibling; ptr = ptr->sibling)
  {

  }
  return ptr;
}

dgBaseNode* dgBaseNode::GetPrev() const
{
  dgBaseNode *x;
  dgBaseNode *ptr;

  if (child)
  {
    return child->GetNext();
  }

  x = (dgBaseNode *) this;
  for (ptr = parent; ptr && (x == ptr->child); ptr = ptr->child)
  {
    x = ptr;
  }
  return ptr;
}

dgBaseNode* dgBaseNode::Find(dgUnsigned32 nameCRC) const
{
  dgBaseNode *ptr;

  for (ptr = GetFirst(); ptr; ptr = ptr->GetNext())
  {
    if (nameCRC == ptr->GetNameID())
    {
      break;
    }
  }
  return ptr;
}

bool dgBaseNode::SanityCheck()
{
  return true;
}

void dgBaseNode::PrintHierarchy(dgFile &file, char *indent) const
{
  dgBaseNode *node;
  char newIndent[1024];

  sprintf(newIndent, "%s   ", indent);
  for (node = child; node; node = node->sibling)
  {
    node->PrintHierarchy(file, newIndent);
  }
}

void dgBaseNode::DebugPrint(const char *fileName)
{
  /*
   char indent[512];

   indent[0] = '\0';
   dgFile file (fileName, "w");
   PrintHierarchy (file, indent); 
   */
}

