/*	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 <assert.h>
#include "CommonDefinitions.h"
#include "Iterator.h"

namespace DESpot
{
	template<class ItemClass, class ConstItemClass>
	class LinkedCompositeIterator :	public Iterator<ItemClass, ConstItemClass>
	{
		public:
			LinkedCompositeIterator(Iterator<ItemClass, ConstItemClass>* pFirstIt, 
									Iterator<ItemClass, ConstItemClass>* pSecondIt,
									bool ownFirstIt = true, bool ownSecondIt = true):
                                        m_firstIt(*pFirstIt),
                                        m_ownFirstIt(ownFirstIt),
                                        m_secondIt(*pSecondIt),
                                        m_ownSecondIt(ownSecondIt)
                        {
			}
			
			virtual ~LinkedCompositeIterator(void)
			{
				if (m_ownFirstIt)
				{
					delete &m_firstIt;
				}

				if (m_ownSecondIt)
				{
					delete &m_secondIt;
				}
			}

		//Iteration Operations
		public:
			virtual void first() const
			{
				m_firstIt.first();
				m_secondIt.first();
				
			}
			
			virtual void next() const
			{
				if (m_firstIt.isDone() && m_secondIt.isDone())
					throw EX("Iteration is already at the end. Call isDone() before calling next()")

				if (m_firstIt.isDone() == false)
				{
					//Try to go to the next item in the first iterator since we are not yet done
					m_firstIt.next();

					if (m_firstIt.isDone())
					{
						//The first iterator was already pointing to the last item
						//Start with the items in the second iterator
						m_secondIt.first();
					}
				}
				else
				{
					//Done with the items in the first iterator, iterate through the second one
					m_secondIt.next();
				}
			}
			
			virtual bool isDone() const
			{
				if (m_firstIt.isDone() && m_secondIt.isDone())
					return true;

				return false;
			}
			
			virtual ItemClass currentItem()
			{
				if (isDone())
					throw EX("Iterator already done. Call isDone() before calling currentItem()")

				if (m_firstIt.isDone() == false)
				{
					//Still iterating through th first iterator so return its current item
					return m_firstIt.currentItem();
				}
				
				//First iterator is done, so we must be iterating through the second iterator
				if (m_secondIt.isDone() == false)
				{
					return m_secondIt.currentItem();
				}

				assert(false);
				throw EX("Invalid iterator state. It is not possible for both iterators to be done")
			}
			
			virtual ConstItemClass currentItem() const
			{
				if (isDone())
					throw EX("Iterator already done. Call isDone() before calling currentItem()")

				if (m_firstIt.isDone() == false)
				{
					//Still iterating through th first iterator so return its current item
					return m_firstIt.currentItem();
				}
				
				//First iterator is done, so we must be iterating through the second iterator
				if (m_secondIt.isDone() == false)
				{
					return m_secondIt.currentItem();
				}

				assert(false);
				throw EX("Invalid iterator state. It is not possible for both iterators to be done")
			}


		private:
			//no copying allowed
			LinkedCompositeIterator(const LinkedCompositeIterator& other) : 
					m_firstIt(other.m_firstIt), 
					m_secondIt(other.m_secondIt) 
			{}
			
			LinkedCompositeIterator& operator=(const LinkedCompositeIterator& other) 
			{}

		private:
			Iterator<ItemClass, ConstItemClass>& m_firstIt;
			bool m_ownFirstIt;

			Iterator<ItemClass, ConstItemClass>& m_secondIt;
			bool m_ownSecondIt;
	};

} //end of namespace DESpot

