// 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
		\brief Implements the k3d::menu_item::control class
		\author Anders Dahnielson (anders@dahnielson.com)
*/

#include "gtkml.h"
#include "menu_item.h"

#include <k3dsdk/application.h>
#include <k3dsdk/idocument.h>
#include <k3dsdk/iobject.h>
#include <k3dsdk/ioptions.h>
#include <k3dsdk/scripting.h>
#include <k3dsdk/string_modifiers.h>

#include <sdpgtk/sdpgtkevents.h>
#include <sdpgtk/sdpgtkutility.h>

#include <fstream>

// We have an unfortunate class with X ...
#ifdef RootWindow
#undef RootWindow
#endif // RootWindow

namespace
{

const std::string control_menuitem("menuitem");

} // namespace

namespace k3d
{

namespace menu_item
{

/////////////////////////////////////////////////////////////////////////////
// control::state

class control::state
{
public:
	/// Stores a filepath to a script
	boost::filesystem::path script_file;
	/// Stores an inline script
	std::string script;
};

/////////////////////////////////////////////////////////////////////////////
// control

control::control(k3d::iunknown* CommandNodeParent, std::string CommandNodeName) :
	base(CommandNodeParent, CommandNodeName),
	m_hotkey(*this),
	m_state(new state())
{
}

control::~control()
{
	delete m_state;
}

void control::set_text(const std::string& Text)
{
	Label("label").SetText(Text.c_str());
}

void control::set_sensitive(const bool Sensitive)
{
	Label("label").SetSensitive(Sensitive);
}

control::activated_signal_t& control::signal_activate()
{
	return m_signal_activate;
}

bool control::Create(sdpGtkIObjectContainer* ObjectContainer, sdpxml::Document& Document, sdpxml::Element& Element)
{
	// Sanity checks ...
	assert_warning(ObjectContainer);
	assert_warning(Element.Name() == "k3dmenuitem");

	// Attributes ...
	std::string file;
	sdpGtkMarkAttribute(Document, Element, "file");
	sdpxml::ParseAttribute(Element, "file", file);
	m_state->script_file = boost::filesystem::path(file, boost::filesystem::native);

	// Children ...
	for(sdpxml::ElementCollection::iterator element = Element.Children().begin(); element != Element.Children().end(); element++)
	{
		if (element->Name() == "k3dhotkey" && m_hotkey.load(Document, *element))
			m_hotkey.event_signal().connect(SigC::slot(*this, &control::on_activate));
		else if (element->Name() == "script")
			m_state->script = k3d::trimleft(sdpGtkInternationalText(Document, *element));
		else if (element->Name() != "i18n")
			std::cerr << __PRETTY_FUNCTION__ << ": unknown element <" << element->Name() << "> at " << sdpxml::FileReference(Document, *element) << " will be ignored" << std::endl;
	}

	// Create and load our UI template ...
	std::stringstream uitemplate;

	uitemplate << "<gtkml>";
	uitemplate << "<menuitem name=\"menuitem\">";
	uitemplate << "<event signal=\"activate\" name=\"menuitem\"/>";
	uitemplate << "<label name=\"label\" alignment=\"0.0 0.5\">" << sdpGtkInternationalText(Document, Element) << "</label>";
	uitemplate << "</menuitem>";
	uitemplate << "</gtkml>\n";

	return_val_if_fail(load_gtkml(uitemplate, "menu item builtin template", *this), false);

	RootWidget().Show();

	return true;
}

const std::string control::CustomType() const
{
	return std::string("k3dmenuitem");
}

bool control::execute_command(const std::string& Command, const std::string& Arguments)
{
	if(Command == "activate")
		{
			InteractiveActivateMenuItem(control_menuitem, k3d::application().options().tutorial_speed(), true);
			return true;
		}

	return base::execute_command(Command, Arguments);
}

void control::OnEvent(sdpGtkEvent* Event)
{
	// Sanity checks ...
	assert_warning(Event);

	if (Event->Name() == control_menuitem)
		on_activate();
	else
		base::OnEvent(Event);
}

void control::on_activate()
{
	// Make a copy of our state (in-case we are deleted during the course of event handling)
	const state current_state(*m_state);

	k3d::record_command(*this, k3d::icommand_node::command_t::USER_INTERFACE, "activate");

	k3d::iscript_engine::context_t context;
	context.push_back(k3d::get_document(*this));
	context.push_back(k3d::get_object(*this));

	m_signal_activate.emit();

	if(!current_state.script.empty())
		{
			bool recognized = false;
			bool executed = false;

			k3d::execute_script(current_state.script, "inline", context, recognized, executed);

			if(!recognized)
				{
					std::cerr << error << __PRETTY_FUNCTION__ << " Could not determine scripting language" << std::endl;
					return;
				}

			if(!executed)
				{
					std::cerr << error << __PRETTY_FUNCTION__ << " Error executing script" << std::endl;
					return;
				}
		}

	if(!current_state.script_file.empty())
		{
			bool recognized = false;
			bool executed = false;

			boost::filesystem::ifstream file(current_state.script_file);
			k3d::execute_script(file, current_state.script_file.native_file_string(), context, recognized, executed);

			if(!recognized)
				{
					std::cerr << error << __PRETTY_FUNCTION__ << " Could not determine scripting language" << std::endl;
					return;
				}

			if(!executed)
				{
					std::cerr << error << __PRETTY_FUNCTION__ << " Error executing script" << std::endl;
					return;
				}
		}
}

} // namespace menu_item

} // namespace k3d


