// © Copyright 1995, Joseph Bergin. All rights reserved.

#ifndef __Range__
#define __Range__
#include "Error.h"

// A range variable with run time value checks.
template <int Low, int High>
class Range
{	public:
		Range(int v = Low)
		:	_value(v)
		{	if(Low > High) userERROR("Illegal Range type.");
			if(_value<Low || _value>High)
				userERROR("Range error.");
		}

      Range<Low,High> & operator = (const int v)
		{  if(v<Low || v>High)
				userERROR("Range error.");
			_value = v;
			return *this;
		}

		int first()const{return Low;}

		int last()const {return High;}

		Range<Low,High> & operator++()	//preincrement
		{	if(_value == High)
				userERROR("Range error.");
			_value++;
			return *this;
		}

		Range<Low,High> & operator--()	//predecrement
		{	if(_value == Low)
				userERROR("Range error.");
			_value--;
			return *this;
		}
		
		typedef void (*action)(int v, void *);
		
		void forall(action p, void * scope)
		{	for(int i = _value; i<= High; i++)
				p(i,scope);			
		}
// Note, arbitrary information may be passed to p via scope.
// The usual thing is to pass a pointer to a struct. 

		Range<Low, High> operator++(int) // postincrement
		{	if(_value == High)
				userERROR("Range error.");
			Range<Low, High> oldval(*this);
			_value++;
			return oldval;
		}

		Range<Low, High> operator--(int) // postdecrement
		{	if(_value == Low)
				userERROR("Range error.");
			Range<Low, High> oldval(*this);
			_value--;
			return oldval;
		}

		operator int() const // Produce an int
		{ 	return _value; 
		}

	private:
		int _value;

}; // Could provide operators +=, -=, *=, /=

// An array class with arbitrary (checked) subscripts.
// Similar to Pascal's Array[Low..High] of E.
template <int Low, int High, class E>
class FreeArray
{	public:
		FreeArray()
		{	if(Low > High) userERROR("Illegal Array type.");
			_elements = new E[High - Low +1];
			FAILNULL(_elements);
		}

		FreeArray(const E& e)	// All cells initialized to e.
		{	if(Low > High) userERROR("Illegal Array type.");
			_elements = new E[High - Low +1];
			FAILNULL(_elements);
			for(int i = Low; i<= High; i++)
				_elements[i-Low] = e;
		}
		FreeArray(const FreeArray<Low,High,E> & A)
		{	copy(A);
		}

		~FreeArray()
		{	free();
		}

		int first(){return Low;}
		int last() {return High;}

		FreeArray<Low,High,E> & operator=(const FreeArray<Low,High,E> & A)
		{	if(&A != this)
			{	free();
				copy(A);
			}
			return *this;
		}

		E & operator[](Range<Low,High> i)const 
		{	return _elements[i - Low];
		}

	private:
		E * _elements;
		void copy(const FreeArray<Low,High,E> & A)
		{	_elements = new E[High - Low +1];
			FAILNULL(_elements);
			for(int i = Low; i <= High; i++)
				_elements[i - Low] = A._elements[i - Low];
		}

		void free()
		{	delete [] _elements;
		}

};

template <int L1, int H1, int L2, int H2, class E>
// Array [L1..H1, L2..H2] of E 
// Access cells of FreeArray2 X with X(i,j)
class FreeArray2
{	public:
		FreeArray2()
		{ 
		}
		
		FreeArray2(E& e)	// All cells initialized to e.
		{ 	for(int k = L1; k<=H1; k++)
				for(int j = L2; j <= H2; j++)
					_elements[k][j] = e;
		}

		FreeArray<L2,H2,E> & operator[](Range<L1,H1> r) // Extract row r
		{	return _elements[r];
		}

		E& operator()(const Range<L1,H1> f, const Range<L2,H2> s)const // Extract element f,s
		{	return _elements[f][s];
		}
		
	private:
		FreeArray<L1,H1, FreeArray<L2,H2,E> > _elements;
		// Destructor, operator= and copy constructor not needed. memberwise ok.
};

#endif
