// 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 script_editor class, which provides a UI for editing / executing scripts
		\author Tim Shead (tshead@k-3d.com)
*/

#include "menu_item.h"
#include "script_editor.h"

#include <k3dsdk/application.h>
#include <k3dsdk/iproperty.h>
#include <k3dsdk/iwritable_property.h>
#include <k3dsdk/ioptions.h>
#include <k3dsdk/result.h>
#include <k3dsdk/user_interface.h>

#include <boost/any.hpp>

#include <sdpgtk/sdpgtkevent.h>

namespace
{

/////////////////////////////////////////////////////////////////////////////
// inline_script_editor_implementation

class inline_script_editor_implementation :
	public k3dDialog
{
	typedef k3dDialog base;
	
public:
	inline_script_editor_implementation(k3d::iproperty& Script, k3d::icommand_node& Parent, const std::string& ScriptName) :
		base(&Parent, "inline_script_editor", new k3d::options_window_geometry_store()),
		m_script(Script),
		m_script_name(ScriptName),
		m_changed(false)
	{
		// We want to be notified if the property is deleted
		m_script.deleted_signal().connect(SigC::slot(*this, &inline_script_editor_implementation::on_close));

		// Load dialog template ...
		return_if_fail(LoadGTKMLTemplate("inline_script_editor.gtkml"));

		// Connect to signals ...
		if(get_menu_item("filesave"))
			get_menu_item("filesave")->signal_activate().connect(SigC::slot(*this, &inline_script_editor_implementation::on_save));
			
		if(get_menu_item("filerevert"))
			get_menu_item("filerevert")->signal_activate().connect(SigC::slot(*this, &inline_script_editor_implementation::on_revert));

		if(get_menu_item("fileclose"))
			get_menu_item("fileclose")->signal_activate().connect(SigC::slot(*this, &inline_script_editor_implementation::on_close));

		// Attach scrollbars to the text widget ...
		Scrollbar("vscrollbar").SetAdjustment(static_cast<GtkText*>(text_control())->vadj);

		// Load data and update UI ...
		on_revert();

		Show();
	}
	
private:
	~inline_script_editor_implementation()
	{
		k3d::iwritable_property* const writable_property = dynamic_cast<k3d::iwritable_property*>(&m_script);
		return_if_fail(writable_property);

		writable_property->set_value(boost::any(std::string(text_control().GetText())));
	}

	void update_titlebar()
	{
		std::string title("Edit Script: " + m_script_name);
		
		if(m_changed)
			title += " [changed]";
		
		RootWindow().SetTitle(title);
	}

	sdpGtkText text_control()
	{
		return Text("text");
	}

	void on_save()
	{
		k3d::iwritable_property* const writable_property = dynamic_cast<k3d::iwritable_property*>(&m_script);
		return_if_fail(writable_property);

		writable_property->set_value(boost::any(std::string(text_control().GetText())));
		
		m_changed = false;
		update_titlebar();
	}

	void on_revert()
	{
		if(m_changed)
			{
				std::vector<std::string> buttons;
				buttons.push_back("Yes");
				buttons.push_back("No");
				if(1 != k3d::query_message("The script has changed.  Revert to previous version?", "Revert " + m_script_name + ":", 1, buttons))
					return;
			}
	
		const boost::any value(m_script.value());
		return_if_fail(typeid(std::string) == value.type());
		
		const std::string text = boost::any_cast<std::string>(value);
		
		// Get rid of old text ...
		text_control().DeleteText(0, -1);

		// Insert new ...
		gint position = 0;
		text_control().InsertText(text.c_str(), strlen(text.c_str()), &position);
	
		// Update the UI ...
		m_changed = false;
		update_titlebar();
	}

	void on_close()
	{
		delete this;
	}

	void OnEvent(sdpGtkEvent* Event)
	{
		if(Event->Name() == "changed")
			on_changed();
		else
			base::OnEvent(Event);
	}
	
	void on_changed()
	{
		if(!m_changed)
			{
				m_changed = true;
				update_titlebar();
			}
	}
	
	/// Stores a reference to the script property
	k3d::iproperty& m_script;
	/// Stores the script name
	const std::string m_script_name;
	/// Set to true iff contents have been modified
	bool m_changed;
};


} // namespace

namespace k3d
{

/////////////////////////////////////////////////////////////////////////////
// script_editor

script_editor::script_editor(k3d::icommand_node& Parent) :
	base(&Parent, "script_editor")
{
	// We want to be asked before the application is closed
	k3d::application().safe_to_close_signal().connect(SigC::slot(*this, &script_editor::safe_to_overwrite));
	// We want to be notified if the application is closed
	k3d::application().close_signal().connect(SigC::slot(*this, &script_editor::on_application_closed));

	// Load dialog template ...
	return_if_fail(LoadGTKMLTemplate("script_editor.gtkml"));

	Show();
}

void script_editor::on_application_closed()
{
	delete this;
}

//////////////////////////////////////////////////////////////////////////////
// display_inline_script_editor

void display_inline_script_editor(iproperty& Script, icommand_node& Parent, const std::string& ScriptName)
{
	new inline_script_editor_implementation(Script, Parent, ScriptName);
}

} // namespace k3d

