#include "engine/media.h"
#include "engine/mediaSDL.h"

void _SDL_init ( Context* me )
{
    me->_internal_draw_circle           = _SDL_draw_circle;
    me->_internal_create_screen         = _SDL_create_screen;
    me->_internal_draw_ellipse          = _SDL_draw_ellipse;
    me->_internal_draw_image            = _SDL_draw_image;
    me->_internal_draw_image_part       = _SDL_draw_image_part;
    me->_internal_draw_line             = _SDL_draw_line;
    me->_internal_draw_rectangle        = _SDL_draw_rectangle;
    me->_internal_draw_surface          = _SDL_draw_surface;
    me->_internal_draw_surface_part     = _SDL_draw_surface_part;
    me->_internal_handle_io             = _SDL_handle_io;
    me->_internal_image_from_surface    = _SDL_image_from_surface;
    me->_internal_image_height          = _SDL_image_height;
    me->_internal_image_load            = _SDL_image_load;
    me->_internal_image_load_mem        = _SDL_image_load_mem;
    me->_internal_image_unload          = _SDL_image_unload;
    me->_internal_image_width           = _SDL_image_width;
    me->_internal_repaint               = _SDL_repaint;
    me->_internal_sound_getlength       = _SDL_sound_getlength;
    me->_internal_sound_getsamplerate   = _SDL_sound_getsamplerate;
    me->_internal_sound_load            = _SDL_sound_load;
    me->_internal_sound_load_mem        = _SDL_sound_load_mem;
    me->_internal_sound_play            = _SDL_sound_play;
    me->_internal_sound_unload          = _SDL_sound_unload;
    me->_internal_surface_create        = _SDL_surface_create;
    me->_internal_surface_free          = _SDL_surface_free;
    me->_internal_surface_from_image    = _SDL_surface_from_image;
    me->_internal_surface_height        = _SDL_surface_height;
    me->_internal_surface_width         = _SDL_surface_width;
    me->_internal_cleanup               = _SDL_cleanup;
    me->_internal_init_sound            = _SDL_init_sound;
    me->_internal_sound_set_callback    = _SDL_sound_set_callback;
    me->_internal_set_caption           = _SDL_set_caption;



    me->EventInfo.Mouse.Button.Left          = SDL_BUTTON_LEFT;
    me->EventInfo.Mouse.Button.Middle        = SDL_BUTTON_MIDDLE;
    me->EventInfo.Mouse.Button.Right         = SDL_BUTTON_RIGHT;
    me->EventInfo.Mouse.Button.X1            = SDL_BUTTON_X1;
    me->EventInfo.Mouse.Button.X2            = SDL_BUTTON_X2;
    me->EventInfo.Mouse.Button.WheelUp       = SDL_BUTTON_WHEELUP;
    me->EventInfo.Mouse.Button.WheelDown     = SDL_BUTTON_WHEELDOWN;


    me->EventInfo.Keyboard.Key.Escape        = SDLK_ESCAPE;
    me->EventInfo.Keyboard.Key.F1            = SDLK_F1;
    me->EventInfo.Keyboard.Key.F2            = SDLK_F2;
    me->EventInfo.Keyboard.Key.F3            = SDLK_F3;
    me->EventInfo.Keyboard.Key.F4            = SDLK_F4;
    me->EventInfo.Keyboard.Key.F5            = SDLK_F5;
    me->EventInfo.Keyboard.Key.F6            = SDLK_F6;
    me->EventInfo.Keyboard.Key.F7            = SDLK_F7;
    me->EventInfo.Keyboard.Key.F8            = SDLK_F8;
    me->EventInfo.Keyboard.Key.F9            = SDLK_F9;
    me->EventInfo.Keyboard.Key.F10           = SDLK_F10;
    me->EventInfo.Keyboard.Key.F11           = SDLK_F11;
    me->EventInfo.Keyboard.Key.F12           = SDLK_F12;
    me->EventInfo.Keyboard.Key.F13           = SDLK_F13;
    me->EventInfo.Keyboard.Key.F14           = SDLK_F14;
    me->EventInfo.Keyboard.Key.F15           = SDLK_F15;
    me->EventInfo.Keyboard.Key.F16           = SDLK_F15;
    me->EventInfo.Keyboard.Key.F17           = SDLK_F15;
    me->EventInfo.Keyboard.Key.F18           = SDLK_F15;
    me->EventInfo.Keyboard.Key.F19           = SDLK_F15;
    me->EventInfo.Keyboard.Key.F20           = SDLK_F15;
    me->EventInfo.Keyboard.Key.PrintScreen   = SDLK_PRINT;
    me->EventInfo.Keyboard.Key.ScrollLock    = SDLK_SCROLLOCK;
    me->EventInfo.Keyboard.Key.Pause         = SDLK_PAUSE;
    me->EventInfo.Keyboard.Key.Tilde         = SDLK_BACKQUOTE;
    me->EventInfo.Keyboard.Key.K_1           = SDLK_1;
    me->EventInfo.Keyboard.Key.K_2           = SDLK_2;
    me->EventInfo.Keyboard.Key.K_3           = SDLK_3;
    me->EventInfo.Keyboard.Key.K_4           = SDLK_4;
    me->EventInfo.Keyboard.Key.K_5           = SDLK_5;
    me->EventInfo.Keyboard.Key.K_6           = SDLK_6;
    me->EventInfo.Keyboard.Key.K_7           = SDLK_7;
    me->EventInfo.Keyboard.Key.K_8           = SDLK_8;
    me->EventInfo.Keyboard.Key.K_9           = SDLK_9;
    me->EventInfo.Keyboard.Key.K_0           = SDLK_0;
    me->EventInfo.Keyboard.Key.Dash          = SDLK_MINUS;
    me->EventInfo.Keyboard.Key.Equals        = SDLK_EQUALS;
    me->EventInfo.Keyboard.Key.Backspace     = SDLK_BACKSPACE;
    me->EventInfo.Keyboard.Key.Tab           = SDLK_TAB;
    me->EventInfo.Keyboard.Key.Q             = SDLK_q;
    me->EventInfo.Keyboard.Key.W             = SDLK_w;
    me->EventInfo.Keyboard.Key.E             = SDLK_e;
    me->EventInfo.Keyboard.Key.R             = SDLK_r;
    me->EventInfo.Keyboard.Key.T             = SDLK_t;
    me->EventInfo.Keyboard.Key.Y             = SDLK_y;
    me->EventInfo.Keyboard.Key.U             = SDLK_u;
    me->EventInfo.Keyboard.Key.I             = SDLK_i;
    me->EventInfo.Keyboard.Key.O             = SDLK_o;
    me->EventInfo.Keyboard.Key.P             = SDLK_p;
    me->EventInfo.Keyboard.Key.BracketOpen   = SDLK_LEFTBRACKET;
    me->EventInfo.Keyboard.Key.BracketClosed = SDLK_RIGHTBRACKET;
    me->EventInfo.Keyboard.Key.FSlash        = SDLK_BACKSLASH;
    me->EventInfo.Keyboard.Key.ForwardSlash  = SDLK_BACKSLASH;
    me->EventInfo.Keyboard.Key.CapsLock      = SDLK_CAPSLOCK;
    me->EventInfo.Keyboard.Key.A             = SDLK_a;
    me->EventInfo.Keyboard.Key.S             = SDLK_s;
    me->EventInfo.Keyboard.Key.D             = SDLK_d;
    me->EventInfo.Keyboard.Key.F             = SDLK_f;
    me->EventInfo.Keyboard.Key.G             = SDLK_g;
    me->EventInfo.Keyboard.Key.H             = SDLK_h;
    me->EventInfo.Keyboard.Key.J             = SDLK_j;
    me->EventInfo.Keyboard.Key.K             = SDLK_k;
    me->EventInfo.Keyboard.Key.L             = SDLK_l;
    me->EventInfo.Keyboard.Key.Colon         = SDLK_COLON;
    me->EventInfo.Keyboard.Key.Quote         = SDLK_QUOTE;
    me->EventInfo.Keyboard.Key.Enter         = SDLK_RETURN;
    me->EventInfo.Keyboard.Key.LShift        = SDLK_LSHIFT;
    me->EventInfo.Keyboard.Key.Z             = SDLK_z;
    me->EventInfo.Keyboard.Key.X             = SDLK_x;
    me->EventInfo.Keyboard.Key.C             = SDLK_c;
    me->EventInfo.Keyboard.Key.V             = SDLK_v;
    me->EventInfo.Keyboard.Key.B             = SDLK_b;
    me->EventInfo.Keyboard.Key.N             = SDLK_n;
    me->EventInfo.Keyboard.Key.M             = SDLK_m;
    me->EventInfo.Keyboard.Key.Comma         = SDLK_COMMA;
    me->EventInfo.Keyboard.Key.Period        = SDLK_PERIOD;
    me->EventInfo.Keyboard.Key.Slash         = SDLK_SLASH;
    me->EventInfo.Keyboard.Key.RShift        = SDLK_RSHIFT;
    me->EventInfo.Keyboard.Key.LControl      = SDLK_LCTRL;
    me->EventInfo.Keyboard.Key.LAlt          = SDLK_LALT;
    me->EventInfo.Keyboard.Key.Space         = SDLK_SPACE;
    me->EventInfo.Keyboard.Key.RAlt          = SDLK_RALT;
    me->EventInfo.Keyboard.Key.RControl      = SDLK_RCTRL;
    me->EventInfo.Keyboard.Key.Insert        = SDLK_INSERT;
    me->EventInfo.Keyboard.Key.Home          = SDLK_HOME;
    me->EventInfo.Keyboard.Key.PageUp        = SDLK_PAGEUP;
    me->EventInfo.Keyboard.Key.Delete        = SDLK_DELETE;
    me->EventInfo.Keyboard.Key.End           = SDLK_END;
    me->EventInfo.Keyboard.Key.PageDown      = SDLK_PAGEDOWN;
    me->EventInfo.Keyboard.Key.NumLock       = SDLK_NUMLOCK;
    me->EventInfo.Keyboard.Key.NumSlash      = SDLK_KP_DIVIDE;
    me->EventInfo.Keyboard.Key.NumStar       = SDLK_KP_MULTIPLY;
    me->EventInfo.Keyboard.Key.NumMinus      = SDLK_KP_MINUS;
    me->EventInfo.Keyboard.Key.Num7          = SDLK_KP7;
    me->EventInfo.Keyboard.Key.Num8          = SDLK_KP8;
    me->EventInfo.Keyboard.Key.Num9          = SDLK_KP9;
    me->EventInfo.Keyboard.Key.NumPlus       = SDLK_KP_PLUS;
    me->EventInfo.Keyboard.Key.Num4          = SDLK_KP4;
    me->EventInfo.Keyboard.Key.Num5          = SDLK_KP5;
    me->EventInfo.Keyboard.Key.Num6          = SDLK_KP6;
    me->EventInfo.Keyboard.Key.Num1          = SDLK_KP1;
    me->EventInfo.Keyboard.Key.Num2          = SDLK_KP2;
    me->EventInfo.Keyboard.Key.Num3          = SDLK_KP3;
    me->EventInfo.Keyboard.Key.NumEnter      = SDLK_KP_ENTER;
    me->EventInfo.Keyboard.Key.Num0          = SDLK_KP0;
    me->EventInfo.Keyboard.Key.NumPeriod     = SDLK_KP_PERIOD;
    me->EventInfo.Keyboard.Key.Left          = SDLK_LEFT;
    me->EventInfo.Keyboard.Key.Right         = SDLK_RIGHT;
    me->EventInfo.Keyboard.Key.Up            = SDLK_UP;
    me->EventInfo.Keyboard.Key.Down          = SDLK_DOWN;


    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
        return;


    me->EngineBase = me->EngineBasis.SDL;


}



void _SDL_handle_io ( Context* me )
{
    SDL_Event event;
    while( SDL_PollEvent( &event ) )
    {
        switch( event.type )
        {

            case SDL_VIDEORESIZE:{ me->listener_push_event( me->EventInfo.Type.System, me->EventInfo.System.Type.Resize, 2, event.resize.w , event.resize.h ); } break;
            case SDL_QUIT:{ me->listener_push_event( me->EventInfo.Type.System, me->EventInfo.System.Type.Quit, 0 ); } break;
            case SDL_KEYDOWN:{me->listener_push_event( me->EventInfo.Type.Keyboard, me->EventInfo.Keyboard.Type.KeyDown, 2, event.key.keysym.sym, event.key.keysym.unicode );break;}
            case SDL_KEYUP:{me->listener_push_event( me->EventInfo.Type.Keyboard, me->EventInfo.Keyboard.Type.KeyUp, 2, event.key.keysym.sym, event.key.keysym.unicode );break;}
            case SDL_MOUSEMOTION:{me->listener_push_event( me->EventInfo.Type.Mouse, me->EventInfo.Mouse.Type.Move, 2, event.motion.x, event.motion.y );break;}
            case SDL_MOUSEBUTTONDOWN:{me->listener_push_event( me->EventInfo.Type.Mouse, me->EventInfo.Mouse.Type.ClickDown, 3, event.button.button, event.button.x, event.button.y );break;}
            case SDL_MOUSEBUTTONUP:{me->listener_push_event( me->EventInfo.Type.Mouse, me->EventInfo.Mouse.Type.ClickUp, 3, event.button.button, event.button.x, event.button.y );break;}
        }
    }
}

void _SDL_create_screen ( Context* me, int width, int height, bool fullscreen, bool border, bool resizable )
{
    _SDL_SCREEN(me) = SDL_SetVideoMode( width, height, 32, SDL_SWSURFACE | ( SDL_FULLSCREEN * fullscreen ) | ( SDL_RESIZABLE * resizable ) | ( SDL_NOFRAME * border ) );
    me->main = me->push_surface( _SDL_SCREEN(me) );
    me->mainalt = me->main;
}

Context::Image* _SDL_image_load ( Context* me, const char* fname )
{
    return me->push_image( (void*)
                          //#ifdef ALIB_SDL_IMAGE
                          IMG_Load( fname )
                          //#else
                          //SDL_LoadBMP( fname )
                          //#endif
                          );
}

Context::Image* _SDL_image_load_mem ( Context* me, void* mem, int len )
{
    SDL_RWops* tmp = SDL_RWFromMem( mem, len );
    return me->push_image( (void*)
                          //#ifdef ALIB_SDL_IMAGE
                          IMG_Load_RW( tmp, 1 )
                          //#else
                          //SDL_LoadBMP_RW( tmp, 1 )
                          //#endif
                           );
}

Context::Surface* _SDL_surface_create ( Context* me, int w, int h)
{
    return me->push_surface( (void*) SDL_CreateRGBSurface( SDL_SWSURFACE | SDL_SRCALPHA,
                                 w, h,
                                 _SDL_SCREEN(me)->format->BitsPerPixel,
                                 _SDL_SCREEN(me)->format->Rmask,
                                 _SDL_SCREEN(me)->format->Gmask,
                                 _SDL_SCREEN(me)->format->Bmask,
                                 _SDL_SCREEN(me)->format->Amask ) );
}

Context::Surface* _SDL_surface_from_image ( Context* me, Context::Image* in)
{

}

Context::Image* _SDL_image_from_surface ( Context* me, Context::Image* in)
{

}

Context::Sound* _SDL_sound_load ( Context* me, const char* fname )
{

}

Context::Sound* _SDL_sound_load_mem ( Context* me, void*, int len )
{

}

int _SDL_sound_unload ( Context* me, Context::Sound*)
{

}

int _SDL_image_unload ( Context* me, Context::Image* img)
{
    SDL_FreeSurface( (SDL_Surface*)img->getdata() );
    return true;
}

int _SDL_surface_free ( Context* me, Context::Surface* img)
{
    SDL_FreeSurface( (SDL_Surface*)img->getdata() );
    return true;
}

void _SDL_draw_rectangle ( Context* me, int x, int y, int w, int h, Context::Color color, bool filled )
{
    SDL_Rect a;
    a.x = x;
    a.y = y;
    a.w = w;
    a.h = h;
    SDL_FillRect( _SDL_SCREEN(me), &a, SDL_MapRGBA( _SDL_SCREEN(me)->format, color.r, color.g, color.b, color.a ) );
}

void _SDL_draw_line ( Context* me, int x1, int y1, int x2, int y2, Context::Color color )
{

}

void _SDL_draw_circle ( Context* me, int x, int y, int r, Context::Color color, bool filled )
{

}

void _SDL_draw_ellipse ( Context* me, int x1, int y1, int x2, int y2, Context::Color color, bool filled )
{

}

void _SDL_draw_image ( Context* me, int x, int y, Context::Image* img )
{
    SDL_Rect a = { 0, 0, x - img->origin.x, y - img->origin.y };
    SDL_BlitSurface( (SDL_Surface*)img->getdata(), 0, (SDL_Surface*)me->main->getdata(), &a );
}

void _SDL_draw_image_part ( Context* me, int x, int y, int left, int top, int w, int h, Context::Image* img )
{
    SDL_Rect a = { x - img->origin.x, y - img->origin.y, 0, 0 };
    SDL_Rect b = { left, top, w, h };
    SDL_BlitSurface( (SDL_Surface*)img->getdata(), &b, (SDL_Surface*)me->main->getdata(), &a );
}

void _SDL_draw_surface ( Context* me, int x, int y, Context::Surface* img )
{
    SDL_Rect a = { 0, 0, x, y };
    SDL_BlitSurface( (SDL_Surface*)img->getdata(), 0, (SDL_Surface*)me->main->getdata(), &a );
}

void _SDL_draw_surface_part ( Context* me, int x, int y, int left, int top, int w, int h, Context::Surface* img )
{
    SDL_Rect a = { x, y, 0, 0 };
    SDL_Rect b = { left, top, w, h };

    SDL_BlitSurface( (SDL_Surface*)img->getdata(), &b, (SDL_Surface*)me->main->getdata(), &a );
}

int _SDL_sound_play ( Context* me, Context::Sound* )
{

}

void _SDL_repaint ( Context* me, int x, int y, int w, int h )
{
    if( x < 0 || y < 0 || w < 0 || h < 0 )
        SDL_Flip( _SDL_SCREEN(me) );
    else
        SDL_UpdateRect( _SDL_SCREEN(me), x, y, w, h );
}

int _SDL_image_width ( Context::Image* me )
{
    return ((SDL_Surface*)me->getdata())->w;
}

int _SDL_image_height ( Context::Image* me )
{
    return ((SDL_Surface*)me->getdata())->h;
}

int _SDL_sound_getlength ( Context::Sound* me )
{

}

int _SDL_sound_getsamplerate ( Context::Sound* me )
{

}

int _SDL_surface_width ( Context::Surface* me )
{
    return ((SDL_Surface*)me->getdata())->w;
}

int _SDL_surface_height ( Context::Surface* me )
{
    return ((SDL_Surface*)me->getdata())->h;
}

void _SDL_cleanup ( Context* me )
{
    if( me->audioinited != 0 )
        SDL_CloseAudio();
    SDL_Quit();
}

void _SDL_audiomixercallback(void* userdata, unsigned char *stream, int len)
{
    Context* me = (Context*) userdata;
    if( me->mixaudio == 0 ){
        if( me->audiomixercallback != 0 )
        {
            me->audiomixercallback( me->audiouserdata, stream, len );
        }
    } else {
        void* exstream = malloc( len );
        if( me->audiomixercallback != 0 )
        {
            me->audiomixercallback( me->audiouserdata, (unsigned char*)exstream, len );
        }
        SDL_MixAudio(stream, (Uint8*)exstream, len, SDL_MIX_MAXVOLUME);
        free( exstream );
    }
}

int _SDL_init_sound ( Context* me, int freq, int rate, int bitrate ) //bitrate & 0x80 equals whether or not it's a signed value
{
    SDL_AudioSpec fmt;
    fmt.freq = freq;
    switch( bitrate ){
        case 8: fmt.format = AUDIO_U8; break;
        case 8+0x80: fmt.format = AUDIO_S8; break;
        case 16: fmt.format = AUDIO_U16SYS; break;
        case 16+0x80: fmt.format = AUDIO_S16SYS; break;
    }
    fmt.channels = 1;
    fmt.samples = rate; /* A good value for games */
    fmt.callback = _SDL_audiomixercallback;
    fmt.userdata = (void*)me;

    /* Open the audio device and start playing sound! */
    if ( SDL_OpenAudio(&fmt, NULL) < 0 ) {
        fprintf(stderr, "Unable to open audio: %sn",
        SDL_GetError());
        return -1;
    }
    SDL_PauseAudio(0);
    SDL_LockAudio();
    SDL_UnlockAudio();
    me->audioinited = 1;
    return 0;
}
void _SDL_sound_set_callback ( Context* me, void* userdata, void (*audiomixercallbacka)(void*,unsigned char *stream, int len) )
{
    me->audiouserdata = userdata;
    me->audiomixercallback = audiomixercallbacka;
}
void _SDL_set_caption ( Context* me, char* title, char* icon )
{
    SDL_WM_SetCaption(title, title);
    SDL_WM_SetIcon( IMG_Load(icon) , 0 );// IMG_LoadICO(icon);

}