/**
* @file RegressionNode.cpp
* @brief regression node
* @author Sven Sickert
* @date 06/19/2013

*/
#include <iostream>

#include "vislearning/regression/randomforest/RegressionNode.h"

using namespace OBJREC;

using namespace std;
using namespace NICE;

RegressionNode::~RegressionNode()
{
}

RegressionNode::RegressionNode ()
{
  left = NULL;
  right = NULL;
  f = 0;
  counter = 0;
}

RegressionNode *RegressionNode::getLeafNode (
          const NICE::Vector & x,
          int depth )
{
  if ( (!depth) || ((left == NULL) && (right == NULL)) )
    return this;
  
  double val = x[f];
  if ( val < threshold )
    if ( left != NULL )
      return left->getLeafNode ( x, depth - 1 );
    else
      return this;
  else
    if ( right != NULL )
      return right->getLeafNode( x, depth - 1 );
    else
      return this;
}

void RegressionNode::traverse (
          const NICE::Vector & x,
          double & _predVal
                              )
{
  RegressionNode *leaf = getLeafNode ( x );
  _predVal = leaf->predVal;
}

void RegressionNode::statistics ( int & depth, int & count ) const
{
  int dl, cl;
  if ( left != NULL )
  {
    left->statistics ( dl, cl );
    dl++;
  } else {
    dl = 0;
    cl = 0;
  }
  
  if ( right != NULL )
  {
    right->statistics( depth, count );
    depth++;
  } else {
    depth = 0;
    count = 0;
  }
  
  depth = (depth > dl) ? depth : dl;
  count += cl + 1;
}

void RegressionNode::indexDescendants (
          map<RegressionNode *, pair<long, int> > & index,
          long & maxindex,
          int depth ) const
{
  if ( left != NULL )
  {
    maxindex++;
    index.insert ( pair<RegressionNode *, pair<long, int> > ( left, pair<long, int>(maxindex, depth + 1) ) );
    left->indexDescendants ( index, maxindex, depth+1 );
  }
  
  if ( right != NULL )
  {
    maxindex++;
    index.insert ( pair<RegressionNode *, pair<long, int> > ( right, pair<long, int>(maxindex, depth + 1) ) );
    right->indexDescendants ( index, maxindex, depth+1 );
  }
}

void RegressionNode::nodePrediction( 
          const Vector & y,
          const vector<int> & selection )
{
  double mean = 0.0;
  for (int i = 0; i < (int)selection.size(); i++)
  {
    mean += y[ selection[i] ];
  }
  mean = mean/selection.size();
  
  double sum_squares = 0.0;
  for (int i = 0; i < (int)selection.size(); i++)
  {
    double diff = y[ selection[i] ] - mean;
    sum_squares += diff*diff;
  }
  
  lsError = sum_squares;
  predVal = mean;
}

void RegressionNode::resetCounters ()
{
  counter = 0;
  if ( left != NULL ) left->resetCounters();
  if ( right != NULL ) right->resetCounters();
}

void RegressionNode::copy ( RegressionNode *node )
{
    left = node->left;
    right = node->right;
    threshold = node->threshold; 
    f = node->f;
    predVal = node->predVal;
    lsError = node->lsError;
    trainExamplesIndices = node->trainExamplesIndices;
}

bool RegressionNode::isLeaf () const
{
    return ( (right == NULL) && (left == NULL) );
}