/******************************************************************************
 JTableData.h

	Interface for the JTableData Class

	Copyright © 1996 John Lindal. All rights reserved.

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

#ifndef _H_JTableData
#define _H_JTableData

#include <JBroadcaster.h>
#include <JRect.h>

class JTableData : virtual public JBroadcaster
{
public:

	JTableData();
	JTableData(const JTableData& source);

	virtual ~JTableData();

	const JTableData& operator=(const JTableData& source);

	JBoolean	IsEmpty() const;

	JSize		GetRowCount() const;
	JBoolean	RowIndexValid(const JIndex index) const;

	JSize		GetColCount() const;
	JBoolean	ColIndexValid(const JIndex index) const;

	JBoolean	CellValid(const JPoint& cell) const;

protected:

	void	RowAdded();
	void	RowDeleted();
	void	SetRowCount(const JSize newRowCount);

	void	ColAdded();
	void	ColDeleted();
	void	SetColCount(const JSize newColCount);

private:

	JSize itsRowCount;
	JSize itsColCount;

public:

	// JBroadcaster messages

	static const JCharacter* kRowInserted;
	static const JCharacter* kRowDuplicated;
	static const JCharacter* kRowRemoved;
	static const JCharacter* kAllRowsRemoved;
	static const JCharacter* kRowMoved;

	static const JCharacter* kColInserted;
	static const JCharacter* kColDuplicated;
	static const JCharacter* kColRemoved;
	static const JCharacter* kAllColsRemoved;
	static const JCharacter* kColMoved;

	static const JCharacter* kRectChanged;

private:

	// base classes for JBroadcaster messages

	class RowColMessage : public JBroadcaster::Message
		{
		public:

			RowColMessage(const JCharacter* type, const JIndex index)
				:
				JBroadcaster::Message(type),
				itsIndex(index)
				{ };

			JIndex
			GetIndex() const
			{
				return itsIndex;
			};

		private:

			JIndex	itsIndex;
		};

	class RowColMoved : public JBroadcaster::Message
		{
		public:

			RowColMoved(const JCharacter* type,
						const JIndex origIndex, const JIndex newIndex)
				:
				JBroadcaster::Message(type),
				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 RowColDupd : public JBroadcaster::Message
		{
		public:

			RowColDupd(const JCharacter* type,
					   const JIndex origIndex, const JIndex newIndex)
				:
				JBroadcaster::Message(type),
				itsOrigIndex(origIndex),
				itsNewIndex(newIndex)
				{ };

			void	AdjustIndex(JIndex* index) const;

			JIndex
			GetOrigIndex() const
			{
				return itsOrigIndex;
			};

			JIndex
			GetNewIndex() const
			{
				return itsNewIndex;
			};

		private:

			JIndex	itsOrigIndex;	// index -before- row/col was duplicated
			JIndex	itsNewIndex;
		};

public:

	// row messages

	class RowInserted : public RowColMessage
		{
		public:

			RowInserted(const JIndex index)
				:
				RowColMessage(kRowInserted, index)
				{ };

			void	AdjustIndex(JIndex* index) const;

			void
			AdjustCell(JPoint* cell) const
			{
				JIndex rowIndex = cell->y;
				AdjustIndex(&rowIndex);
				cell->y = rowIndex;
			};
		};

	class RowDuplicated : public RowColDupd
		{
		public:

			RowDuplicated(const JIndex origIndex, const JIndex newIndex)
				:
				RowColDupd(kRowDuplicated, origIndex, newIndex)
				{ };

			void
			AdjustCell(JPoint* cell) const
			{
				JIndex rowIndex = cell->y;
				AdjustIndex(&rowIndex);
				cell->y = rowIndex;
			};
		};

	class RowRemoved : public RowColMessage
		{
		public:

			RowRemoved(const JIndex index)
				:
				RowColMessage(kRowRemoved, index)
				{ };

			JBoolean	AdjustIndex(JIndex* index) const;

			JBoolean
			AdjustCell(JPoint* cell) const
			{
				JIndex rowIndex   = cell->y;
				const JBoolean ok = AdjustIndex(&rowIndex);
				cell->y           = rowIndex;
				return ok;
			};
		};

	class AllRowsRemoved : public JBroadcaster::Message
		{
		public:

			AllRowsRemoved()
				:
				JBroadcaster::Message(kAllRowsRemoved)
				{ };
		};

	class RowMoved : public RowColMoved
		{
		public:

			RowMoved(const JIndex origIndex, const JIndex newIndex)
				:
				RowColMoved(kRowMoved, origIndex, newIndex)
				{ };

			void
			AdjustCell(JPoint* cell) const
			{
				JIndex rowIndex = cell->y;
				AdjustIndex(&rowIndex);
				cell->y = rowIndex;
			};
		};

	// column messages

	class ColInserted : public RowColMessage
		{
		public:

			ColInserted(const JIndex index)
				:
				RowColMessage(kColInserted, index)
				{ };

			void	AdjustIndex(JIndex* index) const;

			void
			AdjustCell(JPoint* cell) const
			{
				JIndex colIndex = cell->x;
				AdjustIndex(&colIndex);
				cell->x = colIndex;
			};
		};

	class ColDuplicated : public RowColDupd
		{
		public:

			ColDuplicated(const JIndex origIndex, const JIndex newIndex)
				:
				RowColDupd(kColDuplicated, origIndex, newIndex)
				{ };

			void
			AdjustCell(JPoint* cell) const
			{
				JIndex colIndex = cell->x;
				AdjustIndex(&colIndex);
				cell->x = colIndex;
			};
		};

	class ColRemoved : public RowColMessage
		{
		public:

			ColRemoved(const JIndex index)
				:
				RowColMessage(kColRemoved, index)
				{ };

			JBoolean	AdjustIndex(JIndex* index) const;

			JBoolean
			AdjustCell(JPoint* cell) const
			{
				JIndex colIndex   = cell->x;
				const JBoolean ok = AdjustIndex(&colIndex);
				cell->x           = colIndex;
				return ok;
			};
		};

	class AllColsRemoved : public JBroadcaster::Message
		{
		public:

			AllColsRemoved()
				:
				JBroadcaster::Message(kAllColsRemoved)
				{ };
		};

	class ColMoved : public RowColMoved
		{
		public:

			ColMoved(const JIndex origIndex, const JIndex newIndex)
				:
				RowColMoved(kColMoved, origIndex, newIndex)
				{ };

			void
			AdjustCell(JPoint* cell) const
			{
				JIndex colIndex = cell->x;
				AdjustIndex(&colIndex);
				cell->x = colIndex;
			};
		};

	// element messages

	class RectChanged : public JBroadcaster::Message
		{
		public:

			RectChanged(const JRect& r)
				:
				JBroadcaster::Message(kRectChanged),
				itsRect(r)
				{ };

			// single cell

			RectChanged(const JIndex row, const JIndex col)
				:
				JBroadcaster::Message(kRectChanged),
				itsRect(row, col, row+1, col+1)
				{ };

			RectChanged(const JPoint& cell)
				:
				JBroadcaster::Message(kRectChanged),
				itsRect(cell.y, cell.x, cell.y+1, cell.x+1)
				{ };

			const JRect&
			GetRect() const
			{
				return itsRect;
			};

		private:

			JRect	itsRect;
		};
};


/******************************************************************************
 IsEmpty

	Returns TRUE if there are no items in the JTableData.

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

inline JBoolean
JTableData::IsEmpty()
	const
{
	return JConvertToBoolean( itsRowCount == 0 || itsColCount == 0 );
}

/******************************************************************************
 GetRowCount

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

inline JSize
JTableData::GetRowCount()
	const
{
	return itsRowCount;
}

/******************************************************************************
 RowIndexValid

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

inline JBoolean
JTableData::RowIndexValid
	(
	const JIndex index
	)
	const
{
	return JConvertToBoolean( 1 <= index && index <= itsRowCount );
}

/******************************************************************************
 RowAdded (protected)

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

inline void
JTableData::RowAdded()
{
	itsRowCount++;
}

/******************************************************************************
 SetRowCount (protected)

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

inline void
JTableData::SetRowCount
	(
	const JSize newRowCount
	)
{
	itsRowCount = newRowCount;
}

/******************************************************************************
 GetColCount

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

inline JSize
JTableData::GetColCount()
	const
{
	return itsColCount;
}

/******************************************************************************
 ColIndexValid

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

inline JBoolean
JTableData::ColIndexValid
	(
	const JIndex index
	)
	const
{
	return JConvertToBoolean( 1 <= index && index <= itsColCount );
}

/******************************************************************************
 CellValid

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

inline JBoolean
JTableData::CellValid
	(
	const JPoint& cell
	)
	const
{
	return JConvertToBoolean( RowIndexValid(cell.y) && ColIndexValid(cell.x) );
}

/******************************************************************************
 ColAdded (protected)

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

inline void
JTableData::ColAdded()
{
	itsColCount++;
}

/******************************************************************************
 SetColCount (protected)

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

inline void
JTableData::SetColCount
	(
	const JSize newColCount
	)
{
	itsColCount = newColCount;
}

#endif
