 /* 
 * array2D-mk2.h- Redo of the array 2D code
 * Copyright (C) 2018, D Haley
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef ARRAY2D_H_
#define ARRAY2D_H_

template<typename T>
class Array2D {
	private:
		unsigned int nWidth,nHeight;
		T * data; //Square memory block

	public:
		Array2D(){ data=0;};
		Array2D(unsigned int w, unsigned int h) { data=0; resize(w,h);}
		~Array2D() { if(data) delete[] data; }

		Array2D<T> &operator=( const Array2D<T> &rhs) 
		{
			if (this == &rhs)
				return *this;

			//reallocate
			resize(rhs.nWidth,rhs.nHeight);
			//copy
			memcpy(data,rhs.data,nWidth*nHeight*sizeof(T));

			return *this;
		}
		void resize(unsigned int w, unsigned int h) {
			nWidth=w;
			nHeight=h;
			if(data)
				delete[] data;
			data = new T[nWidth*nHeight];

		};

		void set(unsigned int x, unsigned int y, const T &v)
		{
			ASSERT(data);
			ASSERT(x < nWidth && y < nHeight);
			data[nWidth*y+x] = v;
		};
		T get(unsigned int x, unsigned int y) const
		{
			ASSERT(data);
			ASSERT(x < nWidth && y < nHeight);
			return data[nWidth*y + x];
		};
		
		T &getRef(unsigned int x, unsigned int y)
		{
			ASSERT(data);
			ASSERT(x < nWidth && y < nHeight);
			return data[nWidth*y + x];
		};
		
		const T &getCRef(unsigned int x, unsigned int y) const
		{
			ASSERT(x < nWidth && y < nHeight);
			return data[nWidth*y + x];
		};

		void unpack(std::vector<std::vector<T> > &unpackData) const
		{
			unpackData.resize(nHeight);
#pragma omp parallel for
			for(unsigned int ui=0;ui<nHeight; ui++)
			{
				unpackData[ui].resize(nWidth);
				for(unsigned int uj=0;uj<nWidth;uj++)
					unpackData[ui][uj]=get(uj,ui);
			}
		}

		void clear()
		{
			delete[] data;
			data=0;
		}

		size_t size() const { if(data) return nWidth*nHeight; return 0;}

		bool empty() const { return data == 0;}

		size_t height() const { return nHeight;}
		size_t width() const { return nWidth;}
};
#endif	
