/*
	Copyright 2016, 2017 Michele "King_DuckZ" Santullo

	This file is part of MyCurry.

	MyCurry 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.

	MyCurry 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 MyCurry.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "tileiterator.hpp"
#include "worldviewport.hpp"
#include "worldgrid.hpp"
#include "compatibility.h"
#include <cassert>
#include <ciso646>

namespace curry {
	namespace {
		const uint16_t g_invalid_index = 0xFFFF;
		vec2i first_col_starting_pixel (const vec2i& parViewportPos, const vec2i& parTileSize) a_pure;

		vec2i first_col_starting_pixel (const vec2i& parViewportPos, const vec2i& parTileSize) {
			const auto& pos = parViewportPos;
			const auto& ts = parTileSize;

			return vec2i(
				(pos.x() > 0 ? -pos.x() % ts.x() : -pos.x()),
				(pos.y() > 0 ? -pos.y() % ts.y() : -pos.y())
			);
		}
	} //unnamed namespace

	TileIterator::TileIterator (WorldViewport* parViewport, bool parEnd) :
		m_viewport(parViewport),
		m_index(parEnd ? g_invalid_index : 0)
	{
		assert(m_viewport);
		m_pixel_pos = first_col_starting_pixel(
			vector_cast<vec2i>(m_viewport->position()),
			m_viewport->world()->tile_size()
		);
	}

	void TileIterator::increment() {
		assert(m_index != vec2i(g_invalid_index));

		const WorldGrid& world = *m_viewport->world();
		vec2i tile_size(world.tile_size());
		auto first_tile_pos = first_col_starting_pixel(
			vector_cast<vec2i>(m_viewport->position()),
			m_viewport->world()->tile_size()
		);
		vec2i pos(tile_size * vector_cast<vec2i>(m_index) + first_tile_pos);

		assert(pos.x() > -tile_size.x() and pos.x() < m_viewport->size().x());
		assert(pos.y() > -tile_size.y() and pos.y() < m_viewport->size().y());

		const float right_border = std::min(
			m_viewport->size().x(),
			static_cast<float>(world_size_pixel(world).x()) - m_viewport->position().x()
		);
		const float bottom_border = std::min(
			m_viewport->size().y(),
			static_cast<float>(world_size_pixel(world).y()) - m_viewport->position().y()
		);

		if (static_cast<float>(pos.x() + tile_size.x()) < right_border) {
			++m_index.x();
		}
		else if (static_cast<float>(pos.y() + tile_size.y()) < bottom_border) {
			m_index.x() = 0;
			++m_index.y();
			m_pixel_pos.x() = first_tile_pos.x();
			m_pixel_pos.y() += tile_size.y();
		}
		else {
			m_index = vec2us(g_invalid_index);
		}
		//std::cout << "got index " << m_index << " pixel " <<
			//m_index * tile_size - m_viewport->position() << '\n';
		m_pixel_pos = tile_size * vector_cast<vec2i>(m_index) + first_tile_pos;
	}

	ScreenTile TileIterator::dereference() const {
		auto index = vector_cast<vec2us>(m_index);
		return ScreenTile {
			m_viewport->tile(index),
			m_pixel_pos
		};
	}

	bool TileIterator::equal (const TileIterator& parOther) const {
		return m_viewport == parOther.m_viewport and
			m_index == parOther.m_index
		;
	}
} //namespace curry
