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


		#include <cstring>
		#include "metafile/nml.h"
		#include "filesystem/io_handle.h"
		#include "filesystem/filesystem.h"
		#include "platform.h"
		#include "log/log.h"

		using namespace GS;
		using namespace GS::NML;


//------------------------------------------------------------------------------
bool		Parser::SaveBinaryTag(IO::Handle &out, const Tag &tag, File::Binary method)
{
	const Variant &v = tag.GetValue();

	if	(v.GetType() != Variant::VariantNone)
	{
		out.Write <ushort> ((ushort)tag.name.Len());
		out.Write((void *)tag.name.c_str(), tag.name.Len());
	}
	else
		__ERR__(__LOG_W__ << "Ignoring invalid metatag '" << tag.name << "'.\n", true)

	// Store tag start size/type.
	out.Write <uchar> ((uchar)v.GetType());

	size_t tag_length_pos = out.Tell();
	switch (v.GetType())
	{
		case Variant::VariantNone:
		case Variant::VariantBinary:
		case Variant::VariantString:
			out.Write <int> (-1);
			break;

		default: break;
	}

	switch (v.GetType())
	{
		case Variant::VariantNone:
			NMLTagForeach(child, tag)
				if	(!SaveBinaryTag(out, *child, method))
					return false;
			break;

		case Variant::VariantBinary:
			out.Write(tag.GetValue().GetBinaryBuffer(), tag.GetValue().GetBinarySize());
			break;

		case Variant::VariantInteger:
			out.Write <int> (tag.GetInteger());
			break;

		case Variant::VariantFloat:
			out.Write <float> (tag.GetReal());
			break;

		case Variant::VariantString:
			out.Write(tag.GetString(), std::strlen(tag.GetString()));
			break;

		default:
			__ERR__(__LOG_E__ << "No method to output tag '" << tag.name << "' type.\n", false)
	}

	switch (v.GetType())
	{
		case Variant::VariantNone:
		case Variant::VariantBinary:
		case Variant::VariantString:
		{
			size_t tag_end_pos = out.Tell();
			out.Seek(tag_length_pos, IO::Base::SeekStart);
			out.Write <int> (tag_end_pos - tag_length_pos);
			out.Seek(tag_end_pos, IO::Base::SeekStart);
		}
		break;

		default: break;
	}
	return true;
}
bool				Parser::SaveBinary(IO::Handle &h, const File &file)
{
	h.Write((const void *)"<BML=1.0>\n", 10);
	NMLFileForeach(tag, file)
		if	(!SaveBinaryTag(h, *tag, file.GetBinaryMethod()))
			return false;

	return true;
}
bool				Parser::SaveBinary(const char *uri, const File &file)
{
	if	(!uri)
		return false;

	AutoPtr <IO::Handle> handle;
	if	(!(handle = Platform::Get().io->Open(uri, IO::ModeWrite)))
		__ERR__(__LOG_E__ << "Failed to open metafile output '" << uri << "'.\n", false)

	return SaveBinary(*handle, file);
}
//------------------------------------------------------------------------------
