#pragma once
#include "global/stdinc.h"

void unimplemented( ... );

struct Context{
    struct __EngineBasis{ int None, SDL, OpenGL, DirectX, SFML; }EngineBasis;
    struct EventInfoStruct{
        struct __Type{ int Any, Mouse, Keyboard, System; }Type;
        struct __Mouse{
            struct __Type{ int Any, Move, ClickDown, ClickUp; }Type;
            struct __Button{ int Any, Left, Middle, Right, X1, X2, WheelUp, WheelDown; }Button;
        }Mouse;
        struct __Keyboard{
            struct __Type{ int Any, KeyDown, KeyUp, KeyRepeat; }Type;
            struct __Key{ struct __Modifier{ int Any, Caps, Shift, Control, Alt, LShift, RShift, LControl, RControl, NumLock; }Modifier;
                int F13, F14, F15, F16, F17, F18, F19, F20,
                PrintScreen, ScrollLock, Pause,
                K_1, K_2, K_3, K_4, K_5, K_6, K_7, K_8, K_9, K_0,
                Dash, Equals,
                BracketOpen, BracketClosed, Colon, Quote,
                Slash, Comma, Period, ForwardSlash,
                Shift, Control, Alt,

                Escape,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12,
                Tilde,                              Backspace,   Insert, Home,  PageUp,     NumLock,  NumSlash, NumStar,  NumMinus,
                Tab,     Q, W, E, R, T, Y, U, I, O, P, FSlash,   Delete, End,   PageDown,   Num7,     Num8,     Num9,     NumPlus,
                CapsLock,  A, S, D, F, G, H, J, K, L,   Enter,                              Num4,     Num5,     Num6,
                LShift,      Z, X, C, V, B, N, M,      RShift,           Up,                Num1,     Num2,     Num3,     NumEnter,
                LControl, LAlt,     Space,    RAlt,  RControl,   Left,   Down,  Right,      Num0,               NumPeriod;
            }Key;
        }Keyboard;
        struct __System{
            struct __Type{ int Any, Close, Resize, Quit; }Type;
        } System;
    }EventInfo;

    struct Event{
        int Type;
        int EventID;
        int Args;
        int EventData[10];
    };

    struct Image{
        void* data;
        Context* parent;
        struct __origin{int x,y;}origin;
        int width();
        int height();
        void* getdata();
        int pos;
    };

    struct Sound{
        void* data;
        Context* parent;
        int getlength(); //in samples
        int getsamplerate(); //in hz
        void* getdata();
        int pos;
    };

    struct Surface{
        void* data;
        Context* parent;
        int width();
        int height();
        void* getdata();
        int pos;
    };

    struct EventListener{
        std::deque<Event> eventqueue;
        int accepttype;
        void push( int eventtype, int eventid, int args, ... );
        void pushva( int eventtype, int eventid, int args, va_list );

        Event pop( );
        int events( );
        int pos;
    };

    struct Color{
        byte r,g,b,a;
    };
    struct Flags{
        struct Function{
            enum{
                Begin_Loop = 0,
                Begin_Step,
                Step,
                End_Step,
                Draw,
                End_Draw,
                Cleanup
            };
        };
    };
    int EngineBase;
    long flags;
    Surface* main;
    Surface* mainalt;
    bool inloop;

    char play[1000];

    Context();
    void surface_set_target( Surface* surf );
    void surface_reset_target( );
    int mixaudio,audioinited;
    std::vector<Image*> images;
    std::vector<Sound*> sounds;

    std::vector<Surface*> surfaces;
    std::vector<EventListener*> listeners;

    std::vector<void(*)()> functions;

    void (*audiomixercallback)(void* userdata, unsigned char *stream, int len);
    void* audiouserdata;

    int func_register( void(*)() );
    int func_unregister( int id );
    void enter_loop();
    void exit_loop();
    EventListener* listener_add( int flags );
    int listener_remove( EventListener* );
    void listener_push_event( int eventtype, int eventid, int args, ... );
    Image* push_image( void* );
    Surface* push_surface( void* );
    Sound* push_sound( void* );

    void create_screen( int width, int height, bool fullscreen = 0, bool border = 0, bool resizable = 0 );


    void handle_io();
    Image* image_load( const char* fname );
    Image* image_load( void*, int len );
    Surface* surface_create(int w, int h);
    Surface* surface_from_image(Image* in);
    Image* image_from_surface(Image* in);
    Sound* sound_load( const char* fname );
    Sound* sound_load( void*, int len );
    int sound_unload(Sound*);
    int image_unload(Image*);
    int surface_free(Surface*);
    void draw_rectangle( int x1, int y1, int x2, int y2, Color color, bool filled );
    void draw_line( int x1, int y1, int x2, int y2, Color color );
    void draw_circle( int x, int y, int r, Color color, bool filled );
    void draw_ellipse( int x1, int y1, int x2, int y2, Color color, bool filled );
    void draw_image( int x, int y, Image* img );
    void draw_surface( int x, int y, Surface* img );
    void draw_image( int x, int y, Surface* img );
    void draw_surface( int x, int y, Image* img );
    void draw_image_part( int x, int y, int left, int top, int w, int h, Image* img );
    void draw_surface_part( int x, int y, int left, int top, int w, int h, Surface* img );
    void draw_image_part( int x, int y, int left, int top, int w, int h, Surface* img );
    void draw_surface_part( int x, int y, int left, int top, int w, int h, Image* img );
    void set_caption( char* text, char* icon );

    int sound_play( Sound* );
    void repaint(int x = -1, int y = -1, int w = -1, int h = -1 );
    void cleanup();
    int init_sound( int samplerate, int updaterate, int bitrate );
    void sound_set_callback( void* userdata, void (*audiomixercallback)(void*,unsigned char *stream, int len) );

    void (*_internal_handle_io)(Context*);
    void (*_internal_create_screen)( Context* me, int width, int height, bool fullscreen, bool border, bool resizable );
    Image* (*_internal_image_load)( Context*, const char* fname );
    Image* (*_internal_image_load_mem)( Context*, void*, int len );
    Surface* (*_internal_surface_create)(Context*, int w, int h);
    Surface* (*_internal_surface_from_image)(Context*, Image* in);
    Image* (*_internal_image_from_surface)(Context*, Image* in);
    Sound* (*_internal_sound_load)( Context*, const char* fname );
    Sound* (*_internal_sound_load_mem)( Context*, void*, int len );
    int (*_internal_sound_unload)(Context*, Sound*);
    int (*_internal_image_unload)(Context*, Image*);
    int (*_internal_surface_free)(Context*, Surface*);
    void (*_internal_draw_rectangle)( Context*, int x1, int y1, int x2, int y2, Color color, bool filled );
    void (*_internal_draw_line)( Context*, int x1, int y1, int x2, int y2, Color color );
    void (*_internal_draw_circle)( Context*, int x, int y, int r, Color color, bool filled );
    void (*_internal_draw_ellipse)( Context*, int x1, int y1, int x2, int y2, Color color, bool filled );
    void (*_internal_draw_image)( Context*, int x, int y, Image* img );
    void (*_internal_draw_surface)( Context*, int x, int y, Surface* img );
    void (*_internal_draw_image_part)( Context*, int x, int y, int left, int top, int w, int h, Image* img );
    void (*_internal_draw_surface_part)( Context*, int x, int y, int left, int top, int w, int h, Surface* img );
    int (*_internal_sound_play)( Context*, Sound* );
    void (*_internal_repaint)(Context*, int x, int y, int w, int h );
    int (*_internal_image_width)(Image*);
    int (*_internal_image_height)(Image*);
    int (*_internal_sound_getlength)(Sound*); //in samples
    int (*_internal_sound_getsamplerate)(Sound*); //in hz
    int (*_internal_surface_width)(Surface*);
    int (*_internal_surface_height)(Surface*);
    void (*_internal_cleanup)( Context* );
    int (*_internal_init_sound)( Context*, int samplerate, int updaterate, int bitrate );
    void (*_internal_sound_set_callback)( Context*, void* userdata, void (*audiomixercallback)(void*, unsigned char *stream, int len) );
    void (*_internal_set_caption)( Context*, char* text, char* icon );
};