/*  $Id: resourcedata_sprite_description.cpp,v 1.17 2004/04/20 13:36:27 sphair Exp $
**
**  ClanLib Game SDK
**  Copyright (C) 2003  The ClanLib Team
**  For a total list of contributers see the file CREDITS.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This library 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
**  Lesser General Public License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*/

#include "Display/display_precomp.h"
#include "resourcedata_sprite_description.h"
#include "API/Display/sprite_description.h"
#include "API/Display/pixel_buffer.h"
#include "API/Core/System/clanstring.h"
#include "API/Core/System/error.h"
#include "API/Core/Resources/resource_manager.h"
#include "API/Display/Providers/provider_factory.h"

//////////////////////////////////////////////////////////////////////////////
// CL_ResourceData_SpriteDescription construction:

CL_ResourceData_SpriteDescription::CL_ResourceData_SpriteDescription(CL_Resource &resource, const std::string &type)
: CL_ResourceData(resource)
{
	resource.attach_data(type, this);
}
	
CL_ResourceData_SpriteDescription::~CL_ResourceData_SpriteDescription()
{
}
	
//////////////////////////////////////////////////////////////////////////////
// CL_ResourceData_SpriteDescription attributes:

//////////////////////////////////////////////////////////////////////////////
// CL_ResourceData_SpriteDescription operations:

CL_SpriteDescription CL_ResourceData_SpriteDescription::load_description()
{
	CL_Resource resource = get_resource();
	CL_SpriteDescription desc;

	std::string str_keep_pixelbuffer;
	std::string str_force_16bit;

	std::string load_description = resource.get_element().get_attribute("description", "");
	if(load_description != "")
	{
		CL_Resource global_resource = resource.get_manager().get_resource(load_description);
		add_images(desc, global_resource);

		if (global_resource.get_element().has_attribute("keep_pixelbuffer"))
			str_keep_pixelbuffer = global_resource.get_element().get_attribute("keep_pixelbuffer", "false");
		if (global_resource.get_element().has_attribute("force_16bit"))
			str_force_16bit = global_resource.get_element().get_attribute("force_16bit", "false");
	}

	if (resource.get_element().has_attribute("keep_pixelbuffer"))
		str_keep_pixelbuffer = resource.get_element().get_attribute("keep_pixelbuffer", "false");
	if (resource.get_element().has_attribute("force_16bit"))
		str_force_16bit = resource.get_element().get_attribute("force_16bit", "false");

	bool keep_pixelbuffer = CL_String::to_bool(str_keep_pixelbuffer);
	bool force_16bit = CL_String::to_bool(str_force_16bit);

	desc.set_surface_flag(keep_pixelbuffer * CL_Surface::flag_keep_pixelbuffer | force_16bit * CL_Surface::flag_force_16bit);

	add_images(desc, resource);

	if (desc.get_frames().empty()) throw CL_Error("Sprite resource contained no frames!");

	return desc;
}

//////////////////////////////////////////////////////////////////////////////
// CL_ResourceData_SpriteDescription implementation:

void CL_ResourceData_SpriteDescription::add_images(CL_SpriteDescription &desc, CL_Resource &resource)
{
	CL_DomNode cur_node;

	for (
		cur_node = resource.get_element().get_first_child();
		!cur_node.is_null();
		cur_node = cur_node.get_next_sibling())
	{
		if (!cur_node.is_element()) continue;

		CL_DomElement cur_element = cur_node.to_element();
		if (cur_element.get_tag_name() == "image")
		{
			std::string image_name = cur_element.get_attribute("file");
			CL_PixelBuffer *image = load_image(image_name);

			CL_DomElement grid_element = cur_element.named_item("grid").to_element();
			CL_DomElement palette_element = cur_element.named_item("palette").to_element();
			CL_DomElement alpha_element = cur_element.named_item("alpha").to_element();

			if (!grid_element.is_null())
			{
				int xpos = 0;
				int ypos = 0;
				int xarray = 1;
				int yarray = 1;
				int array_skipframes = 0;
				int xspacing = 0;
				int yspacing = 0;

				std::vector<std::string> image_size = CL_String::tokenize(grid_element.get_attribute("size"), ",");
				int width = 0;
				if (image_size.size() > 0)
					width = atoi(image_size[0].c_str());
				int height = 0;
				if (image_size.size() > 1)
					height = atoi(image_size[1].c_str());

				if (grid_element.has_attribute("pos"))
				{
					std::vector<std::string> image_pos = CL_String::tokenize(grid_element.get_attribute("pos"), ",");
					xpos = atoi(image_pos[0].c_str());
					ypos = atoi(image_pos[1].c_str());
				}

				if (grid_element.has_attribute("array"))
				{
					std::vector<std::string> image_array = CL_String::tokenize(grid_element.get_attribute("array"), ",");
					xarray = atoi(image_array[0].c_str());
					yarray = atoi(image_array[1].c_str());
				}

				if (grid_element.has_attribute("array_skipframes"))
				{
					array_skipframes = atoi(grid_element.get_attribute("array_skipframes").c_str());
				}

				if (grid_element.has_attribute("spacing"))
				{
					std::vector<std::string> image_spacing = CL_String::tokenize(grid_element.get_attribute("spacing"), ",");
					xspacing = atoi(image_spacing[0].c_str());
					yspacing = atoi(image_spacing[1].c_str());
				}

				desc.add_gridclipped_frames(
					image,
					xpos, ypos,
					width, height,
					xarray, yarray,
					array_skipframes,
					xspacing, yspacing,
					true);
			}
			else if (!palette_element.is_null())
			{
				int xpos = 0;
				int ypos = 0;

				if (palette_element.has_attribute("pos"))
				{
					std::vector<std::string> image_pos = CL_String::tokenize(palette_element.get_attribute("pos"), ",");
					xpos = atoi(image_pos[0].c_str());
					ypos = atoi(image_pos[1].c_str());
				}

				desc.add_paletteclipped_frames(
					image,
					xpos, ypos,
					true);
			}
			else if (!alpha_element.is_null())
			{
				int xpos = 0;
				int ypos = 0;
				float trans_limit = 0.05f;

				if (alpha_element.has_attribute("pos"))
				{
					std::vector<std::string> image_pos = CL_String::tokenize(alpha_element.get_attribute("pos"), ",");
					xpos = atoi(image_pos[0].c_str());
					ypos = atoi(image_pos[1].c_str());
				}

				if (alpha_element.has_attribute("trans_limit"))
				{
					trans_limit = (float)atof(alpha_element.get_attribute("trans_limit").c_str());
				}

				if (alpha_element.has_attribute("free"))
				{
					desc.add_alphaclipped_frames_free(
						image,
						xpos, ypos,
						trans_limit,
						true);
				}
				else
				{
					desc.add_alphaclipped_frames(
						image,
						xpos, ypos,
						trans_limit,
						true);
				}
			}
			else
			{
				desc.add_frame(image, true);
			}
		}
	}
}

CL_PixelBuffer *CL_ResourceData_SpriteDescription::load_image(const std::string &filename)
{
	return CL_ProviderFactory::load(filename, "", get_resource().get_manager().get_resource_provider());
}
