--
-- SDL_WRAP.LUA
--
local m= {}     -- public, application namespace
local n= {}     -- private, C module namespace

if not Gluahost( "sdl_module", n ) then     -- load the dll/so/dylib
    return nil  -- module not compiled
end

USES 'lib.bitlib'
local bor= ASSUME( lib.bitlib.bor )

local borX= function(...)    -- pass through 'nil'
              if table.getn(arg)>0 then return bor( unpack(arg) ) end
            end

m._info= ASSUME( n._info )

-- Copy stuff from C module to our namespace:
--
for k,v in n do
    --
    if type(v)=="function" then
        local new_k= string.gsub( k, "^SDL_", "" )
        m[new_k]= v
    else
        if k=="SDL_VERSION" or k=="SDL_LINKED_VERSION" then
            m[string.sub(k,5)]= v   -- "SDL_" stripped away
        else
            m[k]= v     -- "SDL_" remains (if any)
        end
    end
end


--== Plain functions ==--

-- Use of 'bor(unpack(arg))' allows the use of many arguments:
--
--      evbuf= sdl.Init( SDL_INIT_AUDIO, SDL_INIT_VIDEO )
--
m.Init= function( ... ) 
            local err= n.SDL_Init( borX(unpack(arg)) ) 
            return (err==0 and n.SDL_Event()) or nil
        end
m.Quit= function( ... ) return n.SDL_Quit( borX(unpack(arg)) ) end


-- Surface functions:
--
local function SurfNew( ud )    -- wrap userdata into a Lua object (with methods)
    return ud and m.Surface_new(ud) or nil
end

function m.FreeSurface(h)
    if h._ud then n.SDL_FreeSurface(h._ud); h._ud=nil end
end

function m.DisplayFormat(h)
    return SurfNew( n.SDL_DisplayFormat(h._ud) ) 
end

function m.DisplayFormatAlpha(h)
    return SurfNew( n.SDL_DisplayFormatAlpha(h._ud) ) 
end

function m.SetVideoMode( w, h, bpp, flags )
    return SurfNew( n.SDL_SetVideoMode( w,h, bpp, flags ) )
end

function m.LoadBMP(fn)
    return SurfNew( n.SDL_LoadBMP( fn ) )
end

function m.CreateRGBSurface(...)
    return SurfNew( n.SDL_CreateRGBSurface( unpack(arg) ) )
end

function m.CreateRGBSurfaceFrom(...)
    return SurfNew( n.SDL_CreateRGBSurfaceFrom( unpack(arg) ) )
end

-- Surface object template
--
-- Preparing this template separately (and not at every 'Surface_new' call)
-- makes things a bit faster (skipping ASSUMEs at object creation). Also, it
-- is good to have only one (constant) metatable instead of new ones for 
-- each object.
--
local _surf_template= {    
    SetSurface=     ASSUME( m.SetSurface ),
    UpdateRect=     ASSUME( m.UpdateRect ),
    UpdateRects=    ASSUME( m.UpdateRects ),
    Flip=           ASSUME( m.Flip ),
    SetColors=      ASSUME( m.SetColors ),
    SetPalette=     ASSUME( m.SetPalette ),
    FreeSurface=    ASSUME( m.FreeSurface ),
    LoadBMP=        function(h,fn) 
                        local _ud= n.SDL_LoadBMP(fn)    -- try first if it succeeds
                        if _ud then   -- yes, it did
                            h:FreeSurface()
                            h._ud= _ud
                            return true
                        end
                    end,
    SaveBMP=        ASSUME( m.SaveBMP ),
    SetColorKey=    ASSUME( m.SetColorKey ),
    SetAlpha=       ASSUME( m.SetAlpha ),
    SetClipRect=    ASSUME( m.SetClipRect ),
    GetClipRect=    ASSUME( m.GetClipRect ),
    ConvertSurface= ASSUME( m.ConvertSurface ),
    FillRect=       ASSUME( m.FillRect ),
    DisplayFormat=  ASSUME( m.DisplayFormat ),
    DisplayFormatAlpha= ASSUME( m.DisplayFormatAlpha ),
    SetIcon=        ASSUME( m.WM_SetIcon ),
    ToggleFullScreen= ASSUME( m.WM_ToggleFullScreen ),
    }

local _surf_metatable=
    { __gc= function(h) h:FreeSurface() end,
      __index= function(h,k) return (k=="_ud") and (h._ud) or (h._ud)[k] end,
      __newindex= function(h,k,v) (h._ud)[k]= v end, 
    }

-----
-- [obj]= Surface_new( [bmp_filename] [bitmap_tbl] [raw_ud] )
--
m.Surface_new= function( p1 )
    --
    local obj= {}
    local p1_str= type(p1)=="string" and p1
    local p1_tbl= type(p1)=="table" and p1
    local p1_ud=  type(p1)=="userdata" and p1

    if p1_str then  -- filename
        obj._ud= n.SDL_LoadBMP( p1_str )
    elseif p1_ud then   -- raw userdata
        obj._ud= p1_ud
    else
        obj._ud= n.SDL_GetVideoSurface()    -- empty surface
    end

    if not obj._ud then return nil; end

    --
    if p1_tbl then  -- fill with a predefined pattern
        n.SDL_SetSurface( obj._ud, p1_tbl )
    end

    -- Member functions:
    --
    for k,v in _surf_template do
        obj[k]= v
    end
    setmetatable( obj, ASSUME(_surf_metatable) )

    return obj
end

-----
-- Cursor functions:
--
-- Only C code can assign GC to userdata, so we have to wrap it in a table
-- (even if we didn't use any member functions).
--
m.Cursor_new= function( data_tbl, mask_tbl, w,h, hotx,hoty )
    --
    local ud= data_tbl and n.SDL_CreateCursor( data_tbl, mask_tbl, w,h, hotx, hoty  )
                        or n.SDL_GetCursor()
    if not ud then return nil end

    local obj= { _ud= ud }

    table.setmetatable( obj, { __gc= function(h) m.FreeCursor(h) end } )

    return obj
end

m.GetCursor= m.Cursor_new

m.FreeCursor= function(obj) 
                if obj._ud then n.SDL_FreeCursor(obj._ud) end
                obj._ud= nil
              end


-- This is an additional userdata->table conversion, mainly for debugging
-- purposes.
--  
m.EventDump= function(e)   -- tbl= EventDump( event_ud )
    --
    local type= e.type
    local ret= {}
    local tmp

    if type==n.SDL_ACTIVEEVENT then
        ret.active= e.active
        tmp= "ACTIVEEVENT"
        --
    elseif type==n.SDL_KEYDOWN or type==n.SDL_KEYUP then
        ret.key= e.key
        tmp= (type==n.SDL_KEYDOWN) and "KEYDOWN" or "KEYUP"
        --
    elseif type==n.SDL_MOUSEMOTION then
        ret.motion= e.motion
        tmp= "MOUSEMOTION"
        --
    elseif type==n.SDL_MOUSEBUTTONDOWN or type==n.SDL_MOUSEBUTTONUP then
        ret.button= e.button
        tmp= "MOUSEBUTTON".. ((type==n.SDL_MOUSEBUTTONDOWN) and "DOWN" or "UP")
        --
    elseif type==n.SDL_JOYAXISMOTION then
        ret.jaxis= e.jaxis
        tmp= "JOYAXISMOTION"
        --
    elseif type==n.SDL_JOYBALLMOTION then
        ret.jball= e.jball
        tmp= "JOYBALLMOTION"
        --
    elseif type==n.SDL_JOYHATMOTION then
        ret.jhatype= e.jhat
        tmp= "JOYHATMOTION"
        --
    elseif type==n.SDL_JOYBUTTONDOWN or type==n.SDL_JOYBUTTONUP then
        ret.jbutton= e.jbutton
        tmp= "JOYBUTTON".. ((type==n.SDL_JOYBUTTONDOWN) and "DOWN" or "UP")
        --
    elseif type==n.SDL_VIDEORESIZE then
        ret.resize= e.resize
        tmp= "VIDEORESIZE"
        --
    elseif type==n.SDL_VIDEOEXPOSE then
        ret.expose= e.expose    -- (nil)
        tmp= "VIDEOEXPOSE"
        --
    elseif type==n.SDL_QUIT then
        ret.quitype= e.quit        -- (nil)
        tmp= "QUIT"
        --
    elseif type==n.SDL_USEREVENT then
        ret.user= e.user
        tmp= "USEREVENT"
        --
    elseif type==n.SDL_SYSWMEVENT then
        ret.syswm= e.syswm
        tmp= "SYSWMEVENT"
        --
    else
        error( "Unknown SDL event type: "..type.."!" )
    end

    ret.type= tmp.." ("..type..")"

    return ret
end


--== Module cleanup ==--

setmetatable( m, { __gc= function(tbl) n.SDL_Quit() end } )  -- atexit


--== SDL_GFX submodule ==--

function m.rotozoomSurface(...)
    return SurfNew( n.rotozoomSurface( unpack(arg) ) ) 
end

function m.zoomSurface(...)
    return SurfNew( n.zoomSurface( unpack(arg) ) ) 
end

m.pixel=        ASSUME( n.gfx_pixel )
m.hline=        ASSUME( n.gfx_hline )
m.vline=        ASSUME( n.gfx_vline )
m.rect=         ASSUME( n.gfx_rect )
m.box=          ASSUME( n.gfx_box )
m.line=         ASSUME( n.gfx_line )    -- aaline
m.circle=       ASSUME( n.gfx_circle )  -- aacircle, filledCircle
m.ellipse=      ASSUME( n.gfx_ellipse ) -- aaellipse, filledEllipse
m.pie=          ASSUME( n.gfx_pie )
m.trigon=       ASSUME( n.gfx_trigon )  -- aatrigon, filledTrigon
m.polygon=      ASSUME( n.gfx_polygon ) -- aapolygon, filledPolygon
m.bezier=       ASSUME( n.gfx_bezier )
m.string=       ASSUME( n.gfx_string )


--== Globalize ==--

local function my_globalize( sdl )
    --
    for k,v in sdl do   -- copy to global namespace

        if type(v)=="function" then
            --
            if string.find(k,"^Gfx") then
                -- GfxPixel.. (skip)
            elseif string.find(k,"RGBA") and k~="MapRGBA" then
                -- pixelRGBA, ...
                rawset( _G, k, v )  -- as is
            else
                rawset( _G, "SDL_"..k, v )
            end
        else
            rawset( _G, k, v )
        end
    end

    rawset( _G, "SDL_NORMAL", ASSUME(sdl.GFX_NORMAL) )
    rawset( _G, "SDL_FILLED", ASSUME(sdl.GFX_FILLED) )
    rawset( _G, "SDL_SMOOTH", ASSUME(sdl.GFX_SMOOTH) )
    --..
end

return m, my_globalize
