
/* http://sdldoc.csn.ul.ie/ */
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/timeb.h>

#include <unistd.h> // pour usleep

#include <pthread.h>
#include <semaphore.h>

#include "SDL.h"

int ScreenWidth;
int ScreenHeight;

Uint32  NextScreen[500][500];
Uint32  NextScreenCpy;

char bufLog[999];
Uint32 time0;
Uint32 nbTicks;

sem_t SemSdlDelay;
sem_t waitSetVideoMode;


SDL_Event   EventList[NBMAXEVT];
int posReadEventList;
int posWritEventList;

int SDL_Init(Uint32 flags)
{
    struct TIMEB timebuffer;

    sem_init(&SemSdlDelay,0,0);

    VDRGNGBLOG("inTest : SDL_Init()\n");

    ftime( &timebuffer );

    time0 = timebuffer.millitm + timebuffer.time * 1000;
    nbTicks = 0;

    posReadEventList=0;
    posWritEventList=0;

    return(1);
}

void SDL_KillThread(SDL_Thread *thread)
{
    VDRGNGBLOG("TODO : SDL_KillThread()\n");
//    pthread_cancel(thread);
}

void SDL_Delay(Uint32 ms)
{
    usleep(ms*1000);
//    VDRGNGBLOG("TODO : SDL_Delay()\n");
}

// Sets a portion of the colormap for the given 8-bit surface.
int SDL_SetColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors)
{
    int i;

    surface->format->palette = (SDL_Palette *) malloc( sizeof(SDL_Palette) );

    surface->format->palette->ncolors = ncolors;
    surface->format->palette->colors = (SDL_Color *)malloc( sizeof(SDL_Color)*ncolors );

    for(i=0;i<ncolors;i++)
    {
        surface->format->palette->colors[i].b = colors[i].b;
        surface->format->palette->colors[i].g = colors[i].g;
        surface->format->palette->colors[i].r = colors[i].r;
        surface->format->palette->colors[i].unused = colors[i].unused;
    }

    VDRGNGBLOG("TODO : SDL_SetColors()\n");

    return(0);
}

int SDL_SetColorKey(SDL_Surface *surface, Uint32 flag, Uint32 key)
{
    VDRGNGBLOG("TODO : SDL_SetColorKey()\n");

    return(0);
}
    /* --- Audio --- */

int SDL_OpenAudio(SDL_AudioSpec *a,int b)
{
    VDRGNGBLOG("TODO : SDL_OpenAudio()\n");
	return(0);
}
void SDL_CloseAudio(void)
{
    VDRGNGBLOG("TODO : SDL_CloseAudio()\n");
}

void SDL_LockAudio(void)
{
    VDRGNGBLOG("TODO : SDL_LockAudio()\n");
}
void SDL_UnlockAudio(void)
{
    VDRGNGBLOG("TODO : SDL_UnlockAudio()\n");
}
void SDL_PauseAudio(int a)
{
    VDRGNGBLOG("TODO : SDL_PauseAudio()\n");
}
void SDL_InitSubSystem(int a)
{
    VDRGNGBLOG("TODO : SDL_InitSubSystem()\n");
}
void SDL_QuitSubSystem(int a)
{
    VDRGNGBLOG("TODO : SDL_QuitSubSystem()\n");
}


    /* --- Graphics --- */
void SetMask(Uint32 *mask,Uint8 *shift,Uint8*loss,Uint32 theMask)
{
    Uint8 sft = 0;
    Uint8 ls = 0;

    *mask = theMask;

    while( sft < 16 && ((theMask&1)==0) )
    {
        theMask >>= 1;
        sft++;
    }

    while( ls < 16 && ((theMask&0x80)==0) )
    {
        theMask <<= 1;
        ls++;
    }

    *loss = ls;
    *shift =sft;
}

SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
{
    SDL_Surface *newSurf;

    char buf[999];

    newSurf = (SDL_Surface *)malloc( sizeof(SDL_Surface) );
    if( newSurf != NULL )
    {
        newSurf->format = (SDL_PixelFormat*)malloc( sizeof(SDL_PixelFormat) );
        newSurf->format->BitsPerPixel = depth;
        SetMask(&newSurf->format->Bmask,&newSurf->format->Bshift,&newSurf->format->Bloss,Bmask);
        SetMask(&newSurf->format->Gmask,&newSurf->format->Gshift,&newSurf->format->Gloss,Gmask);
        SetMask(&newSurf->format->Rmask,&newSurf->format->Rshift,&newSurf->format->Rloss,Rmask);
        SetMask(&newSurf->format->Amask,&newSurf->format->Ashift,&newSurf->format->Aloss,Amask);
        newSurf->h = height;
        newSurf->w = width;
        newSurf->pitch = newSurf->pitch = width * (depth/8);

        newSurf->pixels = (long*)malloc( sizeof(long) * (width * height) );
    }

    sprintf(buf,"inTest : SDL_CreateRGBSurface(w:%d,h:%d,d:%d) : %x pxl:%x\n",width,height,depth,newSurf,newSurf->pixels);
    VDRGNGBLOG(buf);

    return(newSurf);

}

// Creates an SDL_Surface from the provided pixel data.
// 'depth,' just like in SDL_CreateRGBSurface(), is in bits per pixel
// 'pitch' is the length of each scanline in bytes
SDL_Surface *SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
{
    SDL_Surface *newSurf;
    char buf[999];

    newSurf = (SDL_Surface*) malloc( sizeof(SDL_Surface) );
    if( newSurf != NULL )
    {
        newSurf->format = (SDL_PixelFormat*)malloc( sizeof(SDL_PixelFormat) );
        newSurf->pixels = (long*)pixels;
        newSurf->pitch = pitch;
        newSurf->h = height;
        newSurf->w = width;
        newSurf->format->BitsPerPixel = depth;
        SetMask(&newSurf->format->Bmask,&newSurf->format->Bshift,&newSurf->format->Bloss,Bmask);
        SetMask(&newSurf->format->Gmask,&newSurf->format->Gshift,&newSurf->format->Gloss,Gmask);
        SetMask(&newSurf->format->Rmask,&newSurf->format->Rshift,&newSurf->format->Rloss,Rmask);
        SetMask(&newSurf->format->Amask,&newSurf->format->Ashift,&newSurf->format->Aloss,Amask);

    }

    sprintf(buf,"inTest : SDL_CreateRGBSurfaceFrom(w:%d,h:%d,d:%d) : %x pxl:%x\n",width,height,depth,newSurf,newSurf->pixels);
    VDRGNGBLOG(buf);

    return(newSurf);
}

// SDL_SetVideoMode -- Set up a video mode with the specified width, height and bits-per-pixel.
SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags)
{
    SDL_Surface *newSurf;

    char buf[999];
    int msk;

    ScreenWidth = width;
    ScreenHeight = height;

    sem_post(&waitSetVideoMode);

    newSurf = (SDL_Surface*)malloc( sizeof(SDL_Surface) );
    if( newSurf != NULL )
    {
        newSurf->format = (SDL_PixelFormat*) malloc( sizeof(SDL_PixelFormat) );
        newSurf->format->BitsPerPixel = bpp;
        newSurf->h = height;
        newSurf->w = width;
        newSurf->pitch = width * (bpp/8);

        msk = (1<<(bpp/3))-1;
        msk = 0x1f;
        SetMask(&newSurf->format->Bmask,&newSurf->format->Bshift,&newSurf->format->Bloss,msk);
        msk <<= (bpp/3);
        msk= 0x7e0;
        SetMask(&newSurf->format->Gmask,&newSurf->format->Gshift,&newSurf->format->Gloss,msk);
        msk <<= (bpp/3);
        msk= 0xf800;
        SetMask(&newSurf->format->Rmask,&newSurf->format->Rshift,&newSurf->format->Rloss,msk);
//        SetMask(&newSurf->format->Amask,&newSurf->format->Ashift,(1<<(bpp/4))-1);
        SetMask(&newSurf->format->Amask,&newSurf->format->Ashift,&newSurf->format->Aloss,0);

        newSurf->pixels = (long*)malloc( sizeof(long) * (width * height) );
    }

    sprintf(buf,"inTest : SDL_SetVideoMode(w:%d,h:%d,d:%d) : %x pxl:%x\n",width,height,bpp,newSurf,newSurf->pixels);
    VDRGNGBLOG(buf);

    return(newSurf);
}



int SDL_SetAlpha(SDL_Surface *surface, Uint32 flag, Uint8 alpha)
{
    VDRGNGBLOG("TODO : SDL_SetAlpha()\n");
    return(0);
}

void SDL_SetClipRect(SDL_Surface *surface, SDL_Rect *rect)
{
    VDRGNGBLOG("TODO : SDL_SetClipRect()\n");
}



SDL_Surface *SDL_LoadBMP(char *filename)
{
    VDRGNGBLOG("TODO : SDL_LoadBMP()\n");
    return(0);
}

int SDL_SaveBMP(SDL_Surface *s,char *c)
{
    VDRGNGBLOG("TODO : SDL_SaveBMP()\n");
    return(0);
}

void SDL_FreeSurface(SDL_Surface *s)
{
    VDRGNGBLOG("TODO : SDL_FreeSurface()\n");
}

int SDL_ShowCursor(int toggle)
{
    VDRGNGBLOG("TODO : SDL_ShowCursor()\n");
    return(0);
}

// SDL_BlitSurface -- This performs a fast blit from the source surface to the destination surface.
//SDL_BlitSurface()  qui nous permet de copier une partie d'une SDL_Surface  identifiée par une SDL_Rect
//  sur une autre SDL_Surface  identifiée par une autre SDL_Rect
//  - The width and height in srcrect determine the size of the copied rectangle.
//  - Only the position is used in the dstrect (the width and height are ignored).
//  If srcrect is NULL, the entire surface is copied.
//  If dstrect is NULL, then the destination position (upper left corner) is (0, 0).
int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect)
{
    int srcX,srcY,srcW,srcH;
    int dstX,dstY;
    int x,y;
    int idxPal;
    long c;
    Uint8 *pix8b;
    long *pxls,*pxld;

    srcX = 0;
    srcY = 0;
    srcW = src->w;
    srcH = src->h;
    if( srcrect != NULL )
    {
        srcX = srcrect->x;
        srcY = srcrect->y;
        srcW = srcrect->w;
        srcH = srcrect->h;
    }

    dstX = 0;
    dstY = 0;
    if( dstrect != NULL )
    {
        dstX = dstrect->x;
        dstY = dstrect->y;
    }

    if( src->format->BitsPerPixel == dst->format->BitsPerPixel )
    {
    	pxls = (long *)src->pixels;
    	pxld = (long *)dst->pixels;

        for(y=0;y<srcH;y++)
        {
            for(x=0;x<srcW;x++)
            {
            	pxld[ dstX+x + (dstY+y)*dst->w ] = pxls[ (srcX+x) + (srcY+y)*srcW ];
            }
        }
    }
    else
    {
        if( src->format->BitsPerPixel != dst->format->BitsPerPixel )
        {
            if( dst->format->BitsPerPixel == 16 )
            {

                pix8b = (Uint8*)src->pixels;

//                {
//                    FILE *f;
//                    f = fopen("tst.dat","wt");
//                    for(y=0;y<src->h;y++)
//                    {
//                        for(x=0;x<src->w;x++)
//                        {
//                            c = pix8b[ x + (y*src->w) ];
//                            if( c == 0 )
//                                fprintf(f," ",c);
//                            else
//                                fprintf(f,"*",c);
//                        }
//                        fprintf(f,"\n");
//                    }
//                    fclose(f);
//                }

				pxld = (long *) dst->pixels;

                for(y=0;y<srcH;y++)
                {
                    for(x=0;x<srcW;x++)
                    {
                        idxPal = pix8b[ (srcX+x) + (srcY+y)*src->w ];

                        c = src->format->palette->colors[ idxPal ].r;
                        c <<= 8;
                        c |= src->format->palette->colors[ idxPal ].g;
                        c <<= 8;
                        c |= src->format->palette->colors[ idxPal ].b;

                        pxld[ dstX+x + (dstY+y)*dst->w ] = c;
                    }
                }
            }
            else
            {
                if( dst->format->BitsPerPixel == 16 )
                {
                    dst->format->BitsPerPixel += 0;
                }

            }
        }
    }


//    sprintf(bufLog,"inTest : SDL_BlitSurface() s:%x -> s:%x\n",src,dst);    VDRGNGBLOG(bufLog);

    return(0);
}

// SDL_FillRect -- This function performs a fast fill of the given rectangle with some color
int SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color)
{
    int x,y;
    int dx,dy;
    int sx,sy;
   	long *pxld;

    // full all surface
    dx = 0;
    dy = 0;
    sx = dst->w;
    sy = dst->h;

    if( dstrect != NULL )
    {
        dx = dstrect->x;
        dy = dstrect->y;
        sx = dstrect->w;
        sy = dstrect->h;

    }

	pxld = (long *)dst->pixels;
    for(y=dy;y<dy+sy;y++)
    {
        for(x=dx;x<dx+sx;x++)
        {
            pxld[ x + y*dst->w ] = color;
        }
    }

//    sprintf(bufLog,"inTest : SDL_FillRect() s:%x pxl:%x\n",dst,dst->pixels);    VDRGNGBLOG(bufLog);
    return(0);
}

int SDL_LockSurface(SDL_Surface *surface)
{
    VDRGNGBLOG("TODO : SDL_LockSurface()\n");
    return(0);
}
void SDL_UnlockSurface(SDL_Surface *surface)
{
    VDRGNGBLOG("TODO : SDL_UnlockSurface()\n");
}

SDL_Overlay *SDL_CreateYUVOverlay(int width, int height, Uint32 format, SDL_Surface *display)
{
    VDRGNGBLOG("TODO : SDL_CreateYUVOverlay()\n");
    return(0);
}

int SDL_DisplayYUVOverlay(SDL_Overlay *overlay, SDL_Rect *dstrect)
{
    VDRGNGBLOG("TODO : SDL_DisplayYUVOverlay()\n");
    return(0);
}

Uint8 GetRed(SDL_Surface *screen,long pxl)
{
    unsigned int c;

    c = (pxl & screen->format->Rmask) >> screen->format->Rshift;
    c <<= screen->format->Rloss;

    return(c);
}

Uint8 GetBlue(SDL_Surface *screen,long pxl)
{
    int c;

    c = (pxl & screen->format->Bmask) >> screen->format->Bshift;
    c <<= screen->format->Bloss;

    return(c);
}

Uint8 GetGreen(SDL_Surface *screen,long pxl)
{
    int c;

    c = (pxl & screen->format->Gmask) >> screen->format->Gshift;
    c <<= screen->format->Gloss;

    return(c);
}

Uint8 GetAlpha(SDL_Surface *screen,long pxl)
{
    int c;

    c = (pxl  & screen->format->Amask) >> screen->format->Ashift;
    c <<= screen->format->Aloss;

    return(c);
}

// SDL_Flip -- Swaps screen buffers
// This function returns 0 if successful, or -1 if there was an error.
int SDL_Flip(SDL_Surface *screen)
{
    int x,y;
    int r,g,b,a;
    long colScreen;
    long *pxl;

//   sprintf(bufLog,"inTest : SDL_Flip() : %x\n",screen);    VDRGNGBLOG(bufLog);
    // recopie vers l'ecran

   if( NextScreenCpy == 0 )
   {
        pxl = (long * )screen->pixels;

        for(y=0;y<screen->h;y++)
        {
            for(x=0;x<screen->w;x++)
            {
                r = GetRed(  screen,pxl[x+y*screen->w]);
                b = GetBlue( screen,pxl[x+y*screen->w]);
                g = GetGreen(screen,pxl[x+y*screen->w]);
                a = GetAlpha(screen,pxl[x+y*screen->w]);

                //AARRGGBB

                colScreen = a;   colScreen <<= 8;
                colScreen |= r;  colScreen <<= 8;
                colScreen |= g;  colScreen <<= 8;
                colScreen |= b;

                NextScreen[x][y] = colScreen;
            }
        }
   }

    return(0);
}




void SDL_WM_SetCaption(const char *title, const char *icon)
{
    VDRGNGBLOG("TODO : SDL_WM_SetCaption()\n");
}
int SDL_WM_ToggleFullScreen(SDL_Surface *surface)
{
    VDRGNGBLOG("TODO : SDL_WM_ToggleFullScreen()\n");
    return(0);
}
    /* --- Events --- */

// SDL_GetTicks -- Get the number of milliseconds since the SDL library initialization.
Uint32 SDL_GetTicks(void)
{
   Uint32 t;
   struct TIMEB timebuffer;
   ftime( &timebuffer );

   t = timebuffer.millitm + timebuffer.time * 1000;
   t -= time0;

//   sprintf(bufLog,"inTest : SDL_GetTicks() : %ld\n",t);    VDRGNGBLOG(bufLog);


    /*
	Frames++;
	if(SDL_GetTicks() >= Ticks + 1000)
	{
		sprintf(FPS, "%d fps", Frames);
		Frames = 0;
		Ticks = SDL_GetTicks();
	}
    */
   return(t);
}
char *SDL_GetError(void)
{
    VDRGNGBLOG("TODO : SDL_GetError()\n");
    return(NULL);
}

int SDL_WaitEvent(SDL_Event *event)
{
    VDRGNGBLOG("TODO : SDL_WaitEvent()\n");
    return(0);
}


// Polls for currently pending events, and returns 1 if there are any pending events, or 0 if there are none available.
// If event is not NULL, the next event is removed from the queue and stored in that area.
int SDL_PollEvent(SDL_Event *evt)
{
    int nbevt = 0;
    //    VDRGNGBLOG("TODO : SDL_PollEvent()\n");

    if( posReadEventList != posWritEventList )
    {
        evt->type = EventList[ posReadEventList ].type;
        evt->key.keysym.sym = EventList[ posReadEventList ].key.keysym.sym;

//    sprintf(bufLog,"event : %d %d \n", evt->type,evt->key.keysym.sym);    VDRGNGBLOG(bufLog);

        posReadEventList++;
        if(posReadEventList>=NBMAXEVT)
            posReadEventList= 0;

        nbevt = 1;
    }

	return(nbevt);
}

int SDL_NumJoysticks(void)
{
	//
	return(0);
}

SDL_Joystick* SDL_JoystickOpen(int joy)
{


	//
	return(0);
}

char *SDL_JoystickName(int joy)
{
	//
	return(0);
}

int SDL_JoystickNumAxes(SDL_Joystick *sdljoy)
{
	//
	return(0);
}

int SDL_JoystickNumButtons(SDL_Joystick *sdljoy)
{
	//
	return(0);
}

int SDL_JoystickNumBalls(SDL_Joystick *sdljoy)
{
	//
	return(0);
}


void fcntl(int a,int b)
{
}



