#include "engine/media.h"

void unimplemented( ... )
{
    printf( "This function is not implemented.\n");
}

Context::Context()
{
    EngineBasis = { 0, 1, 2, 4, 8 };
    EventInfo.Type = { 0x7FFFFFFF, 1, 2, 4 };
    EventInfo.Mouse.Type = { 0x7FFFFFFF, 1, 2, 4 };
    EventInfo.Mouse.Button = { 0x7FFFFFFF, 1, 2, 4, 8, 16, 32, 128 };
    EventInfo.Keyboard.Type = { 0x7FFFFFFF, 1, 2, 4 };
    EventInfo.Keyboard.Key.Modifier = { 0x7FFFFFFF, 1, 2, 4, 8, 16, 32, 128, 256, 512 };
    EventInfo.System.Type = { 0x7FFFFFFF, 1, 2, 4 };
    audiomixercallback = 0;
    mixaudio = 0;
    audioinited = 0;
}

void Context::create_screen( int width, int height, bool fullscreen, bool border, bool resizable )
{
    _internal_create_screen( this, width, height, fullscreen, border, resizable );
}

void Context::EventListener::push( int eventtype, int eventid, int args, ... )
{
    if( accepttype & eventtype == 0 )
        return;
    Event a;
    a.Args = args;
    a.Type = eventtype;
    a.EventID = eventid;
    va_list b;
    va_start( b, args );
    for( int i = 0; i < args && i < 10; i ++ ){
        a.EventData[i] = va_arg( b, int );
    }
    va_end( b );
    eventqueue.push_back( a );
}

void Context::EventListener::pushva( int eventtype, int eventid, int args, va_list b )
{
    if( (accepttype & eventtype) == 0 && accepttype > 0 )
        return;
    Event a;
    a.Args = args;
    a.Type = eventtype;
    a.EventID = eventid;
    for( int i = 0; i < args && i < 10; i ++ ){
        a.EventData[i] = va_arg( b, int );
    }
    eventqueue.push_back( a );
}

Context::Event Context::EventListener::pop( )
{
    Event a = eventqueue.front();
    eventqueue.pop_front();
    return a;
}

int Context::EventListener::events( )
{
    return eventqueue.size();
}

int Context::Image::width()
{
    return parent->_internal_image_width( this );
}

int Context::Image::height()
{
    return parent->_internal_image_height( this );
}

void* Context::Image::getdata()
{
    return data;
}


int Context::Sound::getlength()
{
    return parent->_internal_sound_getlength( this );
}
 //in samples
int Context::Sound::getsamplerate()
{
    return parent->_internal_sound_getsamplerate( this );
}
 //in hz
void* Context::Sound::getdata()
{
    return data;
}


int Context::Surface::width()
{
    return parent->_internal_surface_width( this );
}

int Context::Surface::height()
{
    return parent->_internal_surface_height( this );
}

void* Context::Surface::getdata()
{
    return data;
}


void Context::surface_set_target( Surface* surf )
{
    main = surf;
}

void Context::surface_reset_target( )
{
    main = mainalt;
}

int Context::func_register( void(*func)() )
{
    functions.push_back( func );
    return functions.size() - 1;
}

int Context::func_unregister( int id )
{
    functions[id] = 0;
}

void Context::enter_loop()
{
    inloop = true;
    while( inloop ){
        handle_io();
        for( int i = 0; i < functions.size(); i ++ )
            if( functions[i] != 0 )
                functions[i]();
    }
}

void Context::exit_loop()
{
    inloop = false;
}

Context::EventListener* Context::listener_add( int flags )
{
    EventListener* a = new EventListener;
    a->pos = listeners.size();
    listeners.push_back( a );
    a->accepttype = flags;
    return a;
}

int Context::listener_remove( Context::EventListener* list )
{
    listeners[list->pos] = 0;
    return 1;
}

void Context::listener_push_event( int eventtype, int eventid, int args, ... )
{
    va_list a;
    va_start( a, args );
    for( int i = 0; i < listeners.size(); i ++ )
    {
        listeners[i]->pushva( eventtype, eventid, args, a );
    }
    va_end( a );
}

Context::Image* Context::push_image( void* in )
{
    Image* a = new Image;
    a->data = in;
    a->parent = this;
    a->pos = images.size();
    a->origin.x = a->origin.y = 0;
    images.push_back( a );
    return a;
}

Context::Surface* Context::push_surface( void* in )
{
    Surface* a = new Surface;
    a->data = in;
    a->parent = this;
    a->pos = surfaces.size();
    surfaces.push_back( a );
    return a;
}

Context::Sound* Context::push_sound( void* in )
{
    Sound* a = new Sound;
    a->data = in;
    a->parent = this;
    a->pos = sounds.size();
    sounds.push_back( a );
    return a;
}



void Context::handle_io()
{
    _internal_handle_io( this );
}

Context::Image* Context::image_load( const char* fname )
{
    return _internal_image_load( this, fname );
}

Context::Image* Context::image_load( void* mem, int len )
{
    return _internal_image_load_mem( this, mem, len );
}

Context::Surface* Context::surface_create(int w, int h)
{
    return _internal_surface_create( this, w, h );
}

Context::Surface* Context::surface_from_image(Context::Image* in)
{
    return _internal_surface_from_image( this, in );
}

Context::Image* Context::image_from_surface(Context::Image* in)
{
    return _internal_image_from_surface( this, in );
}

Context::Sound* Context::sound_load( const char* fname )
{
    return _internal_sound_load( this, fname );
}

Context::Sound* Context::sound_load( void* mem, int len )
{
    return _internal_sound_load_mem( this, mem, len );
}

int Context::sound_unload(Context::Sound* in)
{
    _internal_sound_unload( this, in );
    sounds[in->pos] = 0;
    return true;
}

int Context::image_unload(Context::Image* in)
{
    _internal_image_unload( this, in );
    images[in->pos] = 0;
    return true;
}

int Context::surface_free(Context::Surface* in)
{
    _internal_surface_free( this, in );
    surfaces[in->pos] = 0;
    return true;
}

void Context::draw_rectangle( int x1, int y1, int x2, int y2, Context::Color color, bool filled )
{
    _internal_draw_rectangle( this, x1, y1, x2, y2, color, filled );
}

void Context::draw_line( int x1, int y1, int x2, int y2, Context::Color color )
{
    _internal_draw_line( this, x1, y1, x2, y2, color );
}

void Context::draw_circle( int x, int y, int r, Context::Color color, bool filled )
{
    _internal_draw_circle( this, x, y, r, color, filled );
}

void Context::draw_ellipse( int x1, int y1, int x2, int y2, Context::Color color, bool filled )
{
    _internal_draw_ellipse( this, x1, y1, x2, y2, color, filled );
}

void Context::draw_image( int x, int y, Context::Image* img )
{
    _internal_draw_image( this, x, y, img );
}

void Context::draw_surface( int x, int y, Context::Surface* img )
{
    _internal_draw_surface( this, x, y, img );
}

void Context::draw_image( int x, int y, Context::Surface* img )
{
    _internal_draw_surface( this, x, y, img );
}

void Context::draw_surface( int x, int y, Context::Image* img )
{
    _internal_draw_image( this, x, y, img );
}

void Context::draw_image_part( int x, int y, int left, int top, int w, int h, Context::Image* img )
{
    _internal_draw_image_part( this, x, y, left, top, w, h, img );
}

void Context::draw_surface_part( int x, int y, int left, int top, int w, int h, Context::Surface* img )
{
    _internal_draw_surface_part( this, x, y, left, top, w, h, img );
}

void Context::draw_image_part( int x, int y, int left, int top, int w, int h, Context::Surface* img )
{
    _internal_draw_surface_part( this, x, y, left, top, w, h, img );
}

void Context::draw_surface_part( int x, int y, int left, int top, int w, int h, Context::Image* img )
{
    _internal_draw_image_part( this, x, y, left, top, w, h, img );
}

int Context::sound_play( Context::Sound* in )
{
    return _internal_sound_play( this, in );
}

void Context::repaint(int x, int y, int w, int h )
{
    _internal_repaint( this, x, y, w, h );
}

void Context::cleanup()
{
    _internal_cleanup( this );
}

int Context::init_sound( int samplerate, int updaterate, int bitrate )
{
    return _internal_init_sound( this, samplerate, updaterate, bitrate );
}
void Context::sound_set_callback( void* userdata, void (*audiomixercallbacka)(void*, unsigned char *stream, int len) )
{
    audiomixercallback = audiomixercallbacka;
    _internal_sound_set_callback( this, userdata, audiomixercallbacka );
}
void Context::set_caption( char* text, char* icon )
{
    _internal_set_caption( this, text, icon );
}