#if !defined(AFX_COLORCMatrix_H__138A3C06_93D3_4A65_80F8_3D9F2CF43EC4__INCLUDED_)
#define AFX_COLORCMatrix_H__138A3C06_93D3_4A65_80F8_3D9F2CF43EC4__INCLUDED_
#include <assert.h>
////////////////
//Interface
////////////////
//!A Two dimensional matrix class
/*!
The only things defined in this class are the necessary files for creating 2 dimensional array type things.
The Math functions are implemented separately in 'matrixarith'
There are no requirements placed upon the type used by this class.  It can hold anything.
*/
template<class T>
class CMatrix  
{
public:
	CMatrix();
	CMatrix(int x, int y);
	virtual ~CMatrix();

	//These two operators are for accessing the arrays different ways.
	//The first is for two dimensional access, while the second is for one dimensional access.
	//It is assumed that most accesses will be two dimensional.

        /// Maximum defined x value (1 greater than the farthest element to the right)
	int		   xmax() {return Xmax;};
        /// Maximum defined y value (1 greater than the farthest element at the bottom)
	int		   ymax() {return Ymax;};
        /// Minimum defined x value (farthest left element)
	int		   xmin() {return Xmin;};
        /// Minimum defined y value (closest to top element)
	int		   ymin() {return Ymin;};
        /// Total number of elements in the matrix
	int		   size() {return TotSize;};
        /// Total width of image 
	int		   x()	  {return TotX;};
	/// Total height of image
	int		   y()	  {return TotY;};
	/// Access an individual element using this.
	T &        operator()( const unsigned int x, const unsigned int y);
	/// Used to copy one matrix to another using the assignment operator
	CMatrix<T>& operator=(CMatrix<T> &RHS);
        /// Performs bilinear interpolation (given the four nearest neighbors).  
	double     interpolate( double x, double y);
        /// Useful if you consider the matrix to be single dimensional by lining up the rows.
	T &        operator[]( const unsigned int val){return m_CMatrix[val];};
	/// Stores 'val' at all locations in the matrix.
        void Initialize(T val){for(int i=0; i<size(); i++) m_CMatrix[i]=val;};
	
	/*!
        Set the maximum and minimum values for the range of the CMatrix;
	This will resize the CMatrix to the necessary size, adding or deleting the necessary amount.
	Please note that this requires the creation of more memory before the destruction of the old memory.
	
	If you don't care about copying the old values from the array, set copy=false.  Otherwise, ignore it (don't put a value there)
	*/
        void SetRange(int xtop, int ytop, int xbottom, int ybottom, bool copy=true);

	/// Set the range based upon another matrix.
	void SetRange(CMatrix<T> OLD, bool copy=true){SetRange(OLD.xmin(),OLD.ymin(),OLD.xmax(),OLD.ymax(),copy);};

	/// This sets the minimum CMatrix coordinates to (0,0), and the max to x, y
	void SetSize(int x, int y); //Sets the CMatrix size of the current CMatrix
	/// The actual data that stores the matrix.  Don't ruin the pointers.  Generally, don't mess with this unless you really, really need to be clever.
        T *m_CMatrix,*zeroloc; //I'm hesitant to do this, but sometimes you need to give the location of this out.				
protected:
	int Xmin,Ymin,Xmax,Ymax, TotSize, TotX, TotY;

};







//////////////////////////////////////////////////////////////////////
//  implementation of the colorCMatrix class.
//
//////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

template<class T>
CMatrix<T>::CMatrix():
Xmin(0),Ymin(0),Xmax(0),Ymax(0),TotSize(0), TotX(0), TotY(0)
{
}

template<class T>
CMatrix<T>::CMatrix(int x, int y):
Xmin(0),Ymin(0),Xmax(x),Ymax(y),TotSize(x*y), TotX(x), TotY(y)
{
	m_CMatrix=new T[x*y];
}


//////////////////////////////////////////////////////////////////////
// Operators
//////////////////////////////////////////////////////////////////////
template<class T>
T&        CMatrix<T>::operator()( const unsigned int x, const unsigned int y)
{
	assert(x>=Xmin && x<Xmax);
	assert(y>=Ymin && y<Ymax);
	return zeroloc[ TotX * y + x  ];
}


template<class T>
double		CMatrix<T>::interpolate(double x, double y)
{
	double fpartx, fparty, x1,y1;
	fpartx=modf(x,&x1);
	fparty=modf(y,&y1);
	return	(*this)((int)x1,(int)y1)*(1-fpartx)*(1-fparty)+ 
			(*this)((int)x1+1,(int)y1)*fpartx*(1-fparty)+
			(*this)((int)x1,(int)y1+1)*(1-fpartx)*fparty+
			(*this)((int)x1+1,(int)y1+1)*fpartx*fparty;
}


template<class T>
CMatrix<T> &	CMatrix<T>::operator=(CMatrix<T> &RHS)
{
	SetRange(RHS.xmin(),RHS.ymin(),RHS.xmax(),RHS.ymax(),false);
	for(int i=0; i<TotSize; i++)
		m_CMatrix[i]=RHS[i];
	return *this;
}

//////////////////////////////////////////////////////////////////////
// Range Stuff
//////////////////////////////////////////////////////////////////////
template<class T>
void CMatrix<T>::SetRange(int xtop, int ytop, int xbottom, int ybottom, bool copy) //Sets the CMatrix size of the current CMatrix
{
	int i, j;
	assert(xtop<xbottom);
	assert(ytop<ybottom);
	if(xtop!=Xmin || ytop!=Ymin || xbottom!=Xmax || ybottom!=Ymax)
	{
		T * tempzero,* tempCMatrix = new T[(xtop-xbottom)*(ytop-ybottom)];
		//this line sets the pointer in the array to (0,0)
		tempzero=tempCMatrix+(xtop-xbottom) * (-ytop) - xtop;
//	for(i=0; i<(xtop-xbottom)*(ytop-ybottom); i++)
//		tempCMatrix[i]=0; //Not sure if this is necessary
	if(copy)
	{
		Xmin=Xmin>xtop?Xmin:xtop;
		Xmax=Xmax<xbottom?Xmax:xbottom;
		Ymin=Ymin>ytop?Ymin:ytop;
		Ymax=Ymax<ybottom?Ymax:ybottom;
		for(i=Xmin; i<Xmax; i++)
			for(j=Ymin; j<Ymax; j++)
				tempzero[((xbottom-xtop) * j + i)] = (*this)(i,j);
	}
	if(TotSize>0)
		delete [] m_CMatrix;
		zeroloc=tempzero;
		m_CMatrix=tempCMatrix;
		Xmin=xtop;
		Ymin=ytop;
		Xmax=xbottom;
		Ymax=ybottom;
		TotSize=(xtop-xbottom)*(ytop-ybottom);
		TotX=xbottom-xtop;
		TotY=ybottom-ytop;
	}
}


template<class T>
void CMatrix<T>::SetSize(int x, int y) //Sets the CMatrix size of the current CMatrix
{
	SetRange(0,0,x,y);
}

template<class T>
CMatrix<T>::~CMatrix()
{
	if(TotSize>0) 	delete [] m_CMatrix;
}

#endif // !defined(AFX_COLORCMatrix_H__138A3C06_93D3_4A65_80F8_3D9F2CF43EC4__INCLUDED_)
