#include "mof/EventScheduler.hpp"
#include "mof/EventCondition.hpp"
#include <list>
#include <utility>
#include "mof/utilities.hpp"


class TimeEventCondition : public mof::EventCondition{
	mof::FrameNumber limit;
	mof::FrameNumber count;

public:
	TimeEventCondition(mof::FrameNumber limit)
		: limit(limit) , count(0)
	{
	}

	virtual ~TimeEventCondition(){}

	virtual bool test(){
		return count == limit;
	}

	virtual bool isDisposable(){
		return count > limit;
	}

	virtual void update(){
		if(limit >= count)count++;
	}
};

struct mof::EventScheduler::Impl{
	typedef std::pair<mof::EventCondition* , boost::function0<void>> Schedule; 
	typedef std::list<std::pair<mof::EventCondition* , boost::function0<void>>> EventList; 
	EventList eventList;

	Impl(){
	}

	~Impl(){
		foreach( Impl::Schedule &value , eventList ){
			delete value.first;
		}
	}

};

mof::EventScheduler::EventScheduler()
: m_pImpl(new Impl())
{
}
	
mof::EventScheduler::EventScheduler(EventScheduler&& rh)
	: m_pImpl(std::move(rh.m_pImpl))
{
}


mof::EventScheduler::~EventScheduler(){
	
}

void mof::EventScheduler::addEvent( mof::EventCondition* pCondition , const boost::function0<void> &action){
	m_pImpl->eventList.push_back(std::pair<mof::EventCondition* , boost::function0<void>>(pCondition , action));
}

void mof::EventScheduler::addEvent(mof::FrameNumber frame, const boost::function0<void> &action){
	addEvent(new TimeEventCondition(frame) , action);
}

void mof::EventScheduler::update(){
	for( Impl::EventList::iterator itr = m_pImpl->eventList.begin() ;
		itr != m_pImpl->eventList.end() ; 
		){
			itr->first->update();
			if(itr->first->test()){
				itr->second();
			}
			if(itr->first->isDisposable()){
				delete itr->first;
				itr = m_pImpl->eventList.erase(itr);
			}
			else ++itr;
	}
}


void mof::EventScheduler::clear(){
	for( Impl::EventList::iterator itr = m_pImpl->eventList.begin() ;
		itr != m_pImpl->eventList.end() ; 
		){
		delete itr->first;
		itr = m_pImpl->eventList.erase(itr);
	}

}

