/*
 * GDevelop C++ Platform
 * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
 * This project is released under the MIT License.
 */
#ifndef CODEEXECUTIONENGINE_H
#define CODEEXECUTIONENGINE_H
#include "GDCpp/Runtime/Tools/DynamicLibrariesTools.h"
#include "GDCpp/Runtime/RuntimeContext.h"
#include <vector>
#include <string>

/**
 * \brief Wrapper allowing to load a dynamic library and launch a specific function.
 *
 * RuntimeScene uses this class to launch compiled events. In particular, the signature of the function
 * of the dynamic library must be :
 \code
void functionName(RuntimeContext *);
 \endcode
 *
 * \TODO: This class is unecessarily complicated.
 * \see CodeCompilationHelpers
 * \see CodeCompiler
 *
 * \ingroup CodeExecutionEngine
 */
class GD_API CodeExecutionEngine
{
public:
    typedef int(*functionType)(RuntimeContext *);

    /**
     * Construct an empty engine.
     */
    CodeExecutionEngine();

    /**
     * Create an engine from another: The new execution engine will load the same library as the source execution engine.
     */
    CodeExecutionEngine(const CodeExecutionEngine & other) : runtimeContext(other.runtimeContext) { Init(other); };

    /**
     * Create an engine from another: The new execution engine will load the same library as the source execution engine.
     */
    CodeExecutionEngine& operator=(const CodeExecutionEngine & other) {if( (this) != &other ) Init(other); return *this; }

    /**
     * Destructor: Unload if necessary the dynamic library.
     */
    virtual ~CodeExecutionEngine();

    /**
     * Execute the loaded function.
     */
    void Execute() { if (Ready()) ((functionType)function)(&runtimeContext); };

    /**
     * Return true if an initialization from a dynamic library has been made successfully and if Execute can be called.
     */
    bool Ready() const { return loaded; };

    /**
     * Unload the dynamic library from memory.
     *
     * \warning Of course, Execute() can not be called after Unload() is called.
     */
    void Unload();

    /**
     * Initialize the engine from a dynamic library, which is kept loaded in memory.
     *
     * \param filename The dynamic library to be loaded
     * \param mainFunctionName The name of the function to be executed when Execute() is called. The function signature must be void functionName(RuntimeContext *);
     *
     * \return true if the CodeExecutionEngine is successfully initialized and Execute() can be called.
     */
    bool LoadFromDynamicLibrary(const gd::String & filename, const gd::String & mainFunctionName);

    bool LoadFunction(functionType fn);

    RuntimeContext runtimeContext; ///< The object passed as parameter to the function of the dynamic library.

private:

    bool loaded; ///< True if a dynamic library is loaded and a function is ready to be executed.
    gd::String dynamicLibraryFilename; ///< The filename of the dynamic library loaded in memory.
    Handle dynamicLibrary; ///< The dynamic library loaded in memory.
    gd::String functionName; ///< The name of the function of the dynamic library to be executed.
    void * function; ///< Pointer to function to be executed.

    void Init(const CodeExecutionEngine & other);
};


#endif // CODEEXECUTIONENGINE_H
