/*	Author: Magdin Stoica
	Supervisor: Dr. Ryan Leduc
	
	Project created in conformity with the requirements for the Degree of Master of Engineering in Software Engineering, 
	Computing and Software Department, 
	McMaster University
	2003 - 2007
*/

#pragma once

#include <vector>
#include <memory>
#include "CommonDefinitions.h"
#include "DesState.h"

namespace DESpot
{

class DesStateIterator;
class DesMarkedStateIterator;


class StatePool
{
	//Types
	public:
		typedef std::auto_ptr<DesStateIterator> StateIteratorPtr;

	public:
		StatePool(void);
		~StatePool(void);

	//State access
	public:
		//Returns a state that must exist in the pool. Throws exception if the stateId is not found in the pool
		DesState* getState(const DesState::ID& stateId) const;
		
		//Attempts to find a state with the given ID
		bool	  findState(const DesState::ID& stateId, DesState** ppFoundState = null) const;

		//Attempts to find a state with the given name
		bool	  findState(const std::wstring& stateName, const std::wstring& stateAlias, 
							DesState** ppFoundState = null) const;

		//Attempts to find a state
		bool	  findState(const DesState& state, DesState** ppFoundState = null) const;

	//Pool operations
	public:																		    
		//Adds a new state ot the pool with the properties of the state template. Note that a new ID is assigned to the new state
		const DesState& addNewState(const DesState& stateTemplate);

		//Adds the given state to the pool. Note that it does not make a copy
		void addState(DesState* pStateToAdd);

		//The following group of methods change a state in the pool. They return true if a change was necessary and false
		//if not change was necessary. If a change is performed the state that was changed is returned in the out parameter
		bool changeState(const DesState::ID& stateId, const DesState& newState, const DesState** out_changedState = null);
		bool changeStateName(const DesState::ID& stateId, const std::wstring& newName, const DesState** out_changedState = null);
		bool changeStateAlias(const DesState::ID& stateId, const std::wstring& newAlias, const DesState** out_changedState = null);
		bool changeStateInit(const DesState::ID& stateId, bool isInit, const DesState** out_changedState = null);
		bool changeStateMarking(const DesState::ID& stateId, bool isMarked, const DesState** out_changedState = null);
		bool changeStateReachable(const DesState::ID& stateId, bool isReachable, const DesState** out_changedState = null);

		//resets the reachability of all the states
		void resetReachability(ReachableProp resetValue = eReachableNotVerified);

		//Removes the state with given ID from the pool. It doesn't detroy the state
		DesState* removeState(DesState::ID stateId);

		//Removes the given state from the pool. It doesn't detroy the state
		void      removeState(DesState* pStateToRemove);
	
		//deletes all the states, reverting state pool back to initial state after construction
		void clear();
		
		//Returns the number of states in the pool
		DesState::Count getStateCount() const;

		//Returns the number of marked states in the pool
		DesState::Count getMarkedStateCount() const;

		//Iterator
		DesStateIterator* createIterator() const;
		DesMarkedStateIterator* createMarkedStateIterator() const;

		//returns the last used state ID 
		DesState::ID getLastUsedId() const;

	//Implementation types
	private:
		typedef std::vector<DesState*> StatePoolSet;
		typedef StatePoolSet::const_iterator StateIterator;

	//Implementations methods
	private:
		//Returns an unused ID to be used for a new state before being added to the pool. Once this is called
		//the returned ID will not be used again so it is important to only call this when adding a new state to
		//be used within the automaton
		DesState::ID reserveNewStateID();

	//Data
	private:
		//The set of states in the pool. Note that the set may contain null states that occurred when states were removed from the pool
		StatePoolSet m_statePool;
		
		//The number of states in the pool. Note that we cannot rely on the size of the pool set as the set
		//may contains nulls
		DesState::Count m_stateCount;
		
		//The number of marked states
		DesState::Count m_markedStateCount;

		//State ID management
		DesState::Index m_nextFreeID;
};

} //end of namespace DESpot

