/**
 *  Triangles
 *  Copyright (C) 2016 POSITIVE MENTAL ATTITUDE
 *
 *  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, version 3 of the License.
 *
 *  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/>.
 */

#include "Foreground.hpp"
#include <iostream>
#include <cmath>

Foreground::Foreground(): _wormholePosition(0, 0) {}

Foreground::~Foreground()
{
	for(unsigned i = 0; i < _sprites.size(); ++i)
		_sprites[i].clear();
	_sprites.clear();
	_tiles.clear();
	_normalSprites.clear();
	_normalTiles.clear();
}

const sf::Vector2u Foreground::getSize() const
{
	return {_tileCount.x * _tileSize, _tileCount.y * _tileSize};
}

unsigned const Foreground::tileAlpha(unsigned x, unsigned y, unsigned pixelX, unsigned pixelY)
{
	return _tiles[y * _tileCount.x + x].first.getPixel(pixelX, pixelY).a;
}
 
void Foreground::reloadFromTile(int x, int y, bool neighbouring)
{
	if(x < 0 or y < 0 or x >= (int)_tileCount.x or y >= (int)_tileCount.y)
		return;
		
	if(neighbouring)
	{
		for(int i = -1; i <= 1; ++i)
		{
			if(x + i < 0 or x + i >= (int)_tileCount.x) 
				continue;
			for(int j = -1; j <= 1; ++j)
			{
				if(y + j < 0 or y + j >= (int)_tileCount.y) 
					continue;
				unsigned id = (y + j) * _tileCount.x + (x + i);
				_tiles[id].second.loadFromImage(_tiles[id].first);
				_normalTiles[id].second.loadFromImage(_normalTiles[id].first);
			}
		}
	}
	else
	{
		unsigned id = y * _tileCount.x + x;
		_tiles[id].second.loadFromImage(_tiles[id].first);
		_normalTiles[id].second.loadFromImage(_normalTiles[id].first);
	}
}

void Foreground::reloadFromPixel(int x, int y, bool neighbouring)
{
	reloadFromTile((x / _tileSize), (y / _tileSize), neighbouring);
}

bool Foreground::destroy(unsigned x, unsigned y)
{
	if((x / _tileSize) < 0 or (y / _tileSize) < 0 or (x / _tileSize) >= _tileCount.x or (y / _tileSize) >= _tileCount.y)
		return true;

	unsigned id = ((y / _tileSize) * _tileCount.x) + (x / _tileSize);
	x %= _tileSize;
	y %= _tileSize;
	int a = _tiles[id].first.getPixel(x, y).a;
	if(a > 0)
	{
		_tiles[id].first.setPixel(x, y, sf::Color::Transparent);
		_normalTiles[id].first.setPixel(x, y, sf::Color::Transparent);
		return true;
	}
	else
		return false;
}

const unsigned Foreground::getTileSize() const
{
	return _tileSize;
}

void Foreground::create(sf::Image& foreground, sf::Image& normal, sf::Image& map)
{
	_tileSize = 256;
	_position.x = 0; _position.y = 0;
	_tileCount.x = std::ceil(static_cast<float>(map.getSize().x) / _tileSize);
	_tileCount.y = std::ceil(static_cast<float>(map.getSize().y) / _tileSize);
	_tiles.clear();
	_tiles.resize(_tileCount.x * _tileCount.y);
	_sprites.resize(_tileCount.x);
	_normalTiles.clear();
	_normalTiles.resize(_tileCount.x * _tileCount.y);
	_normalSprites.resize(_tileCount.x);
	for(unsigned i = 0; i < _tileCount.x; ++i)
	{
		_sprites[i].resize(_tileCount.y);
		_normalSprites[i].resize(_tileCount.y);
	}
	for(unsigned i = 0; i < _tiles.size(); ++i)
	{
		_tiles[i].first.create(_tileSize, _tileSize, sf::Color::Yellow);
		_normalTiles[i].first.create(_tileSize, _tileSize, sf::Color::Yellow);
	}
	for(unsigned i = 0; i < _tileCount.x * _tileSize; ++i)
		for(unsigned j = 0; j < _tileCount.y * _tileSize; ++j)
		{
			sf::Color color = foreground.getPixel(i % foreground.getSize().x, j % foreground.getSize().y);
			
			_tiles[j / _tileSize * _tileCount.x + i / _tileSize].first
			.setPixel(i % _tileSize, j % _tileSize, sf::Color(color.r, color.g, color.b, i < map.getSize().x && j < map.getSize().y ? 255 - map.getPixel(i, j).r : 255));
			color = normal.getPixel(i % normal.getSize().x, j % normal.getSize().y);
			_normalTiles[j / _tileSize * _tileCount.x + i / _tileSize].first
			.setPixel(i % _tileSize, j % _tileSize, sf::Color(color.r, color.g, color.b, i < map.getSize().x && j < map.getSize().y ? 255 - map.getPixel(i, j).r : 255));
			
			if(i >= map.getSize().x - 1 || j >= map.getSize().y - 1)
				continue;
			
			if(i == 0 || j == 0)
				continue;
				
			color = map.getPixel(i, j);

			if((int)color.g > 0 && (int)color.g != 255)
			{
				if((int(map.getPixel(i - 1, j).g) == 0 || int(map.getPixel(i - 1, j).g) == 255)
				&& (int(map.getPixel(i , j - 1).g) == 0 || int(map.getPixel(i, j - 1).g) == 255))
				{
					if((int)color.b == 255 && (int)color.g == 100)
						_wormholePosition = sf::Vector2u(i, j);
					else if((int)color.b == 0 && (int)color.g == 250)
						_starPosition.emplace_back(i, j);
				}
			}
		}
	for(unsigned i = 0; i < _tiles.size(); ++i)
	{
		_tiles[i].second.loadFromImage(_tiles[i].first);
		_sprites[i % _tileCount.x][i / _tileCount.x].setTexture(_tiles[i].second);
		_sprites[i % _tileCount.x][i / _tileCount.x].setPosition((i % _tileCount.x) * _tileSize, (i / _tileCount.x) * _tileSize);
		_normalTiles[i].second.loadFromImage(_normalTiles[i].first);
		_normalSprites[i % _tileCount.x][i / _tileCount.x].setTexture(_normalTiles[i].second);
		_normalSprites[i % _tileCount.x][i / _tileCount.x].setPosition((i % _tileCount.x) * _tileSize, (i / _tileCount.x) * _tileSize);
	}
}

void Foreground::create(std::string foreground, std::string normal, std::string map)
{
	sf::Image image1, image2, image3;
	image1.loadFromFile(foreground);
	image2.loadFromFile(normal);
	image3.loadFromFile(map);
	create(image1, image2, image3);
}

void Foreground::setResolution(sf::Vector2u resolution)
{
	sf::Vector2f temp;
	temp.x = static_cast<float>(resolution.x) / static_cast<float>(_tileSize);
	temp.y = static_cast<float>(resolution.y) / static_cast<float>(_tileSize);
	_renderCount = sf::Vector2u(std::ceil(temp.x) + 1, std::ceil(temp.y) + 1);
}

void Foreground::setPosition(sf::Vector2f position)
{
	_position.x = position.x >= 0 ? position.x : 0;
	_position.y = position.y >= 0 ? position.y : 0;
}

void Foreground::renderNormals(bool render)
{
	_renderNormals = render;
}

void Foreground::move(sf::Vector2f movement)
{
	for(unsigned i = 0; i < _renderCount.x; ++i)
		for(unsigned j = 0; j < _renderCount.y; ++j)
		{
			_sprites[i][j].move(movement);
			_normalSprites[i][j].move(movement);
		}
}

void Foreground::rotate(float rotation)
{
	for(unsigned i = 0; i < _renderCount.x; ++i)
		for(unsigned j = 0; j < _renderCount.y; ++j)
		{
			_sprites[i][j].rotate(rotation);
			_normalSprites[i][j].rotate(rotation);
		}
}
void Foreground::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
	unsigned x = _position.x / _tileSize, y = _position.y / _tileSize;
	for(unsigned i = 0; i < _renderCount.x; ++i)
			for(unsigned j = 0; j < _renderCount.y; ++j)
				if(i + x < _tileCount.x and j + y < _tileCount.y)
				{
					if(!_renderNormals)
						target.draw(_sprites[i + x][j + y], states);
					else
						target.draw(_normalSprites[i + x][j + y], states);
				}
}

const sf::Vector2f Foreground::getWormholePosition() const
{
	return sf::Vector2f(_wormholePosition);
}

const bool Foreground::getStarPosition(sf::Vector2f& starPosition)
{
	if(_starPosition.size() == 0) 
		return false;
	
	starPosition = sf::Vector2f(_starPosition.back());
	_starPosition.pop_back();
	return true;
}