/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


		#include "core/terrain.h"
		#include "core/engine.h"
		#include "core/embedded_resource_handler_interface.h"
		#include "picture/pict_io.h"
		#include "filesystem/filesystem.h"
		#include "platform.h"
		#include "log/log.h"

		using namespace GS::Core;
		using GS::NML::Tag;


//------------------------------------------------------------------------------
bool				Terrain::LoadHeightmap(const char *uri)
{
	if	(Platform::Get().io->FileSize(uri) != (size_t)(4 * heightmap_w * heightmap_h))
		__ERR__(__LOG_W__ << "Corrupt heightmap data in " << uri << ", incorrect data size.\n", false)

	AutoPtr <IO::Handle> h(Platform::Get().io->Open(uri));
	if	(h.IsNull())
		return false;

	float *ph = heightmap;
	for (int v = 0; v < heightmap_h; ++v)
	{
		h->Read(ph, heightmap_w * 4);
		ph += heightmap_w;
		ph[0] = ph[-1];
		ph++;
	}
	for (int u = 0; u < heightmap_w; ++u)
	{
		ph[0] = ph[-(heightmap_w + 1)];
		ph++;
	}
	return true;
}
bool				Terrain::SaveHeightmap(const char *uri)
{
	AutoPtr <IO::Handle> h(Platform::Get().io->Open(uri, IO::ModeWrite));
	if	(h.IsNull())
		return false;

	float *ph = heightmap;
	for (int v = 0; v < heightmap_h; ++v)
	{
		h->Write(ph, heightmap_w * 4);
		ph += heightmap_w + 1;
	}
	return true;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
bool				Terrain::FromMetaTag(Tag &tag)
{
	if	(tag.name != "Terrain")
		__ERR__(__LOG_E__ << "Could not parse terrain, incorrect root tag (" << tag.name << ").\n", false)

	NMLTagForeach(pt, tag)
	{
				if	(pt->name == "Item")
				Item::FromMetaTag(*pt);

		else	if	(pt->name == "Width")
				width = pt->GetReal();
		else	if	(pt->name == "Height")
				depth = pt->GetReal();

		else	if	(pt->name == "Material")		// Legacy path, embedded material.
				IEmbeddedResourceHandler::Get()->ExtractEmbeddedMaterial(material, *pt, "terrain", 0);
		else	if	(pt->name == "MaterialName")
				material = pt->GetString();

		else	if	(pt->name == "Layers")
		{
			NMLTagForeach(layer_tag, *pt)
				if	(layer_tag->name == "Layer")
				{
					Tag *index_tag = layer_tag->GetTag("Index");
					Layer &l = layer[index_tag ? index_tag->GetInteger() : 0];

					if	(layer_tag->GetTag("Enabled;"))
						l.enabled = true;

					if	(Tag *map = layer_tag->GetTag("Diffuse;"))
						l.diffuse = map->GetString();
					if	(Tag *map = layer_tag->GetTag("Normal;"))
						l.normal = map->GetString();
					if	(Tag *map = layer_tag->GetTag("Specular;"))
						l.specular = map->GetString();
					if	(Tag *map = layer_tag->GetTag("Self;"))
						l.self = map->GetString();

					if	(Tag *map = layer_tag->GetTag("UVAngle;"))
						l.angle = map->GetReal();
					if	(Tag *map = layer_tag->GetTag("UVTiling;"))
						l.tiling = map->GetReal();
				}
		}
		else	if	(pt->name == "Shader")
			shader_path = pt->GetString();

		else	if	(pt->name == "Blendmap")
			blendmap_path = pt->GetString();

		else	if	(pt->name == "Heightmap")
		{
			Tag *w_tag = pt->GetTypedTag("Width;", Variant::VariantInteger),
					 *h_tag = pt->GetTypedTag("Height;", Variant::VariantInteger),
					 *d_tag = pt->GetTypedTag("Data;", Variant::VariantString),
					 *r_tag = pt->GetTypedTag("Resolution;", Variant::VariantFloat);

			if	(w_tag && h_tag && d_tag && r_tag)
				if	(Allocate(w_tag->GetInteger(), h_tag->GetInteger(), r_tag->GetReal()))
					heightmap_path = d_tag->GetString();
		}
		else
			__LOG_W__ << "Unknown tag '" << pt->name << "' in <Terrain>.\n";
	}
	return true;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
Tag			*Terrain::LayerAsMetaTag(int index)
{
	Layer &l = layer[index];

	Tag *layer_tag = new Tag("Layer");
	if	(!layer_tag)
		__ERR__(__LOG_E__ << "Failed to serialize terrain layer " << index << ".\n", NULL)

	layer_tag->AddChild("Index", index);

	if	(l.enabled)
		layer_tag->AddChild(new Tag("Enabled"));

	if	(!l.diffuse.IsEmpty())
		layer_tag->AddChild("Diffuse", l.diffuse.toUtf8());
	if	(!l.normal.IsEmpty())
		layer_tag->AddChild("Normal", l.normal.toUtf8());
	if	(!l.specular.IsEmpty())
		layer_tag->AddChild("Specular", l.specular.toUtf8());
	if	(!l.self.IsEmpty())
		layer_tag->AddChild("Self", l.self.toUtf8());

	layer_tag->AddChild("UVAngle", l.angle);
	layer_tag->AddChild("UVTiling", l.tiling);

	return layer_tag;
}
Tag			*Terrain::AsMetaTag()
{
	Tag *root = new Tag("Terrain");
	if	(!root)
		__ERR__(__LOG_E__ << "Could not serialize terrain. Failed to create root tag.\n", NULL)

	// Store item.
	root->AddChild(Item::AsMetaTag());

	// Store terrain.
	root->AddChild("Width", width);
	root->AddChild("Height", depth);

	if	(!material.IsEmpty())
		root->AddChild("MaterialName", material.c_str());

	// Store layers.
	if	(Tag *layers_tag = root->AddChild("Layers"))
		for (int n = 0; n < 4; ++n)
			layers_tag->AddChild(LayerAsMetaTag(n));

	root->AddChild("Blendmap", blendmap_path.c_str());
	root->AddChild("Shader", shader_path.c_str());

	// Store heightmap.
	if	(Tag *height_tag = root->AddChild("Heightmap"))
	{
		height_tag->AddChild("Width", heightmap_w);
		height_tag->AddChild("Height", heightmap_h);
		height_tag->AddChild("Resolution", unit);
		// Note: The terrain heightmap is saved by the editor.
		height_tag->AddChild("Data", heightmap_path.c_str());
	}
	return root;
}
//------------------------------------------------------------------------------
