#include "Arbitrator.h"
//#include "Windows.h"
#include "BaseModel.h"
#include "BaseModelConsistencyMonitor.h"
#include "BuildOrderTemplate.h"

//************************************
// Method:    monitor
// FullName:  Arbitrator::monitor
// Access:    public 
// Returns:   void
// Comments:  This method ensures that running tasks are monitored.
//************************************
void Arbitrator::monitor()
{

	int line=1;
	for (deque<TaskBase*>::iterator i = activeTasks.begin(); i != activeTasks.end(); ++i)
	{
		TaskBase* cur = *i;
		if(cur->getBuildType() != UnitTypes::None) {
			////Broodwar->drawTextScreen5,16*line,"- %ss", cur->getBuildType().getName().c_str());
		}
		line++;
	}
	
	// first monitor the staged tasks
//	////Broodwar->drawTextScreen100,175,"staged tasks: %d", stagedTasks.size());
	if(!stagedTasks.empty()) {
		deque<TaskBase*>::iterator it = stagedTasks.begin();
		while(it != stagedTasks.end() && !stagedTasks.empty())
		{
			TaskBase* currentTask = *it;

			if(currentTask->isInitialized()) {
				if(declareNewTask(currentTask)) {
					it = stagedTasks.erase(it);
					if(it == stagedTasks.end() || stagedTasks.empty()) {
						break;
					}
					break;
				}
			} else {
			if(currentTask->canInitialize()) {	
				if(declareNewTask(currentTask)) {
					it = stagedTasks.erase(it);
					if(it == stagedTasks.end() || stagedTasks.empty()) {
						break;
					}
					break;
				}
			}
		}
			//if(it != stagedTasks.end()) {
				it++;
				if(it == stagedTasks.end()) {
					break;
				}
			//}
		}
	}

	if(activeTasks.empty()){
		return;
	}
	
	for (deque<TaskBase*>::iterator itt = activeTasks.begin(); itt != activeTasks.end(); ++itt)
	{
		TaskBase* currentTask = *itt;
		if(currentTask->isFinished()) {
			itt = activeTasks.erase(itt);

			if(itt == activeTasks.end() || activeTasks.empty()) {
				break;
			}
		} else {
			// manage tasks that are initialized, but not yet executing
			// ie. expansions, where the probe has to move into position
			// before we can begin execution
			
			if(currentTask->isInitialized()) {
			
				if(currentTask->isExecuting()) {
					
					// if we're running the task, just monitor it
					currentTask->monitor();
				} else {
					// try to execute now
					// except for if it's an expansion task, since they can be initialised and not executing for a little while
					if(currentTask->getTaskType() != EXPAND) {

						currentTask->execute();								
					}
					break;	  
				}
			} else {
				// in case a task has to be reset due to catastrophic failiure
			
				if(currentTask->canInitialize()) {
					break; 
				}
			}
		}
	}
}

//************************************
// Method:    declareNewTask
// FullName:  Arbitrator::declareNewTask
// Access:    public 
// Returns:   bool
// Parameter: TaskBase * t
// Comments:  Declares and determines if a new task can be undertaken by the system.
//************************************
bool Arbitrator::declareNewTask( TaskBase* t )
{

	if(t->execute()) {
	//	////////Broodwar->sendText(">>>>>>>>>>>>>>> task executing");
		if(t->getBuildType() == UnitTypes::Protoss_Pylon || ((t->getTaskType() == EXPAND || t->getTaskType() == CONSTRUCTION) && t->isUrgent())) {
			activeTasks.push_front(t);
		} else {
			activeTasks.push_back(t);
		}
		return true;
	}
	//////////Broodwar->sendText("************ task failed to execute");
	return false;
}

//************************************
// Method:    stageNewTask
// FullName:  Arbitrator::stageNewTask
// Access:    public 
// Returns:   bool
// Parameter: TaskBase * t
// Comments:  Stages a task to be managed by the system.
//************************************
bool Arbitrator::stageNewTask( TaskBase* t )
{
	if(t->isInitialized()) {
		stagedTasks.push_back(t);
			return true;
	}  else {
		if(t->canInitialize()) {
			if(t->getBuildType() == UnitTypes::Protoss_Pylon || ((t->getTaskType() == EXPAND || t->getTaskType() == CONSTRUCTION) && t->isUrgent())) {
				stagedTasks.push_front(t);
			} else {
				stagedTasks.push_back(t);
			}
			return true;
		}
	}

	return false;
}

int Arbitrator::countProjectedUnitsOfType( UnitType t, int window )
{
	int projectedCount = 0;
	int curExamined = 0;
	for (deque<TaskBase*>::iterator i = stagedTasks.begin(); i != stagedTasks.end(); ++i)
	{
		TaskBase* currentTask = *i;
		if(currentTask->getBuildType() == t) {	
			projectedCount++;
		}
		if(curExamined >= window) {
			break;
		} else {
			curExamined++;
		}
	}



	return projectedCount;
}

bool Arbitrator::isStagedToBeBuilt( UnitType t )
{
	for (deque<TaskBase*>::iterator i = stagedTasks.begin(); i != stagedTasks.end(); ++i)
	{
		TaskBase* currentTask = *i;
		if(currentTask->getBuildType() == t) {	
			return true;
		}
	}
	for (deque<TaskBase*>::iterator i = activeTasks.begin(); i != activeTasks.end(); ++i)
	{
		TaskBase* currentTask = *i;
		if(currentTask->getBuildType() == t) {	
			return true;
		}
	}


	return false;
}

deque<TaskBase*> Arbitrator::getActiveTasks()
{
	return activeTasks;
}

bool Arbitrator::stageNewTaskUrgent( TaskBase* t )
{
	stagedTasks.push_front(t);
	return true;
}
