#pragma once

#include "volumeshop.h"

#include <vector>
#include "Color.h"

class Image
{
public:

	Image(const unsigned int uWidth = 1, const unsigned int uHeight = 1) : m_uWidth(uWidth), m_uHeight(uHeight)
	{/*
		glGenTextures(1,&m_uTexture);
		const GLenum glError = glGetError();

		if (glError != GL_NO_ERROR)
		{
			std::cerr << "Error generating texture (" << gluErrorString(glError) << ")." << std::endl << std::endl;
			exit(EXIT_FAILURE);
		}
*/
		m_vecData.resize(m_uWidth*m_uHeight);
		m_vecData[0] = Color(0,0,0,0);
	};

	Image(const unsigned int uWidth, const unsigned int uHeight, const Color *pData) : m_uWidth(uWidth), m_uHeight(uHeight)
	{
/*
		glGenTextures(1,&m_uTexture);
		const GLenum glError = glGetError();

		if (glError != GL_NO_ERROR)
		{
			std::cerr << "Error generating texture (" << gluErrorString(glError) << ")." << std::endl << std::endl;
			exit(EXIT_FAILURE);
		}
*/
		m_vecData.resize(m_uWidth*m_uHeight);
		memcpy((void*) &(m_vecData[0]),(void*) pData, m_uWidth*m_uHeight*sizeof(Color));
	};

	~Image()
	{
/*
		if (m_uTexture)
		{
			glDeleteTextures(1,&m_uTexture);
			const GLenum glError = glGetError();

			if (glError != GL_NO_ERROR)
			{
				std::cerr << "Error deleting texture (" << gluErrorString(glError) << ")." << std::endl << std::endl;
				exit(EXIT_FAILURE);
			}
		}
*/
	};

	const unsigned int GetWidth() const
	{
		return m_uWidth;
	};

	const unsigned int GetHeight() const
	{
		return m_uHeight;
	};

	void Set(const unsigned int uX, const unsigned int uY, const Color &colValue)
	{
		m_vecData[uX+m_uWidth*uY] = colValue;
	};

	void Set(const Color *pData)
	{
		memcpy((void*) &(m_vecData[0]),(void*) pData, m_uWidth*m_uHeight*sizeof(Color));
	};

	const Color & Get(const unsigned int uX, const unsigned int uY) const
	{
		return m_vecData[uX+m_uWidth*uY];
	};

	const Color * Get() const
	{
		return &(m_vecData[0]);
	};

	void update() const
	{
		bind();

		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

		glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,m_uWidth,m_uHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);

		for (unsigned int i=0;i<m_uHeight;i++)
			glTexSubImage2D(GL_TEXTURE_2D,0,0,m_uHeight-1-i,m_uWidth,1,GL_RGBA,GL_UNSIGNED_BYTE,(void*) &(m_vecData[i*m_uWidth]));

		release();

	};

	void bind()  const
	{
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D,m_uTexture);
	};

	void release() const
	{
		glBindTexture(GL_TEXTURE_2D,0);
		glDisable(GL_TEXTURE_2D);
	};

	const Image & operator*=(const float fOther)
	{
		for (unsigned int i=0;i<m_vecData.size();i++)
			m_vecData[i] *= fOther;

		return *this;
	};

	const Image & operator/=(const float fOther)
	{
		for (unsigned int i=0;i<m_vecData.size();i++)
			m_vecData[i] /= fOther;

		return *this;
	};

	const Image & operator+=(const Image &imgOther)
	{
		const unsigned int uWidth = std::min(GetWidth(),imgOther.GetWidth());
		const unsigned int uHeight = std::min(GetHeight(),imgOther.GetHeight());

		for (unsigned int j=0;j<uHeight;j++)
			for (unsigned int i=0;i<uWidth;i++)
				m_vecData[i+j*m_uWidth] += imgOther.Get(i,j);

		return *this;
	};

	const Image & operator-=(const Image &imgOther)
	{
		const unsigned int uWidth = std::min(GetWidth(),imgOther.GetWidth());
		const unsigned int uHeight = std::min(GetHeight(),imgOther.GetHeight());

		for (unsigned int j=0;j<uHeight;j++)
			for (unsigned int i=0;i<uWidth;i++)
				m_vecData[i+j*m_uWidth] -= imgOther.Get(i,j);

		return *this;
	};

	const Image operator*(const float fOther) const
	{
		Image imgNew = *this;
		imgNew *= fOther;
		return imgNew;
	};

	const Image operator/(const float fOther) const
	{
		Image imgNew = *this;
		imgNew *= fOther;
		return imgNew;
	};

	const Image operator+(const Image &imgOther) const
	{
		Image imgNew = *this;
		imgNew += imgOther;
		return imgNew;
	};

	const Image operator-(const Image &imgOther) const
	{
		Image imgNew = *this;
		imgNew -= imgOther;
		return imgNew;
	};

private:

	unsigned int m_uTexture;
	unsigned int m_uWidth;
	unsigned int m_uHeight;
	std::vector<Color> m_vecData;
};