#ifndef exaustcombine_c_
#define exaustcombine_c_

#include<string.h>
#include<stdlib.h>

#include "Stack.c"


/**
 * This method will exaustive combine all elements in the current stack to create a new stack.
 * @param stack The current stack of the program.
 * @param score The method to score a stack element.
 * @param getScore The method for getting the score of the stack element.
 * @param compare The method to compare two stack elements.
 * @param combine The method of combining two stack elements to create a new stack element.
 * @return 0 if no problems, error codes otherwise.
 **/
int exaustCombine( Stack *stack, float (*score)(void*), float (*getScore)(void*),
		   float (*compare)(void*,void*), void *(*combine)(void*,void*) )
{
  Stack *temp = newStack( -1, stack->mDeleteData, stack->mSetNodeData );
  StackNode *currTarget = stack->mTop, *currCombine;
  PickObject *po;
  int *wasPushed = (int*)malloc( sizeof( int ) * ( stack->mSize * stack->mSize  ) );
  int newPickObjectCount = 0;

  // For each element in the stack, combine it with all other elements.
  while ( currTarget != NULL )
  {
    currCombine = stack->mTop;
    // Go through each element of the stack and combine it with the current target element.
    while ( currCombine != NULL )
    {
      // If the current target and the current combine element are not the same memory, combine them.
      if ( currCombine != currTarget ) 
      {
	po = combine( currTarget->mData, currCombine->mData );
	newPickObjectCount++;
	wasPushed[newPickObjectCount] = 0;
	// If the combine didn't fail, add it to the temp stack.
	if ( po != NULL )
	{
	  po->mScore = score( po );
	  push( po, temp );
	}
      }
      currCombine = currCombine->mPrev;
    }
    currTarget = currTarget->mPrev;
  }

  // Now that we have a second stack of newly combined elements, go through and attempt to insert each one into the original stack.
  StackNode *currNode = temp->mTop;
  int count = 0;
  while ( currNode != NULL )
  {
    if ( pushWithScore( compare, currNode->mData, stack ) == 0 )
    {
      wasPushed[count] = 1;
    }
    currNode = currNode->mPrev;
    count++;
  }
  
  // Now that we have added all of the combine elements, delete the ones that were not put into the new stack.
  currNode = temp->mTop;
  count = 0;
  int noNew = -1;
  while( currNode != NULL )
  {
    if ( wasPushed[count] == 0 )
    {
      StackNode *t = currNode->mPrev;
      temp->mDeleteData( currNode->mData );
      free( currNode );
      currNode = t;
    }
    else
    {
      noNew = 0;
      currNode = currNode->mPrev;
    }
    count++;
  }

  free( temp );
  return noNew;
}

#endif
