////////////////////////////////////////////////////////////////////
// LPC framework
// (c) 2006 Embedded Artists AB
// (c) 2007 Peter "ph0x" Moraliyski (ppm@freemail.hu)
////////////////////////////////////////////////////////////////////

#include "../pre_emptive_os/api/osapi.h"
#include "../pre_emptive_os/api/general.h"
#include <printf_P.h>
#include <ea_init.h>
#include "lcd.h"
#include "key.h"
#include "select.h"
#include "hw.h"
#include "configAppl.h"

#include <stdlib.h>
#include <string.h>
#include "overlay.h"

///////////////////////////////////////////////////////////////////////////////

#define lpc			

#include "jtypes.h"
#include "SDL.h"

#define DW 130
#define DH 130
#define SW 82
#define SH 82

#define LEFT 4
#define RIGHT 8
#define TOP 16
#define BOTTOM 32
#define HCENTER 1
#define VCENTER 2 

u8 frontBuffer[SW*SH];
SDL_Surface _screen;
SDL_Surface *screen;
int key;

extern void keyPressed(int keyCode);
extern void keyReleased(int keyCode); 
extern void run();
extern void init();

#ifdef __cplusplus
extern "C" {
#endif 

	#define LCD_CMD_RAMWR     0x2C
	void lcdWindow1(tU8 xp, tU8 yp, tU8 xe, tU8 ye);

#ifdef __cplusplus
}
#endif 


void drawSprite(SDL_Surface* img, int x1, int y1, SDL_Surface* screen);

void _drawimage(SDL_Surface &img, int x, int y, int anc, SDL_Surface *screen) { //hack
	if (screen == NULL) return; //fix issue!
	///if (img == NULL) return;

	if (anc!=0) {
		int w= img.w;
		int h= img.h;
		if ((anc & VCENTER)!=0) y-= h>>1; else
		if ((anc & BOTTOM)!=0) y-= h;
		if ((anc & HCENTER)!=0) x-= w>>1; else
		if ((anc & RIGHT)!=0) x-= w;
	} 

	drawSprite(&img, x, y, screen); //wrk
}


bool intersect(SDL_Rect *a, SDL_Rect *b, SDL_Rect *c) {
	#define max(a,b) (a>b?(a):(b))
	#define min(a,b) (a<b?(a):(b))
	if (!(
		a->x > b->x+b->w-1 || a->x+a->w-1 < b->x ||
		a->y > b->y+b->h-1 || a->y+a->h-1 < b->y
		)) {
			c->x= max(a->x, b->x);
			c->y= max(a->y, b->y);
			c->w= min(a->x+a->w-1, b->x+b->w-1)-c->x+1;
			c->h= min(a->y+a->h-1, b->y+b->h-1)-c->y+1;

			return true;
		} else {
			c->x= 0;
			c->y= 0;
			c->w= 0;
			c->h= 0;
			
			return false;
		}
}



void _setclip(int x, int y, int w, int h, SDL_Surface *scr) {
	if (scr == NULL) return; //fix issue!	

	if (x < 0) {w+= x; x= 0;}
	if (w < 0) w= 0; 
	if (y < 0) {h+= y; y= 0;}
	if (h < 0) h= 0;
	
	scr->clip_rect.x= x;
	scr->clip_rect.y= y;
	scr->clip_rect.w= w;
	scr->clip_rect.h= h;
	
	if (scr==screen) {
		SDL_Rect r;
		r.x= 0;
		r.y= 0;
		r.w= SW;
		r.h= SH;
		intersect(&scr->clip_rect, &r, &scr->clip_rect);		
	} 
}

SDL_Surface *_createsurface(int w, int h, SDL_Surface *surf) {
	//SDL_Surface *surf= (SDL_Surface *)malloc(sizeof(SDL_Surface));  //fixme
	
	if (w==0 && h==0) {
		surf->w= SW;
		surf->h= SH;
		surf->pixels= (void*)frontBuffer;
	} else {
		surf->w= w;
		surf->h= h;
		surf->pixels= (void*)malloc(w*h*2);		
	}
	
	surf->clip_rect.x= 0;
	surf->clip_rect.y= 0;
	surf->clip_rect.w= surf->w;
	surf->clip_rect.h= surf->h;
	
	return surf;
}

Uint32 SDL_MapRGB(SDL_PixelFormat *format, Uint8 r, Uint8 g, Uint8 b) {
	r>>=4;
	g>>=4;
	b>>=4;
	return r<<4|g<<2|b; //FIXME //RGB15(r,g,b)|BIT(15);
}

void drawSprite(SDL_Surface *img, int x, int y, SDL_Surface *scr) {

	u8* src=(u8*)img->pixels;	
	u8* dst=(u8*)scr->pixels;	
	
	SDL_Rect m,c;
	
	m.x= x;
	m.y= y;
	m.w= img->w;
	m.h= img->h;

	if (!intersect(&m, &scr->clip_rect, &c)) return;
		
	int dy= scr->clip_rect.y > y ? scr->clip_rect.y - y : 0;
	int dx= scr->clip_rect.x > x ? scr->clip_rect.x - x : 0;
	src+= dy*img->w + dx;
	dst+= c.y*scr->w + c.x;
	
	/*if (c.w == SW && c.h == SH) {
		//CpuFastSet(src, dst, SW*SH*2/4);
		memcpy(dst, src, SW*SH*2); //fixme
		return;	
	} else
	if (c.w == SW && c.h == 1) {
		//CpuFastSet(src, dst, SW*2/4);
		memcpy(dst, src, SW*2); //fixme
		return;
	}*/

	{	
	int x, y;
	for (y=0; y < c.h; y+= 1) {
		for (x=0; x < c.w; x+= 1) {			
			if (*src!= 0x87)
			if (*src!= 0xe3) //fixme?
			*dst=*src;
			src+= 1;
			dst+= 1;
		}
		src+= img->w - c.w;		
		dst+= scr->w - c.w;
	}
	}	  
	
}

void _repaint() {
	int x= (DW-SW)/2;
	int y= (DH-SH)/2;
  selectLCD(TRUE);   
  lcdWindow1(x, y, x+SW-1, y+SH-1);  
  lcdWrcmd(LCD_CMD_RAMWR);    //write memory

	int i;
	for (i= 0; i<SW*SH; i++)	lcdWrdata(frontBuffer[i]);
	selectLCD(FALSE); //deselect controller
}

void _drawline(int x0, int y0, int x1, int y1, int col, SDL_Surface *screen) {	
	u8* buf= (u8*)screen->pixels; //wrk
	
	if (screen == NULL) return; //fix issue!

	//fix basic clipping
	if (x0 == x1) {
		if (y0 > SH-1) return;
		if (y1 < 0) return;
		
		if (y0 < 0) y0= 0;
		if (y1 > SH-1) y1= SH-1;		
	} else 
	if (y0 == y1) {
		if (y0 < 0 || y0 > SH-1) return;
	} else
	if (x0 < 0 || x0 > SW-1 ||
		y0 < 0 || y0 > SH-1 ||
		x1 < 0 || x1 > SW-1 ||
		y1 < 0 || y1 > SH-1) {
		return;
	}


    int dy;
    int dx;
    int stepx, stepy;

    dy = y1 - y0;
    dx = x1 - x0;

    if (dy < 0) { dy = -dy;  stepy = -SW; } else { stepy = SW; }
    if (dx < 0) { dx = -dx;  stepx = -1; } else { stepx = 1; }
    dy <<= 1;
    dx <<= 1;
		
    y0 *= SW;
    y1 *= SW;
        
    ((u8*)buf)[x0+y0] = col;     
    
    if (dx > dy) {
        int fraction = dy - (dx >> 1);
        while (x0 != x1) {
            if (fraction >= 0) {
                y0 += stepy;
                fraction -= dx;
            }
            x0 += stepx;
            fraction += dy;
				    ((u8*)buf)[x0+y0] = col; 
	        
        }
    } else {
        int fraction = dx - (dy >> 1);
        while (y0 != y1) {
            if (fraction >= 0) {
                x0 += stepx;
                fraction -= dy;
            }
            y0 += stepy;
            fraction += dx;
				    ((u8*)buf)[x0+y0] = col; 
        }
    }
	
}


SDL_Surface *IMG_Load(const void *p, SDL_Surface *s)  { //fixme
	SDL_Surface *surf= NULL;
	
					
	surf= s;//(SDL_Surface *)malloc(sizeof(SDL_Surface)); //fixme
	surf->w= (int)((unsigned char*)p)[0];
	surf->h= (int)((unsigned char*)p)[1];
	surf->pixels= (void*)((int)p+4);
	surf->clip_rect.x= 0;
	surf->clip_rect.y= 0;
	surf->clip_rect.w= surf->w;
	surf->clip_rect.h= surf->h;
	
	//printf("%s %dx%d %d\n", file, surf->w, surf->h, size);							
	return surf; 
}

//fixme
#define KEY_NUM0 9
#define KEY_NUM1 10
#define KEY_NUM2 11
#define KEY_NUM3 12
#define KEY_NUM4 13
#define KEY_NUM5 14
#define KEY_NUM6 15
#define KEY_NUM7 16
#define KEY_NUM8 17
#define KEY_NUM9 18

bool leftpressed;
bool rightpressed;
bool uppressed;
bool downpressed;
bool centerpressed;

void _processinput() {  
	int oldkey= key;
	key= checkKey();
	
	if (key != KEY_NOTHING) {
		if (key == KEY_LEFT) if (!leftpressed) {keyPressed(KEY_NUM4); leftpressed= true;}
		if (key == KEY_RIGHT) if (!rightpressed) {keyPressed(KEY_NUM6); rightpressed= true;}
		if (key == KEY_UP) if (!uppressed) {keyPressed(KEY_NUM2); uppressed= true;}
		if (key == KEY_DOWN) if (!downpressed) {keyPressed(KEY_NUM8); downpressed= true;}
		if (key == KEY_CENTER) if (!centerpressed) {keyPressed(KEY_NUM5); centerpressed= true;}
	}

	if (key != oldkey) {
		if (key != KEY_LEFT) if (leftpressed) {keyReleased(KEY_NUM4); leftpressed= false;}
		if (key != KEY_RIGHT) if (rightpressed) {keyReleased(KEY_NUM6); rightpressed= false;}
		if (key != KEY_UP) if (uppressed) {keyReleased(KEY_NUM2); uppressed= false;}
		if (key != KEY_DOWN) if (downpressed) {keyReleased(KEY_NUM8); downpressed= false;}
		if (key != KEY_CENTER) if (centerpressed) {keyReleased(KEY_NUM5); centerpressed= false;}
	}

}

extern volatile tU32 ms;
int _getticks() {
	return ms;
}

#define SIZEOF(a) (sizeof(a)/sizeof(*a))  //fixme
u8 coltab[4];
void _fillrect(int x, int y, int w, int h, int col, SDL_Surface *screen) {

	if (screen == NULL) return; //fix issue!

	u8* dst=(u8*)screen->pixels;	
	
	SDL_Rect m,c;
	
	m.x= x;
	m.y= y;
	m.w= w;
	m.h= h;
	
	if (!intersect(&m, &screen->clip_rect, &c)) return;
	
	if (col != coltab[0])
	for (int i=0; i< (int)SIZEOF(coltab); i++) coltab[i]= col;
	
	dst+= c.y*screen->w + c.x;
	for (int y=0; y < c.h; y+= 1) {
		/*int mod= c.w&3;
		int len= c.w-mod;		
		CpuFastSet(coltab, dst, len>>1|FILL); //2 x short				
		memcpy(dst+len, coltab, mod*2);
		dst+= screen->w;*/
		
		for (int x=0; x < c.w; x+= 1) *dst++= col;
		dst+= screen->w - c.w;
	}
}

void _fillArc(int x, int y, int w, int h, int af, int at, int col, SDL_Surface *screen) {
	int w2= w/2;
	int h2= h/2;
	for (int yy= -h/2; yy < h/2; yy++)
	for (int xx= -w/2; xx < w/2; xx++) {
		void _fillrect(int x, int y, int w, int h, int col, SDL_Surface *screen);
		int x3= xx+w2+x;
		int y3= yy+h2+y;
		if (x3 >= 0 && x3 < SW && y3 >= 0 && y3 < SH) //fixme clipping
		if (xx*xx+yy*yy <= w2*w2) 
			*(Uint8*)&((Uint8*)screen->pixels)[y3*SW+x3*1]= col; //4 = 32bit
			//_fillrect(x3, y3, 1, 1, col, screen);
	}
} 

void _processinputend() {
}

void _quit(int rc) {
}

void _sleep(int n) {
	//osSleep(n); //fixme
}


void _servicerepaints() {
}


/******************************************************************************
 * Typedefs and defines
 *****************************************************************************/

#define GAME_NOT_STARTED 0
#define GAME_RUNNING     1
#define GAME_OVER        2
#define GAME_END         3

static tU8 gameStatus;

/*****************************************************************************
 *
 * Description:
 *    Implements example game
 *    
 ****************************************************************************/
void playExample(void) 
{	
	lcdRect(0, 0, DW-1, DH-1, 255);
	lcdIcon((DW-_overlay[0])/2, (DH-_overlay[1])/2, _overlay[0], _overlay[1], _overlay[2], _overlay[3], &_overlay[4]);  
	osSleep(100*1);
	
	//FIXME
	//screen= _createsurface(0, 0); 	
	_createsurface(0, 0, &_screen);
	screen= &_screen;
		   
	gameStatus = GAME_RUNNING;

	init();
	run();
	while (true);

}

/******************************************************************************
 * Typedefs and defines
 *****************************************************************************/
#define PROC1_STACK_SIZE 800
#define INIT_STACK_SIZE  600


/*****************************************************************************
 * Local variables
 ****************************************************************************/
static tU8 proc1Stack[PROC1_STACK_SIZE];
static tU8 initStack[INIT_STACK_SIZE];
static tU8 pid1;

static tU8 contrast = 56;
static tU8 cursor   = 0;


/*****************************************************************************
 * Local prototypes
 ****************************************************************************/
static void proc1(void* arg);
static void initProc(void* arg);

#define MAJOR_VER 1
#define MINOR_VER 9
#define RELEASE_DATE "2006-08-07"

static void proc1(void* arg);
static void initProc(void* arg);

static void
initProc(void* arg)
{
  tU8 error;

  eaInit();
  printf("\n*********************************************************");
  printf("\n*                                                       *");
  printf("\n* Welcome to Embedded Artists' summer promotion board;  *");
  printf("\n*   'LPC2104 Color LCD Game Board with Bluetooth'       *");
  printf("\n* in cooperation with Future Electronics and Philips.   *");
  printf("\n* Boards with embedded JTAG includes J-link(tm)         *");
  printf("\n* technology from Segger.                               *");
  printf("\n*                                                       *");

  printf("\n* Program version:  %d.%d                                 *", MAJOR_VER, MINOR_VER);
  printf("\n* Program date:     %s                          *", RELEASE_DATE);

  if (TRUE == ver1_0)
    printf("\n* Hardware version: 1.0                                 *");
  else if (TRUE == ver1_1)
    printf("\n* Hardware version: 1.1                                 *");

#ifdef __IAR_SYSTEMS_ICC__
  printf("\n* Compiled with IAR Embedded Workbench                  *");
#else
  printf("\n* Compiled with GCC                                     *");
#endif

  printf("\n*                                                       *");
  printf("\n* (C) Embedded Artists AB, 2006                         *");
  printf("\n*                                                       *");
  printf("\n*********************************************************\n");
  

  osCreateProcess(proc1, proc1Stack, PROC1_STACK_SIZE, &pid1, 3, NULL, &error);
  osStartProcess(pid1, &error);  
  
  initKeyProc();

  osDeleteProcess();
}

static void proc1(void* arg) {
  //shortly bleep with the buzzer and flash with the LEDs
  tU8 i,j;

  for(i=0; i<3; i++)
  {
    for(j=0; j<3; j++)
    {
      setBuzzer(TRUE);
      setLED(LED_GREEN, FALSE);
      setLED(LED_RED,   TRUE);
      osSleep(1);

      setBuzzer(FALSE);
      setLED(LED_GREEN, TRUE);
      setLED(LED_RED,   FALSE);
      osSleep(1);
    }
    osSleep(10);
  }
  setLED(LED_GREEN, FALSE);
  setLED(LED_RED,   FALSE);

  //display startup message
  resetLCD();
  lcdInit();

#ifdef INCLUDE_STARTUP_SEQUENCE
  //displayStartupSequence();
#endif

  playExample();
	while (1) {}
}

int main() {
  tU8 error;
  tU8 pid;

  osInit();

  //immediate initilaizeation of hardware I/O pins
  immediateIoInit();
  
  osCreateProcess(initProc, initStack, INIT_STACK_SIZE, &pid, 1, NULL, &error);
  osStartProcess(pid, &error);
  
  osStart();
  return 0;
}
