The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

#ifndef SDL_PERL_HELPER_H
#define SDL_PERL_HELPER_H

#include <SDL.h>
#include "SDL_thread.h"
#ifndef Uint32
#define Uint32 uint32_t
#endif

PerlInterpreter * perl = NULL;

void *bag2obj( SV *bag )
{
    void *obj = NULL;

    if( sv_isobject(bag) && (SvTYPE(SvRV(bag)) == SVt_PVMG) )
    {
        void **pointers = (void **)INT2PTR(void *, SvIV((SV *)SvRV( bag ))); 
        obj             = (void *)(pointers[0]);
    }
    
    return obj;
}

SV *obj2bag( int size_ptr,  void *obj, char *CLASS )
{
    SV *   objref;
    void** pointers;
    Uint32 *threadid;

    objref    = newSV( size_ptr );
    pointers  = safemalloc(3 * sizeof(void*));
    pointers[0]      = (void*)obj;
    pointers[1]      = (void*)PERL_GET_CONTEXT;
    threadid = (Uint32 *)safemalloc(sizeof(Uint32));
    *threadid        = SDL_ThreadID();
    pointers[2]      = (void*)threadid;
    sv_setref_pv( objref, CLASS, (void *)pointers);
    return objref;
}

SV *cpy2bag( void *object, int p_size, int s_size, char *package )
{
    void** pointers;
    Uint32 *threadid;
    SV* ref;
    SV* a;
    void *copy;
    
    ref  = newSV( p_size );
    copy = safemalloc( s_size );
    memcpy( copy, object, s_size );

    pointers  = safemalloc(3 * sizeof(void*));
    pointers[0]      = (void*)copy;
    pointers[1]      = (void*)PERL_GET_CONTEXT;
    threadid = (Uint32 *)safemalloc(sizeof(Uint32));
    *threadid        = SDL_ThreadID();
    pointers[2]      = (void*)threadid;
    a            = sv_setref_pv(ref, package, (void *)pointers);
    return a;
}

void objDESTROY(SV *bag, void (* callback)(void *object))
{
    if( sv_isobject(bag) && (SvTYPE(SvRV(bag)) == SVt_PVMG) )
    {
        void** pointers  = (void**)INT2PTR(void *, SvIV((SV *)SvRV( bag )));
        void* object     = pointers[0];
        Uint32 *threadid = (Uint32*)(pointers[2]);
        
        if(PERL_GET_CONTEXT == pointers[1]
        && *threadid == SDL_ThreadID())
        {
            pointers[0] = NULL;
            if(object)
                callback(object);
            safefree(threadid);
            safefree(pointers);
        }
    }
}

SV *_sv_ref( void *object, int p_size, int s_size, char *package )
{
    SV   *ref;
    void *copy;
    void** pointers;
    Uint32 *threadid;

    ref         = newSV( p_size );
    copy        = safemalloc( s_size );
    memcpy( copy, object, s_size );
    pointers    = safemalloc(3 * sizeof(void*));
    pointers[0] = (void*)copy;
    pointers[1] = (void*)perl;
    threadid    = (Uint32 *)safemalloc(sizeof(Uint32));
    *threadid   = SDL_ThreadID();
    pointers[2] = (void*)threadid;

    return sv_setref_pv(ref, package, (void *)pointers);
}

void _svinta_free(Sint16* av, int len_from_av_len)
{
    if( av == NULL )
        return;
    safefree( av ); /* we only need to free the malloc'd array. It is one block. */
    av = NULL;
}

Sint16* av_to_sint16 (AV* av)
{
    int len = av_len(av);
    if( len != -1)
    {
        int i;
        Sint16* table = (Sint16 *)safemalloc(sizeof(Sint16)*(len+1));
        for ( i = 0; i < len+1 ; i++ )
        { 
            SV ** temp = av_fetch(av,i,0);
            if( temp != NULL )
                table[i] = (Sint16) SvIV ( *temp  );
            else
                table[i] = 0;
        }
        return table;

    }
    return NULL;
}

void _int_range( int *val, int min, int max )
{
    if( *val < min  )
       *val = min;
    else if ( *val > max )
       *val = max;
}

#endif