//////////////////////////////////////////////////
// (c) MMIII Sven Reichard
// 

# include <ProofNumberNode.h>
# include <iostream>
const int
ProofNumberNode::_INFINITY = 1000000;

int 
ProofNumberNode::instances =0;

int
ProofNumberNode::getNumberOfInstances()
{
  return instances;
};

ProofNumberNode::ProofNumberNode()
  : proofNumber(1),
    disproofNumber(1),
    depth(0),
    height(0),
    expanded(false),
    terminal(false),
    legal(true)
{
  instances ++;
};

ProofNumberNode::~ProofNumberNode()
{
  for (unsigned int i = 0; i < children.size(); i++)
    delete children[i];
  instances --;
};

int
ProofNumberNode::getProofNumber() const
{
  return proofNumber;
};

int
ProofNumberNode::getDisproofNumber() const
{
  return disproofNumber;
};

bool
ProofNumberNode::isExpanded() const
{
  return expanded;
};

bool
ProofNumberNode::needsExpansion() const
{
  return !terminal;
};


bool
ProofNumberNode::isLegal() const
{
  return legal;
};

int
ProofNumberNode::getNumberOfChildren() const
{
  return children.size();
};

ProofNumberNode*
ProofNumberNode::getChild(int i )
{
  return children.at(i);
};

void
ProofNumberNode::expand( int nChildren )
{
  assert(! isExpanded() );
  for (int i = 0; i < nChildren; i++)
    {
      children.push_back( new ProofNumberNode );
      children.back()->height = getHeight()+1;
    }
  expanded = true;
};

bool
ProofNumberNode::adjustNumbers()
{
  if (! isExpanded())
    {
      return true;;
    }
  proofNumber = _INFINITY;
  int oldDisproofNumber = disproofNumber;
  int oldProofNumber = proofNumber;
  disproofNumber = 0;
  depth = 0;
  for (int i =0; i < getNumberOfChildren(); i++)
    {
      ProofNumberNode* child = getChild(i);
      if (! child->isLegal())
	continue;
      if (child->getDisproofNumber() < proofNumber)
	proofNumber = child->getDisproofNumber();
      disproofNumber += child->getProofNumber();
      if (child->getDepth()+1 > depth)
	depth = child->getDepth()+1;
    };
  if (disproofNumber > _INFINITY)
    disproofNumber = _INFINITY;
# if 1
  if ((((height&1) == 1) && (proofNumber == 0)) ||
      (((height&1) == 0) && (disproofNumber == 0)))
    {
      // in this case we can forget all children
      for (std::vector<ProofNumberNode*>::iterator it = children.begin();
	   it != children.end();
	   ++ it)
	delete *it;
      children.resize(0);
    }
  else
# endif
    if ((disproofNumber == 0) || (proofNumber == 0))
    {
      // in this case we have to keep just the good children
      std::vector<ProofNumberNode*>::iterator good = children.begin();
      for (std::vector<ProofNumberNode*>::iterator child = children.begin();
	   child != children.end(); ++ child)
	if ((*child)->getDisproofNumber() == proofNumber)
	  std::iter_swap(good++, child);
      int newSize = good-children.begin();
      for (; good != children.end(); ++ good)
	delete(*good);
      children.resize(newSize);
    }

  return (disproofNumber != oldDisproofNumber)
    || (proofNumber != oldProofNumber);
};

void
ProofNumberNode::setProven()
{
  terminal = true;
  proofNumber = 0;
  depth = 0;
  disproofNumber = _INFINITY;
};

void
ProofNumberNode::setDisproven()
{
  depth = 0;
  terminal = true;
  disproofNumber = 0;
  proofNumber = _INFINITY;
};

int
ProofNumberNode::getChildToExpand() const
{
  int result = -1;
  //int bestDepth = _INFINITY;
  for (unsigned int i = 0; i < children.size(); i++)
    {
      if (!children[i]->isLegal())
	continue;
      if (children[i]->getDisproofNumber() == getProofNumber())
	return i;
    }
  if (result >= 0)
    return result;
  std::cout<<getProofNumber()<<std::endl;
  for (unsigned int i = 0; i < children.size(); i++)
    std::cout<<children[i]->getDisproofNumber()<<" ";
  std::cout<<std::endl;
  std::cout<<needsExpansion()<<std::endl;
  std::cout<<isExpanded()<<std::endl;
  assert(false);
};

short
ProofNumberNode::getHeight() const
{
  return height;
};

SmartPointer<Move>&
ProofNumberNode::getIncomingMove()
{
  return incomingMove;
};

void
ProofNumberNode::setIncomingMove( SmartPointer<Move>& move )
{
  incomingMove = move;
};

int
ProofNumberNode::lengthToMate() const
{
  if (terminal)
    return 0;
  int result = 0;
  for (unsigned int i = 0; i < children.size(); i++)
    if (children[i]->getDisproofNumber() == getProofNumber())
      result = std::max(result, children[i]->lengthToMate() + 1);
  return result;
};
