/******************************************************************************
 JOrderedSet.h

	Interface for JOrderedSet class

	Copyright © 1994-97 by John Lindal. All rights reserved.

 ******************************************************************************/

#ifndef _H_JOrderedSet
#define _H_JOrderedSet

#include <JCollection.h>
#include <JOrderedSetIterator.h>

// namespace to own JBroadcaster messages, etc (template is unnecessary)

class JOrderedSetT
{
public:

	enum SortOrder
	{
		kSortAscending,
		kSortDescending
	};

	enum CompareResult
	{
		kFirstLessSecond,
		kFirstEqualSecond,
		kFirstGreaterSecond
	};

	enum SearchReturn
	{
		kFirstMatch,
		kLastMatch,
		kAnyMatch
	};

public:

	// for all objects

	static const JCharacter* kElementsInserted;
	static const JCharacter* kElementsRemoved;
	static const JCharacter* kAllElementsRemoved;

	// for JBroadcasters

	static const JCharacter* kElementMoved;
	static const JCharacter* kElementsSwapped;
	static const JCharacter* kElementChanged;
	static const JCharacter* kSorted;

	// for iterators

	static const JCharacter* kGoingAway;
	static const JCharacter* kCopied;

private:

	// base class for JBroadcaster messages

	class ElementMessage : public JBroadcaster::Message
		{
		public:

			ElementMessage(const JCharacter* type,
						   const JIndex firstIndex, const JSize count)
				:
				JBroadcaster::Message(type),
				itsFirstIndex(firstIndex),
				itsCount(count)
				{ };

			JIndex
			GetFirstIndex() const
			{
				return itsFirstIndex;
			};

			JIndex
			GetLastIndex() const
			{
				return itsFirstIndex + itsCount-1;
			};

			JSize
			GetCount() const
			{
				return itsCount;
			};

			JBoolean
			Contains(const JIndex index) const
			{
				return JConvertToBoolean(
						GetFirstIndex() <= index && index <= GetLastIndex() );
			};

		private:

			JIndex	itsFirstIndex;
			JSize	itsCount;
		};

public:

	// for all objects

	class ElementsInserted : public ElementMessage
		{
		public:

			ElementsInserted(const JIndex firstIndex, const JSize count)
				:
				ElementMessage(kElementsInserted, firstIndex, count)
				{ };

			void	AdjustIndex(JIndex* index) const;
		};

	class ElementsRemoved : public ElementMessage
		{
		public:

			ElementsRemoved(const JIndex firstIndex, const JSize count)
				:
				ElementMessage(kElementsRemoved, firstIndex, count)
				{ };

			JBoolean	AdjustIndex(JIndex* index) const;
		};

	class AllElementsRemoved : public JBroadcaster::Message
		{
		public:

			AllElementsRemoved()
				:
				JBroadcaster::Message(kAllElementsRemoved)
				{ };
		};

	// for JBroadcasters

	class ElementMoved : public JBroadcaster::Message
		{
		public:

			ElementMoved(const JIndex origIndex, const JIndex newIndex)
				:
				JBroadcaster::Message(kElementMoved),
				itsOrigIndex(origIndex),
				itsNewIndex(newIndex)
				{ };

			void	AdjustIndex(JIndex* index) const;

			JIndex
			GetOrigIndex() const
			{
				return itsOrigIndex;
			};

			JIndex
			GetNewIndex() const
			{
				return itsNewIndex;
			};

		private:

			JIndex	itsOrigIndex;
			JIndex	itsNewIndex;
		};

	class ElementsSwapped : public JBroadcaster::Message
		{
		public:

			ElementsSwapped(const JIndex index1, const JIndex index2)
				:
				JBroadcaster::Message(kElementsSwapped),
				itsIndex1(index1),
				itsIndex2(index2)
				{ };

			void	AdjustIndex(JIndex* index) const;

			JIndex
			GetIndex1() const
			{
				return itsIndex1;
			};

			JIndex
			GetIndex2() const
			{
				return itsIndex2;
			};

		private:

			JIndex	itsIndex1;
			JIndex	itsIndex2;
		};

	class ElementChanged : public ElementMessage
		{
		public:

			ElementChanged(const JIndex index)
				:
				ElementMessage(kElementChanged, index, 1)
				{ };
		};

	class Sorted : public JBroadcaster::Message
		{
		public:

			Sorted()
				:
				JBroadcaster::Message(kSorted)
				{ };
		};

	// for iterators

	class GoingAway : public JBroadcaster::Message
		{
		public:

			GoingAway()
				:
				JBroadcaster::Message(kGoingAway)
				{ };
		};

	class Copied : public JBroadcaster::Message
		{
		public:

			Copied()
				:
				JBroadcaster::Message(kCopied)
				{ };
		};
};


// pure virtual template class

template <class T>
class JOrderedSet : public JCollection
{
	friend class JOrderedSetIterator<T>;

public:

	JOrderedSet();
	JOrderedSet(const JOrderedSet<T>& source);

	virtual ~JOrderedSet();

	virtual void	InsertElementAtIndex(const JIndex index, const T& data) = 0;

	void	PrependElement(const T& data);
	void	AppendElement(const T& data);

	void			RemoveElement(const JIndex index);
	virtual void	RemoveNextElements(const JIndex firstIndex, const JSize count) = 0;
//	virtual void	RemovePrevElements(const JIndex lastIndex, const JSize count) = 0;
	void			RemoveElements(const JOrderedSetT::ElementsRemoved& info);
	virtual void	RemoveAll() = 0;	// separate so derived classes can optimize

	virtual const T	GetElement(const JIndex index) const = 0;
	virtual void	SetElement(const JIndex index, const T& data) = 0;

	const T	GetFirstElement() const;
	const T	GetLastElement() const;

	// the second version has a different name to avoid shadowing

	virtual void	MoveElementToIndex(const JIndex currentIndex,
									   const JIndex newIndex) = 0;
	void			MoveElementToIndexWithMsg(const JOrderedSetT::ElementMoved& info);

	virtual void	SwapElements(const JIndex index1, const JIndex index2) = 0;
	void			SwapElementsWithMsg(const JOrderedSetT::ElementsSwapped& info);

	virtual JOrderedSetIterator<T>*
		NewIterator(const JIteratorPosition start = kJIteratorStartAtBeginning,
					const JIndex index = 0);
	virtual JOrderedSetIterator<T>*
		NewIterator(const JIteratorPosition start = kJIteratorStartAtBeginning,
					const JIndex index = 0) const;

	// sorting functions -- virtual so they can be optimized for particular storage methods

	#ifdef __MWERKS__
	JOrderedSetT::CompareResult (*GetCompareFunction())(const T&, const T&) const;
	#else
	JOrderedSetT::CompareResult (*GetCompareFunction() const)(const T&, const T&);
	#endif

	void	SetCompareFunction(JOrderedSetT::CompareResult (*compareFn)(const T&, const T&));

	JOrderedSetT::SortOrder	GetSortOrder() const;
	void					SetSortOrder(const JOrderedSetT::SortOrder order);

	virtual void	Sort();

	JBoolean	InsertSorted(const T& data, const JBoolean insertIfDuplicate = kTrue,
							 JIndex* index = NULL);
	JIndex		GetInsertionSortIndex(const T& data, JBoolean* isDuplicate = NULL) const;

	JBoolean	SearchSorted(const T& target, const JOrderedSetT::SearchReturn which,
							 JIndex* index) const;

	virtual JIndex	SearchSorted1(const T& target,
								  const JOrderedSetT::SearchReturn which,
								  JBoolean* found) const;

protected:

	void	OrderedSetAssigned(const JOrderedSet<T>& source);
	void	NotifyIterators(const JBroadcaster::Message& message);

private:

	JOrderedSetT::CompareResult	(*itsCompareFn)(const T&, const T&);

	JOrderedSetT::SortOrder		itsSortOrder;
	JOrderedSetIterator<T>*		itsFirstIterator;	// linked list of active iterators

private:

	// must be overridden

	const JOrderedSet<T>& operator=(const JOrderedSet<T>& source);
};

#endif
