#include "ImageComponent.h"
#include <iostream>
#include <boost/filesystem.hpp>
#include <math.h>
#include "../Log.h"
#include "../Renderer.h"
#include "../Window.h"

Vector2u ImageComponent::getTextureSize() 
{
	if(mTexture)
		return mTexture->getSize();
	else
		return Vector2u(0, 0);
}

ImageComponent::ImageComponent(Window* window, int offsetX, int offsetY, std::string path, unsigned int resizeWidth, unsigned int resizeHeight, bool allowUpscale) : GuiComponent(window)
{
	setOffset(Vector2i(offsetX, offsetY));

	//default origin is the center of image
	mOrigin.x = 0.5;
	mOrigin.y = 0.5;

	mOpacity = 255;

	mTiled = false;

	mTargetSize.x = resizeWidth;
	mTargetSize.y = resizeHeight;

	mAllowUpscale = allowUpscale;

	mFlipX = false;
	mFlipY = false;

	if(!path.empty())
		setImage(path);
}

ImageComponent::~ImageComponent()
{
}

void ImageComponent::resize()
{
	if(!mTexture)
		return;

	mSize.x = getTextureSize().x;
	mSize.y = getTextureSize().y;

	//(we don't resize tiled images)
	if(!mTiled && (mTargetSize.x || mTargetSize.y))
	{
		Vector2f resizeScale;

		if(mTargetSize.x && (mAllowUpscale || mSize.x > mTargetSize.x))
		{
			resizeScale.x = (float)mTargetSize.x / mSize.x;
		}
		if(mTargetSize.y && (mAllowUpscale || mSize.y > mTargetSize.y))
		{
			resizeScale.y = (float)mTargetSize.y / mSize.y;
		}

		if(resizeScale.x && !resizeScale.y)
			resizeScale.y = resizeScale.x;
		if(resizeScale.y && !resizeScale.x)
			resizeScale.x = resizeScale.y;

		if(resizeScale.x)
			mSize.x = (int)(mSize.x * resizeScale.x);
		if(resizeScale.y)
			mSize.y = (int)(mSize.y * resizeScale.y);
	}

	if(mTiled)
		mSize = mTargetSize;
}

void ImageComponent::setImage(std::string path)
{
	if(mPath == path)
		return;

	mPath = path;

	mTexture = mWindow->getResourceManager()->getTexture(path);
	resize();
}

void ImageComponent::setOrigin(float originX, float originY)
{
	mOrigin.x = originX;
	mOrigin.y = originY;
}

void ImageComponent::setTiling(bool tile)
{
	mTiled = tile;

	if(mTiled)
		mAllowUpscale = false;

	resize();
}

void ImageComponent::setResize(unsigned int width, unsigned int height, bool allowUpscale)
{
	mTargetSize.x = width;
	mTargetSize.y = height;
	mAllowUpscale = allowUpscale;
	resize();
}

void ImageComponent::setFlipX(bool flip)
{
	mFlipX = flip;
}

void ImageComponent::setFlipY(bool flip)
{
	mFlipY = flip;
}

void ImageComponent::onRender()
{
	if(mTexture && getOpacity() > 0)
	{
		GLfloat points[12], texs[12];
		GLubyte colors[6*4];

		if(mTiled)
		{
			float xCount = (float)mSize.x / getTextureSize().x;
			float yCount = (float)mSize.y / getTextureSize().y;
			
			Renderer::buildGLColorArray(colors, 0xFFFFFF00 | (getOpacity()), 6);
			buildImageArray(0, 0, points, texs, xCount, yCount);
		}else{
			Renderer::buildGLColorArray(colors, 0xFFFFFF00 | (getOpacity()), 6);
			buildImageArray(0, 0, points, texs);
		}

		drawImageArray(points, texs, colors, 6);
	}

	GuiComponent::onRender();
}

void ImageComponent::buildImageArray(int posX, int posY, GLfloat* points, GLfloat* texs, float px, float py)
{
	points[0] = posX - (mSize.x * mOrigin.x);		points[1] = posY - (mSize.y * mOrigin.y);
	points[2] = posX - (mSize.x * mOrigin.x);		points[3] = posY + (mSize.y * (1 - mOrigin.y));
	points[4] = posX + (mSize.x * (1 - mOrigin.x));		points[5] = posY - (mSize.y * mOrigin.y);

	points[6] = posX + (mSize.x * (1 - mOrigin.x));		points[7] = posY - (mSize.y * mOrigin.y);
	points[8] = posX - (mSize.x * mOrigin.x);		points[9] = posY + (mSize.y * (1 - mOrigin.y));
	points[10] = posX + (mSize.x * (1 -mOrigin.x));		points[11] = posY + (mSize.y * (1 - mOrigin.y));



	texs[0] = 0;		texs[1] = py;
	texs[2] = 0;		texs[3] = 0;
	texs[4] = px;		texs[5] = py;

	texs[6] = px;		texs[7] = py;
	texs[8] = 0;		texs[9] = 0;
	texs[10] = px;		texs[11] = 0;

	if(mFlipX)
	{
		for(int i = 0; i < 11; i += 2)
			if(texs[i] == px)
				texs[i] = 0;
			else
				texs[i] = px;
	}
	if(mFlipY)
	{
		for(int i = 1; i < 12; i += 2)
			if(texs[i] == py)
				texs[i] = 0;
			else
				texs[i] = py;
	}
}

void ImageComponent::drawImageArray(GLfloat* points, GLfloat* texs, GLubyte* colors, unsigned int numArrays)
{
	mTexture->bind();

	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	if(colors != NULL)
	{
		glEnableClientState(GL_COLOR_ARRAY);
		glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
	}

	glVertexPointer(2, GL_FLOAT, 0, points);
	glTexCoordPointer(2, GL_FLOAT, 0, texs);

	glDrawArrays(GL_TRIANGLES, 0, numArrays);

	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);

	if(colors != NULL)
		glDisableClientState(GL_COLOR_ARRAY);

	glDisable(GL_TEXTURE_2D);
	glDisable(GL_BLEND);
}

bool ImageComponent::hasImage()
{
	return !mPath.empty();
}


void ImageComponent::copyScreen()
{
	mTexture.reset();

	mTexture = std::make_shared<TextureResource>();
	mTexture->initFromScreen();

	resize();
}