/*********************************************************
** Copyright (c) 2005
** University of Washington
** Licensed under the terms set forth by University of
** Washington. If you did not sign such a license, you
** are using this software/code illegally and you do not
** have permission to use, modify, or redistribute
** this or any files in this software package.
**
** File: ClusterNode.cpp
**
**********************************************************/
#include "ClusterNode.h"
#include "ClusterException.h"
#include <new>
#include <iostream>

CClusterNode::CClusterNode(void* pData, int index) 
  : m_pParent(NULL), m_pLeft(NULL), m_pRight(NULL), m_pData(pData), m_index(index)
{
#ifdef EDGE_DEBUG
// gah - debug
fprintf(stderr,"%pC\n",this);
#endif
  m_pLeftLeaves = NULL;
  m_pRightLeaves = NULL;
  try {
    m_pLeftLeaves = new NodeVector(0);
    m_pRightLeaves = new NodeVector(0);
  }
  catch(bad_alloc&) {
    delete m_pLeftLeaves;
    delete m_pRightLeaves;
    __throw_cluster_ex(CLUSTEX_OUTOFMEMORY, "Out of memory (bad_alloc)");
  }
}

CClusterNode::CClusterNode(void* pData, int index, CClusterNode* pLeft, CClusterNode* pRight)
  : m_pParent(NULL), m_pLeft(pLeft), m_pRight(pRight), m_pData(pData), m_index(index)
{
#ifdef EDGE_DEBUG
// gah - debug
fprintf(stderr,"%pD\n",this);
#endif
  m_pLeftLeaves = NULL;
  m_pRightLeaves = NULL;
  int ltCount = NULL == pLeft ? 0 : (pLeft->IsLeaf() ? 1 : pLeft->GetLeafCount());
  int rtCount = NULL == pRight ? 0 : (pRight->IsLeaf() ? 1 : pRight->GetLeafCount());
  try {
    m_pLeftLeaves = new NodeVector(ltCount);
    m_pRightLeaves = new NodeVector(rtCount);
  }
  catch(bad_alloc&) {
    delete m_pLeftLeaves;
    delete m_pRightLeaves;
    __throw_cluster_ex(CLUSTEX_OUTOFMEMORY, "Out of memory.");
  }

  if (NULL != m_pLeft)
    {
      m_pLeft->SetParent(this);
      if(m_pLeft->IsLeaf())
	{
	  m_pLeftLeaves->insert(m_pLeftLeaves->end(), m_pLeft);
	}
      else
	{
	  m_pLeftLeaves->insert(m_pLeftLeaves->end(), m_pLeft->GetLeftLeaves()->begin(), m_pLeft->GetLeftLeaves()->end());
	  m_pLeftLeaves->insert(m_pLeftLeaves->end(), m_pLeft->GetRightLeaves()->begin(), m_pLeft->GetRightLeaves()->end());
	}
    }
  if (NULL != m_pRight)
    {
      m_pRight->SetParent(this);
      if(m_pRight->IsLeaf())
	{
	  m_pRightLeaves->insert(m_pRightLeaves->end(), m_pRight);
	}
      else
	{
	  m_pRightLeaves->insert(m_pRightLeaves->end(), m_pRight->GetLeftLeaves()->begin(), m_pRight->GetLeftLeaves()->end());
	  m_pRightLeaves->insert(m_pRightLeaves->end(), m_pRight->GetRightLeaves()->begin(), m_pRight->GetRightLeaves()->end());
	}
    }
}

CClusterNode::~CClusterNode()
{
  delete m_pLeftLeaves;
  delete m_pRightLeaves;
}

int CClusterNode::GetIndex()
{
  return m_index;
}

CClusterNode* CClusterNode::GetParent(){
  return m_pParent;
}


void CClusterNode::SetParent(CClusterNode* pNewParent){
  m_pParent = pNewParent;
}


CClusterNode* CClusterNode::GetLeftChild(){
  return m_pLeft;
}


CClusterNode* CClusterNode::GetRightChild(){
  return m_pRight;
}

void* CClusterNode::GetData()
{
  return m_pData;
}

bool CClusterNode::IsLeaf()
{
  return (NULL == m_pRight && NULL == m_pLeft);
}

void CClusterNode::SwapLeaves()
{
  CClusterNode* pTmp = m_pLeft;
  m_pLeft = m_pRight;
  m_pRight = pTmp;
  
  // also swap LeftLeaves and RightLeaves
  NodeVector* pVec = m_pLeftLeaves;
  m_pLeftLeaves = m_pRightLeaves;
  m_pRightLeaves = pVec;

}

void CClusterNode::WalkLeaves(CClusterNodeFunction* pAction)
{
  if(IsLeaf())
    {
      if (NULL != pAction)
	{
	  pAction->Go(this);
	}
    }
  else
    {
      if (NULL != GetLeftChild())
	{
	  GetLeftChild()->WalkLeaves(pAction);
	}
      if (NULL != GetRightChild())
	{
	  GetRightChild()->WalkLeaves(pAction);
	}
    }
}

void CClusterNode::WalkTree(CClusterNodeFunction* pAction)
{
  if (NULL != pAction)
    {
      pAction->Go(this);
    }
  if (NULL != GetLeftChild())
    {
      GetLeftChild()->WalkTree(pAction);
    }
  if (NULL != GetRightChild())
    {
      GetRightChild()->WalkTree(pAction);
    }
}

bool CClusterNode::IsLeftLeaf(CClusterNode* child)
{
  if (NULL == m_pLeft)
    return false;

  return VectorContains(m_pLeftLeaves, child);
}

bool CClusterNode::IsRightLeaf(CClusterNode* child)
{
  if (NULL == m_pRight)
    return false;

  return VectorContains(m_pRightLeaves, child);
}

bool CClusterNode::VectorContains(NodeVector* pVec, CClusterNode* pTree)
{
  if (NULL == pVec)
    {
      return false;
    }

  for(NodeVector::iterator iter = pVec->begin(); iter != pVec->end(); iter++)
    {
      if( (*iter) == pTree )
	return true;
    }

  return false;
}


inline int CClusterNode::GetLeafCount() 
{ 
  return m_pLeftLeaves->size() + m_pRightLeaves->size(); 

}

void CClusterNode::RecursiveDelete()
{
  if(NULL != m_pRight)
    {
#ifdef EDGE_DEBUG
// gah - debug
fprintf(stderr,"%pR\n",m_pRight);
#endif
      m_pRight->RecursiveDelete();
      delete m_pRight;
      m_pRight = NULL;
    }

  if(NULL != m_pLeft)
    {
#ifdef EDGE_DEBUG
// gah - debug
fprintf(stderr,"%pL\n",m_pLeft);
#endif
      m_pLeft->RecursiveDelete();
      delete m_pLeft;
      m_pLeft = NULL;
    }
}
