/*	
	This is to be used like a dynamic 2 dimensional array with inbuilt safety features

	THIS, WHILE TEMPLATED, IS MEANT TO BE USED WITH SIMPLE DATATYPES THAT MAY BE
	COMPARED'<, >', EQUALITY ' = '  ADDITION, SUBTRACTION AND DIVISION OPERATIONS 
	APPLIED TO SUCH DATATYPES. eg, int, float double short etc.

	HOWEVER, OTHER DATATYPES MAY BE USED ONLY IF SUCH OPERATORS such as
	<, >, =, ==, and / are overloaded in these types.

	a simple array structure that has blocks of size the square root of the total size
	of the total array size. Still size constraints with memory, but much better, 
	and practically as fast as a regular array

	Arguments to Grid are (size of x, size of y, intital values for all)


*/

#include <windows.h>
#include <stdio.h>

#ifndef _GRID

#define _GRID


// include section

#include <string.h>


const static int OUT_OF_BOUNDS_ERROR=1;  // integer error thrown by subscripting error


template <class T>
class Grid{

	private:

		struct IArray{	// private struct assisting the Grid

			/*	temporarily commented for VC++ compiler
				IArray(unsigned int x, T init){
	
					X = new T[x];
					memset(X, init, sizeof(T)*x);
				}
			*/


			IArray(){
				X = 0;
			} // This only for VC++ compiler



			void init(unsigned int x, int init){
				
				if (X!=0) delete[] X; 
				X = new T[x];
				memset(X, init, sizeof(T)*x);
			}


			~IArray(){
				if (X !=0)
					delete[] X;
			}

			// MEMBER VARIABLES

			T* X; // X values along a particular column of selected Y
		};

		/////// END OF IArray STRUCT //////////////
	
		
		IArray* Y;
		int initial_value;  // temp until work out how to initialize automatically all values with T

		unsigned int XSize;
		unsigned int YSize;
		unsigned int AccessX;
		unsigned int AccessY;

	public:

		Grid(unsigned int x, unsigned int y, int init){
		//	Y = new IArray[y](x, init); // comment out for VC++ (ok for g++)

			XSize = x;
			YSize = y;
			AccessY = y;
			AccessX = x;
			initial_value = init;

			Y = new IArray[YSize];

			initAll(init);
		}

		// copy constructor

		Grid(const Grid& other){

			XSize = other.XSize;
			YSize = other.YSize;
			AccessY = other.AccessY;
			AccessX = other.AccessX;

			initial_value = other.initial_value;
			
			Y = new IArray[YSize];
			initAll(initial_value); // this line MUST come after new

			for (unsigned int y=0;y<YSize;y++)
				for(unsigned int x=0;x<XSize;x++)
					Y[y].X[x] = other.Y[y].X[x];
			
		}

		Grid& operator=(const Grid& other){

			if (this != &other){
	
				if (Y != 0)
					delete[] Y;

				XSize = other.XSize;
				YSize = other.YSize;
				AccessY = other.AccessY;
				AccessX = other.AccessX;

				initial_value = other.initial_value;
	
				Y = new IArray[YSize];
				initAll(initial_value); // this line MUST come after new
	
				for (unsigned int y=0;y<YSize;y++)
					for(unsigned int x=0;x<XSize;x++)
						Y[y].X[x] = other.Y[y].X[x];

			}// end of if
			return *this;
		}



		~Grid(){
			if (Y !=0)
				delete[] Y;
		}

		


		/////////////////////////////INIT ALL
		void initAll(int init){

			for (unsigned int i=0;i<YSize;i++)
				Y[i].init(XSize, init);
		}




		T operator()(unsigned int x, unsigned int y){	// get value from co-ordinates x, y

			char stuff[100]={0};
			sprintf(stuff, "x=%d, and y=%d",x, y);

			if (x>=AccessX || y>=AccessY) {
				//MessageBox(NULL, stuff, "exception", MB_OK); // to use, uncomment include 
				throw OUT_OF_BOUNDS_ERROR;
			}
			return Y[y].X[x];
		}

		void put(unsigned int x, unsigned int y, T val){

			char stuff[100]={0};
			sprintf(stuff, "x=%d, and y=%d",x, y);

			if (x>=AccessX || y>=AccessY){
				//MessageBox(NULL, stuff, "exception", MB_OK); // to use, uncomment include 
				throw OUT_OF_BOUNDS_ERROR;  // Subscripting Error
			}	
			Y[y].X[x] = val;
		}


		
		void inc(unsigned int x, unsigned int y, T val){

			char hbuff[100]={0};
			sprintf(hbuff, "x=%d, and y=%d",x, y);

			if (x>=AccessX || y>=AccessY){
				MessageBox(NULL, hbuff, "ERROR", MB_OK);
				throw OUT_OF_BOUNDS_ERROR;  // Subscripting Error
			}
			Y[y].X[x] += val;
		}

		
		void dec(unsigned int x, unsigned int y, T val){

			if (x>=AccessX || y>=AccessY) throw OUT_OF_BOUNDS_ERROR;  // Subscripting Error
		
			Y[y].X[x] -= val;
		}


		void set(T* data, unsigned int num){

			unsigned int x=0, y=0, i=0, end=0;

			while (i<num && !end){
	
				Y[y].X[x] = data[i];

				x++; 

				if (x>=XSize){  // reset column and increment row if at end of row
					x=0;
					y++;
				}
				
				if (y>=YSize) end=1;
				i++;
			}			
		}// end of set


		void get(T* data, unsigned int num){

			unsigned int x=0, y=0, i=0, end=0;

			while (i<num && !end){
	
				data[i] = Y[y].X[x];
				x++; 

				if (x>=XSize){  // reset column and increment row if at end of row
					x=0;
					y++;
				}
				
				if (y>=YSize) end=1;
				i++;
			}			
		}// end of get


		unsigned int xsize(){return AccessX;}
		unsigned int ysize(){return AccessY;}

		void SetAccess(unsigned int x, unsigned int y){	// set access to 1-Size: NULL means set to actual size

			if (x==0 || x>XSize) AccessX = XSize;
			else AccessX = x;

			if (y==0 || y>YSize) AccessY = YSize;
			else AccessY = y;
		}
};


#endif