namespace emo {

    class AssetPackInfo{
    public:
        AssetPackInfo();
        ~AssetPackInfo();
        void setPackInfo(rapidxml::xml_node<> * node, bool hasContent);

        bool packed;
        bool encrypted;
        bool contentEncrypted;

    };

    class Config {
    public:
        Config();
        ~Config();
        void loadConfig(Database* database);

        AssetPackInfo tablesInfo;
        AssetPackInfo scriptsInfo;
        AssetPackInfo soundsInfo;
        AssetPackInfo imagesInfo;
        AssetPackInfo mapsInfo;
        AssetPackInfo modelsInfo;

        std::string mainScriptName;
        std::string runtimeScriptName;
    };

    class Engine {
    public:
        Engine();
        ~Engine();

        int32_t event_handle_input(android_app* app, AInputEvent* event);
        void    event_handle_cmd(android_app* app, int32_t cmd);

        int32_t onInitDisplay();
        void    onInitGLSurface();

        void onInitEngine();
        void onDispose();

        void onTerminateDisplay();

        void onDrawFrame();
        void onLostFocus();
        void onGainedFocus();
        void onLowMemory();

        int32_t getWidth();
        int32_t getHeight();

        void updateUptime();
        int32_t getLastOnDrawDelta();
        int32_t getLastOnDrawDrawablesDelta();

        int32_t onSensorEvent(ASensorEvent* event);
        int32_t onMotionEvent(android_app* app, AInputEvent* event);
        int32_t onKeyEvent(android_app* app, AInputEvent* event);

        ASensorEventQueue* getSensorEventQueue();

        void updateOptions(int value);
        void createSensors(int value);
        void enableSensor(int sensorType, int interval);
        void disableSensor(int sensorType);

        void enableOnDrawListener(bool enable);
        void setOnDrawListenerInterval(int value);
        void setOnDrawDrawablesInterval(int value);

        void enableOnUpdateListener(bool enable);

        void enableOnFpsListener(bool enable);
        void setOnFpsListenerInterval(int value);

        void addDrawable(std::string key, Drawable* drawable);
        void addDrawableToRemove(std::string key, Drawable* drawable);
        bool removeDrawable(std::string key);
        bool freeDrawable(std::string key);
        Drawable* getDrawable(std::string key);

        void onDrawDrawables(int32_t delta);
        
        void rebindDrawableBuffers();

        void loadDrawables();
        void unloadDrawables();
        void deleteDrawableBuffers();

        int32_t getLastError();
        void setLastError(int32_t error);

        HSQUIRRELVM sqvm;
        Sqrat::Table* emoSpace;

        bool animating;
        bool finishing;
        bool sortOrderDirty;
        bool useANR;

        android_app* app;
        Config* config;
        Audio* audio;
        Stage* stage;
        Database* database;
        JavaGlue* javaGlue;
        SquirrelGlue* squirrelGlue;
        Android* android;
        timeb uptime;

        int32_t onDrawFrameInterval;
        int32_t onDrawDrawablesInterval;
        int32_t onFpsInterval;

        std::string getJavaPackageName();

        void stopwatchStart();
        void stopwatchRestart();
        void stopwatchStop();
        int32_t stopwatchElapsed();
        int32_t stopwatchRealElapsed();
        bool stopwatchIsStopped();

        bool hasCachedImage(std::string key);
        Image* getCachedImage(std::string key);
        void addCachedImage(std::string key, Image* image);
        bool removeCachedImage(std::string key);
        void clearCachedImage();

        int logLevel;

        bool hasDisplay();

        void enableOffscreen();
        void disableOffscreen();
        void bindOffscreenFramebuffer();
        void stopOffscreenDrawable(Drawable* drawable);

        bool canUseOffscreen;
        bool useOffscreen;
        bool stopOffscreenRequested;
        GLuint offscreenFramebuffer;

        GLint srcBlendFactor;
        GLint dstBlendFactor;

        int nativeOrientation;

    protected:
        bool loaded;
        bool focused;
        bool loadedCalled;
        bool initialized;
        bool scriptLoaded;

        EGLDisplay display;
        EGLSurface surface;
        EGLContext context;

        GLint framebuffer;

        int32_t width;
        int32_t height;
        int32_t lastError;

        timeb startTime;

        float touchEventParamCache[MOTION_EVENT_PARAMS_SIZE];
        float keyEventParamCache[KEY_EVENT_PARAMS_SIZE];
        float accelerometerEventParamCache[ACCELEROMETER_EVENT_PARAMS_SIZE];

        timeb   lastOnDrawInterval;
        timeb   lastOnDrawDrawablesInterval;

        int32_t onFpsIntervalDelta;
        int32_t frameCount;

        bool      stopwatchStarted;
        bool      stopwatchStopped;
        timeb     stopwatchStartTime;
        timeb     stopwatchRestartTime;
        timeb     stopwatchAccumulateTime;
        int32_t   stopwatchElapsedTime;
        int32_t   getLastStopwatchElapsedDelta();

        bool enablePerspectiveNicest;
        bool enableOnDrawFrame;
        bool enableBackKey;
        bool enableOnUpdate;
        bool enableOnFps;

        drawables_t* drawables;
        drawables_t* drawablesToRemove;
        std::vector<Drawable*>* sortedDrawables;
        images_t* imageCache;

        ASensorManager* sensorManager;
        ASensorEventQueue* sensorEventQueue;

        const ASensor* accelerometerSensor;
        const ASensor* magneticSensor;
        const ASensor* gyroscopeSensor;
        const ASensor* lightSensor;
        const ASensor* proximitySensor;

        std::string getRuntimeScriptName();
        std::string getMainScriptName();
    };
}
#endif
