/* Copyright 2015, Michele Santullo
 * This file is part of DoorKeeper.
 *
 * DoorKeeper 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.
 *
 * DoorKeeper 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 DoorKeeper.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <gtest/gtest.h>
#include "doorkeeper/helpers/asciimapsource.hpp"
#include "doorkeeper/doorkeeper.hpp"
#include "doorkeeper/components/pixelconv.hpp"
#include "asciimapsource.hpp"
#include <sstream>
#include <memory>

const char asciimapsource::map_data[] =
	"1101111001\n1101111001\n1110111100\n1110111000\n"
	"1111011011\n1111010111\n1111101111\n1111111111\n";
const dk::CoordinateScalarType asciimapsource::tile_size = 64;
const dk::CoordinateScalarType asciimapsource::map_width = 10;
const dk::CoordinateScalarType asciimapsource::map_height = 8;

asciimapsource::asciimapsource() :
	tiler(coords2(tile_size)),
	layer(nullptr)
{
	std::istringstream iss((std::string(map_data)));
	loader.reset(new dkh::AsciiMapSource(iss, coords2(map_width, map_height), dk::MapType_Isometric, coords2(tile_size)));
	layer = &tiler.push_layer<dkh::AsciiMapSource::MapTileType>(loader.get(), 0);
}

void asciimapsource::SetUp() {
	ASSERT_NE(nullptr, layer);
}

TEST_F(asciimapsource, load) {
	dk::Viewport<2> full_view(tiler, coords2(map_width, map_height), coords2(0));

	EXPECT_EQ(coords2(map_width, map_height), tiler.map_size());

	dk::CoordinateDistType index = 0;
	int data_index = 0;
	full_view.setFrom(coords2(0));
	for (auto itTile = full_view.begin(*layer), itTileEND = full_view.end(*layer); itTile != itTileEND; ++itTile) {
		EXPECT_EQ(index, dk::to_index(itTile->raw_coords()));
		EXPECT_LT(index, sizeof(map_data));
		ASSERT_LT(data_index, sizeof(map_data));
		const auto expected_value = static_cast<dk::CoordinateScalarType>(map_data[data_index] - '0');
		EXPECT_EQ(expected_value, itTile->data());
		++index;
		++data_index;
		if (map_data[data_index] == '\n') {
			++data_index;
		}
	}
	EXPECT_EQ(map_width * map_height, index);
}

TEST_F(asciimapsource, coordinates) {
	const coords2 tsize(tile_size);
	dk::Viewport<2> full_view(tiler, coords2(map_width, map_height), coords2(0));
	dk::PixelConvSquare<2> iso_conv((tsize));
	dk::PixelConvDiamond diamond_conv(tsize, true, false);
	dk::PixelConvDiamond diamond_conv2(tsize, true, true);

	full_view.setFrom(coords2(0));
	for (auto itTile = full_view.begin(*layer), itTileEND = full_view.end(*layer); itTile != itTileEND; ++itTile) {
		//Check isometric coordinates
		{
			const coords2 expected_coords(tsize * itTile->block_position());
			const auto returned_coords(iso_conv.to_pixel(itTile->block_position(), coords2(0)));
			EXPECT_EQ(expected_coords, returned_coords);
			EXPECT_EQ(expected_coords, itTile->screen_position());
		}

		//Check staggered diamond coordinates, second row reentrant
		{
			const auto xoffs = (itTile->block_position().y() % 2 == 0 ? 0 : tsize.x() / 2);
			const coords2 expected_coords(
				xoffs + itTile->block_position().x() * tsize.x(),
				itTile->block_position().y() * tsize.y()
			);
			const auto returned_coords(diamond_conv.to_pixel(itTile->block_position(), coords2(0)));
			EXPECT_EQ(expected_coords, returned_coords);
		}

		//Check staggered diamond coordinates, first row reentrant
		{
			const auto xoffs = (itTile->block_position().y() % 2 == 1 ? 0 : tsize.x() / 2);
			const coords2 expected_coords(
				xoffs + itTile->block_position().x() * tsize.x(),
				itTile->block_position().y() * tsize.y()
			);
			const auto returned_coords(diamond_conv2.to_pixel(itTile->block_position(), coords2(0)));
			EXPECT_EQ(expected_coords, returned_coords);
		}
	}
}
