// 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 convenience methods for working with scripts
		\author Tim Shead (tshead@k-3d.com)
*/

#include "application.h"
#include "iapplication_plugin_factory.h"
#include "ideletable.h"
#include "iplugin_factory.h"
#include "iscript_engine.h"
#include "plugins.h"
#include "result.h"
#include "scripting.h"
#include "uuid.h"

#include <sstream>
#include <typeinfo>

namespace k3d
{

namespace detail
{

/// Returns the set of all available scripting languages (cached)
const factories_t& script_engine_factories()
{
	static factories_t factories;
	if(factories.empty())
		factories = plugins<iscript_engine>();

	return factories;
}

/// Executes a script using the given plugin factory to create the script engine
bool execute_script(const std::string& Script, const std::string& ScriptName, const iscript_engine::context_t& Context, iplugin_factory& Language)
{
	// Sanity checks ...
	return_val_if_fail(Script.size(), false);
	return_val_if_fail(ScriptName.size(), false);

	// Get the requested scripting engine ...
	iscript_engine* const engine = dynamic_cast<iscript_engine*>(create_application_plugin(Language));
	return_val_if_fail(engine, false);

	// Run that bad-boy ...
	const bool result = engine->execute(ScriptName, Script, Context);

	// Done with the engine ...
	delete dynamic_cast<ideletable*>(engine);

	return result;
}

} // namespace detail

iplugin_factory* recognize_script_language(const std::string& Script)
{
	// Get the set of all script engine factories ...
	const factories_t& factories(detail::script_engine_factories());

	// Look for a scripting engine that can execute the script ...
	for(factories_t::const_iterator factory = factories.begin(); factory != factories.end(); ++factory)
		{
			iscript_engine* const script_engine = dynamic_cast<iscript_engine*>(create_application_plugin(**factory));
			if(!script_engine)
				continue;

			const bool can_execute = script_engine->can_execute(Script);
			delete dynamic_cast<ideletable*>(script_engine);
		
			if(can_execute)
				return *factory;
		}

	// Couldn't find anything ...
	return 0;
}

bool execute_script(const std::string& Script, const std::string& ScriptName, const iscript_engine::context_t& Context, const uuid& Language)
{
	// Lookup the engine ...
	iplugin_factory* const language = plugin(Language);
	return_val_if_fail(language, false);

	// Make it happen ...
	return detail::execute_script(Script, ScriptName, Context, *language);
}

void execute_script(const std::string& Script, const std::string& ScriptName, const iscript_engine::context_t& Context, bool& Recognized, bool& Executed)
{
	// Starting state ...
	Recognized = false;
	Executed = false;

	// See which language it's written in ...
	iplugin_factory* const language = recognize_script_language(Script);

	// If the language wasn't recognized, we're done ...
	Recognized = language ? true : false;
	if(!Recognized)
		return;

	// Execute that puppy ...
	Executed = detail::execute_script(Script, ScriptName, Context, *language);
}

void execute_script(std::istream& Script, const std::string& ScriptName, const iscript_engine::context_t& Context, bool& Recognized, bool& Executed)
{
	// Convert the stream to a string
	std::stringstream script;
	Script.get(*script.rdbuf(), '\0');

	execute_script(script.str(), ScriptName, Context, Recognized, Executed);
}

} // namespace k3d


