// K-3D
// Copyright (c) 1995-2004, Timothy M. Shead
//
// Contact: tshead@k-3d.com
//
// This program 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 2 of the License, or (at your option) any later version.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/** \file
	\author Anders Dahnielson (anders@dahnielson.com)
*/

#include <k3dsdk/algebra.h>
#include <k3dsdk/bitmap_filter.h>
#include <k3dsdk/object.h>
#include <k3dsdk/persistence.h>
#include <k3dsdk/measurement.h>
#include <k3dsdk/module.h>
#include <k3dsdk/plugins.h>
#include <k3dsdk/transformable.h>

#include "bitmap_element.h"

namespace libk3dbitmap
{

/////////////////////////////////////////////////////////////////////////////
// bitmap_instance_implementation

class bitmap_instance_implementation :
	public k3d::bitmap_filter<k3d::persistent<k3d::object> >
{
	typedef k3d::bitmap_filter<k3d::persistent<k3d::object> > base_t;
public:
	bitmap_instance_implementation(k3d::idocument& Document) :
		base_t(Document),
		m_position(k3d::init_name("position") + k3d::init_description("Position [vector3]") + k3d::init_value(k3d::vector3(0.0, 0.0, 0.0)) + k3d::init_document(Document)),
		m_scale(k3d::init_name("scale") + k3d::init_description("Scale [vector3]") + k3d::init_value(k3d::vector3(1.0, 1.0, 1.0)) + k3d::init_document(Document)),
		m_angle(k3d::init_name("angle") + k3d::init_description("Angle [angle]") + k3d::init_value(k3d::radians(0.0)) + k3d::init_document(Document) + k3d::init_precision(2) + k3d::init_step_increment(k3d::radians(1.0)) + k3d::init_units(typeid(k3d::measurement::angle))),
		m_premultiplied(k3d::init_name("premultiplied") + k3d::init_description("Image is pre-multiplied [boolean]") + k3d::init_value(true) + k3d::init_document(Document)),
		m_color_matrix(k3d::init_name("color_matrix") + k3d::init_description("Color matrix [matrix4]") + k3d::init_value(k3d::identity3D()) + k3d::init_document(Document))
	{
		enable_serialization(k3d::persistence::proxy(m_position));
		enable_serialization(k3d::persistence::proxy(m_scale));
		enable_serialization(k3d::persistence::proxy(m_angle));
		enable_serialization(k3d::persistence::proxy(m_premultiplied));

		register_property(m_position);
		register_property(m_scale);
		register_property(m_angle);
		register_property(m_premultiplied);
		register_property(m_color_matrix);

		m_position.changed_signal().connect(SigC::slot(*this, &bitmap_instance_implementation::on_reset_bitmap));
		m_scale.changed_signal().connect(SigC::slot(*this, &bitmap_instance_implementation::on_reset_bitmap));
		m_angle.changed_signal().connect(SigC::slot(*this, &bitmap_instance_implementation::on_reset_bitmap));
		m_premultiplied.changed_signal().connect(SigC::slot(*this, &bitmap_instance_implementation::on_reset_bitmap));
		m_color_matrix.changed_signal().connect(SigC::slot(*this, &bitmap_instance_implementation::on_reset_bitmap));
		m_input.changed_signal().connect(SigC::slot(*this, &bitmap_instance_implementation::on_reset_bitmap));
		m_output.need_data_signal().connect(SigC::slot(*this, &bitmap_instance_implementation::on_create_bitmap));
	}

	void on_reset_bitmap()
	{
		m_output.reset();
	}

	k3d::bitmap* on_create_bitmap()
	{
		// Get the input bitmap ...
		k3d::bitmap* const input = m_input.property_value();
		if(!input)
			return 0;

		// Cache properties ...
		k3d::matrix4 color_matrix = m_color_matrix.property_value();
		bool premultiplied = m_premultiplied.property_value();
		double angle = m_angle.property_value();
		k3d::vector3 scale = m_scale.property_value();
		k3d::vector3 position = m_position.property_value();

		// Transform ...
 		bitmap_element* element = new bitmap_element(input);
		element->color(color_matrix, premultiplied);
		element->scale(k3d::vector2(scale[k3d::VX], scale[k3d::VY]));
		element->rotate(angle);
		element->position(k3d::vector2(position[k3d::VX], position[k3d::VY]));
		element->true_translation();

		return element->get_bitmap();
	}

	k3d::iplugin_factory& factory()
	{
		return get_factory();
	}

	static k3d::iplugin_factory& get_factory()
	{
		static k3d::plugin_factory<
			k3d::document_plugin<bitmap_instance_implementation>,
			k3d::interface_list<k3d::ibitmap_source,
			k3d::interface_list<k3d::ibitmap_sink> > > factory(
				k3d::uuid(0x9a247cdf, 0xebcf4861, 0xaa814c6f, 0xed947b51),
				"BitmapInstance",
				"Gives bitmap a position",
				"Objects",
				k3d::iplugin_factory::STABLE);

		return factory;
	}

private:
	k3d_data_property(k3d::vector3, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_position;
	k3d_data_property(k3d::vector3, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_scale;
	k3d_measurement_property(double, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_angle;
	k3d_data_property(bool, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_premultiplied;
	k3d_data_property(k3d::matrix4, k3d::immutable_name, k3d::change_signal, k3d::with_undo, k3d::local_storage, k3d::no_constraint) m_color_matrix;
};

/////////////////////////////////////////////////////////////////////////////
// bitmap_instance_factory

k3d::iplugin_factory& bitmap_instance_factory()
{
	return bitmap_instance_implementation::get_factory();
}

} // namespace libk3dbitmap
