/*********************************************************
** 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: EisenOrdering.cpp
**
**********************************************************/
#include "EisenOrdering.h"
#include "VectorDataFunctions.h"
#include "MsgIds.h"
#include "ClusterException.h"

CEisenOrdering::CEisenOrdering(CWeightFunction* pWeight)
  : m_pWeight(pWeight), m_freeWeight(false),
    m_tracker(0), m_trackerTotal(0)
{
}

CEisenOrdering::CEisenOrdering()
  : m_pWeight(NULL), m_freeWeight(true)
{
  m_pWeight = new CAverageWeight();
}

CEisenOrdering::~CEisenOrdering()
{
  if(m_freeWeight)
    {
      delete m_pWeight ;
      m_pWeight  = NULL;
    }
}

void CEisenOrdering::OrderLeaves(CClusterNode* pCluster, CMatrix* pDistances)
{
  m_trackerTotal = 2*pCluster->GetLeafCount() - 1;
  m_tracker = 0;
  OrderLeavesRecursive(pCluster, pDistances);
}

void CEisenOrdering::OrderLeavesRecursive(CClusterNode* pCluster, CMatrix* pDistances)
{
  // Walk the tree, getting the average of each node.
  // If weight(left) > weight(right) swap nodes

  if (pCluster->IsLeaf())
    return;

  if(pCluster->GetLeftChild() != NULL && pCluster->GetRightChild() != NULL)
    {
      double lw = m_pWeight->GetWeight(pCluster->GetLeftChild());
      double rw = m_pWeight->GetWeight(pCluster->GetRightChild());
      if (lw > rw)
	{
	  pCluster->SwapLeaves();
	}
    }

  if (pCluster->GetLeftChild() != NULL)
    OrderLeavesRecursive(pCluster->GetLeftChild(), pDistances);

  if (pCluster->GetRightChild() != NULL)
    OrderLeavesRecursive(pCluster->GetRightChild(), pDistances);

  DoCallback(m_trackerTotal, m_tracker++, HEURORD_ORDERLEAVES);
}

double CAverageWeight::GetWeight(CClusterNode* pNode)
{
  if (NULL == pNode)
    __throw_cluster_ex(CLUSTEX_NULLARG, "pNode is NULL");

  TDoubleVector* pData = (TDoubleVector*)pNode->GetData();
  if (NULL == pData)
    __throw_cluster_ex(CLUSTEX_NULLARG, "pData is NULL");

  double sum = 0;
  for(TDoubleVector::iterator i = pData->begin() ; i != pData->end() ; i++)
    {
      sum += *i;
    }
  
  double avg = sum / pData->size();

  return avg ;
}

double CTimeOfMaxExpression::GetWeight(CClusterNode* pNode)
{
  if (NULL == pNode)
    __throw_cluster_ex(CLUSTEX_NULLARG, "pNode is NULL");

  TDoubleVector* pData = (TDoubleVector*)pNode->GetData();
  if (NULL == pData)
    __throw_cluster_ex(CLUSTEX_NULLARG, "pData is NULL");

  TDoubleVector::iterator i = pData->begin();

  double maxIndTime = 0;
  double maxInd = (*i);
  i++;

  double time = 0;
  for( ; i != pData->end() ; i++, time++)
    {
      if ((*i) > maxInd)
	{
	  maxInd = *i;
	  maxIndTime = time;
	}
    }
  
  return maxIndTime ;
}

uintmax_t CEisenOrdering::GetMemoryRequirement(CClusterNode* pCluster, CMatrix* pDistances)
{
  return 0;
}
