// Copyright (C) 1999 Jean-Marc Valin & Dominic Letourneau


#include "Iterator.h"
#include "Node.h"
#include "ObjectRef.h"
#include "UserException.h"

//@implements core
using namespace std;

namespace FD {

/***************************************************************************/
/*
  Iterator::Iterator(...)
  Dominic Letourneau
 */
/***************************************************************************/
Iterator::Iterator (string nodeName, ParameterSet params) 
   : Network(nodeName, params)
   , exit_status(false) 

{
   translator = NULL;
   conditionNode = NULL;
   
   //FIXME: this should be set dynamically.
   output.resize(30);
}

void Iterator::stop() {
  //cerr << "Setting exit_status" << endl;
   exit_status = true;
   Network::stop();
}


/***************************************************************************/
/*
  Iterator::getOutput(...)
  Dominic Letourneau
 */
/***************************************************************************/
ObjectRef Iterator::getOutput (int output_id, int count) {
   
   if (!hasOutput(output_id)) throw new NodeException (this, "Cannot getOutput id",__FILE__,__LINE__);

   if (processCount != count) {

      try {
         
         //Reinitialization of all the processCount in our Network
         map<string,Node*>::iterator iter;         
 
         if (processCount != -1) {

            for (iter = nodeDictionary.begin(); iter != nodeDictionary.end(); iter++) {
               (*iter).second->reset();
            }

         }
         //We are doing a little trick for the translator (real inputNode)
         //if it exists
         if (translator) {
            translator->setProcessCount(count);
         }

         int conditionID = conditionNode->translateOutput("OUTPUT");

         int pc = 0;
	 
	 /*So we never return garbage*/
	 int out_id=0;
	 while (sinkNode->hasOutput(out_id))
	 {
	    output[out_id] = nilObject;
	    out_id++;
	 }

         while(1)
         {
	   if (exit_status)
	     throw new UserException;
            if (doWhile)
            {
	       int out_id=0;
	       while (sinkNode->hasOutput(out_id))
	       {
		  output[out_id] = sinkNode->getOutput(out_id,pc);
		  out_id++;
		  if (exit_status)
		    throw new UserException;
	       }
            }
            ObjectRef condition = conditionNode->getOutput(conditionID,pc);
	   if (exit_status)
	     throw new UserException;
            
            if (dereference_cast<bool>(condition)==false) break;
            if (!doWhile)
            {
	       int out_id=0;
	       while (sinkNode->hasOutput(out_id))
	       {
		  output[out_id] = sinkNode->getOutput(out_id,pc);
		  out_id++;
		  if (exit_status)
		    throw new UserException;
	       }
	    }
            pc++;
         }
      }
      catch (BaseException *e) {
         //Something weird happened
         //e->print();
         throw e->add (new NodeException (this,string("Error in Iterator::getOutput"), __FILE__,__LINE__));
      }
      processCount = count;
      }


   return output[output_id];   
}

/***************************************************************************/
/*
  Iterator::connectToNode(...)
  Dominic Letourneau
 */
/***************************************************************************/
void Iterator::connectToNode(unsigned int in, Node *inNode, unsigned int out) {
 
   if (!inputNode) 
      throw new NodeException(this,"Trying to connect without input node",__FILE__,__LINE__);

   if (!translator) {
      //let's add our translator node
      translator = new InputTranslator("ITERATOR_TRANSLATOR",ParameterSet());  
      addNode (*translator);   
   }

   int translator_out = translator->addInput(this->getInputs()[in].name);

   // Connecting the inputNode
   inputNode->connectToNode(in,translator,translator_out);

   // We are connecting the translator
   translator->connectToNode(translator_out,inNode,out);

}
/***************************************************************************/
/*
  Iterator::initialize(...)
  Dominic Letourneau
 */
/***************************************************************************/   
void Iterator::initialize() {

   if (!conditionNode) {
      throw new NodeException(this,"No condition Node specified in Iterator",__FILE__,__LINE__);
   }

   // We must initialize the conditionNode before
   
   conditionNode->initialize();
   
   this->Network::initialize();
   
   if (parameters.exist("DOWHILE"))
   {
   
     ObjectRef param = parameters.get("DOWHILE");
   
     if (!param.isNil()) {
       if (dereference_cast<bool> (parameters.get("DOWHILE"))) {
         doWhile = true;
       }
       else {
         doWhile = false;
       }
     }
     else {
       doWhile = false;
     }
   } else {
     doWhile = false;
   }
   processCount = -1;
}

void Iterator::reset()
{
   processCount = -1;
   Network::reset();
}

}//namespace FD


syntax highlighted by Code2HTML, v. 0.9.1