// 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 Ruby engine, an implementation of k3d::iscript_engine that supports the Ruby language
		\author Anders Dahnielson (anders@dahnielson.com)
*/

#include "object_model.h"

#include <k3dsdk/command_node.h>
#include <k3dsdk/ideletable.h>
#include <k3dsdk/iscript_engine.h>
#include <k3dsdk/classes.h>
#include <k3dsdk/module.h>

#include <iostream>

/// Namespace reserved for the Ruby script engine plugin module, to protect public symbols from name clashes with other modules
namespace libk3druby
{

const std::string magic_token("#ruby");

static VALUE defout_write(VALUE self, VALUE str)
{
	std::cerr << Ruby_To_String(str);
	return RBVAL_NONE;
}

class engine :
	public k3d::iscript_engine,
	public k3d::ideletable
{
public:
	engine()
	{
		// Fire up the interpreter here
		ruby_init();
		ruby_init_loadpath();
		rb_set_safe_level(0);
		ruby_script("ruby");

		// Connect Ruby to outputstream
		rb_defout = rb_str_new("", 0);
		rb_define_singleton_method(rb_defout, "write", (VALUE(*)(...))defout_write, 1);

		// Initialize Application module
		CRubyApplication::CreateModule();

		// Initialize classes ...
		CRubyUserInterface::CreateClass();
		CRubyScriptEngines::CreateClass();
		CRubyCommandNode::CreateClass();
		CRubyDocument::CreateClass();
		CRubyObject::CreateClass();
	}

	virtual ~engine()
	{
		// Shut down the interpreter
	}

	// k3d::iscript_engine implementation ...
	const std::string language()
	{
		return "Ruby";
	}

	bool can_execute(const std::string& Script)
	{
		// Look for magic token
		return Script.substr(0, magic_token.size()) == magic_token;
	}

	bool execute(const std::string& ScriptName, const std::string& Script, const context_t& Context)
	{
		// Sanity checks ...
		return_val_if_fail(Script.size(), false);
		return_val_if_fail(ScriptName.size(), false);

/*
		// Create the document object and assign it as a global property ...
		VALUE document = Document ? CRubyDocument::Create(Document) : RBVAL_FALSE;
		VALUE object = Object ? CRubyObject::Create(Object) : RBVAL_FALSE;

		rb_define_global_const("MyDocument", document);
		rb_define_global_const("MyObject", object);
*/
		// Evaluate the script ...
		int returncode;
		rb_eval_string_protect((char*) Script.c_str(), &returncode);

		if(returncode != 0)
			{
				std::cerr << "Ruby error -> ";
				rb_p(ruby_errinfo);

				return false;
			}

		return true;
	}

	bool halt()
	{
		return false;
	}

	void bless_script(std::string& Script)
	{
		// Don't keep adding magic tokens to code that already has one ...
		if(can_execute(Script))
			return;

		Script.insert(Script.begin(), magic_token.begin(), magic_token.end());
	}

	bool convert_command(k3d::icommand_node& CommandNode, const std::string& Name, const std::string& Arguments, std::string& Result)
	{
		Result = "Application.CommandNode(\"";
		Result += k3d::command_node_path(CommandNode);
		Result += "\").Command(\"";
		Result += Name;
		Result += "\", \"";
		Result += Arguments;
		Result += "\");";

		return true;
	}
};

k3d::iplugin_factory& engine_factory()
{
	static k3d::plugin_factory<k3d::application_plugin<engine>, k3d::interface_list<k3d::iscript_engine> > factory(
		k3d::classes::RubyEngine(),
		"Ruby",
		"Ruby scripting engine",
		"ScriptEngines");

	return factory;
}

} // namespace libk3druby

K3D_MODULE_START(k3d::uuid(0x9b22330f, 0x14284d8f, 0xb43ba5ba, 0x7b6b261b), Registry)
	Registry.register_factory(libk3druby::engine_factory());
K3D_MODULE_END


