#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <termios.h> /* POSIX terminal control definitions */
#include <fcntl.h>   /* File control definitions */

#include <SDL/SDL.h>
#include <SDL/SDL_gfxPrimitives.h>

void Slock(SDL_Surface *screen) ;
void Sulock(SDL_Surface *screen) ;
void DrawScene(SDL_Surface *screen, int px, int py, int mx, int my);
void Init(void);
void SendData(int fd, int x, int y) ;


SDL_Surface *screen;
int ticks;
static char ticktext[] = "|/-\\";


#define WIDTH 321
#define HEIGHT 257

#define limit(v, l, h)  ((v) > (h)) ? (h) : ((v) < (l)) ? (l) : (v)

#define ticktock() ticks=(++ticks)&7

void Slock(SDL_Surface *screen) {
  if ( SDL_MUSTLOCK(screen) ) {
    if ( SDL_LockSurface(screen) < 0 ) {
      return;
    }
  }
}

void Sulock(SDL_Surface *screen) {
  if ( SDL_MUSTLOCK(screen) ) {
    SDL_UnlockSurface(screen);
  }
}


void DrawScene(SDL_Surface *screen, int px, int py, int mx, int my) {

  char xloc[32], yloc[32];
  Sint16 x, y;
  int offset, space, lineheight;

  
  offset = 4;
  space = 4; 
  lineheight = 8;
  
  x = px; y = py;

  Slock(screen);
  
  rectangleRGBA (screen, 0, 0, 256, 256, 250, 250, 250, 255 ); // navigation box
  rectangleRGBA (screen, 257, 0, 320, 256, 255, 10, 10, 255 ); // data box
     
  //boxRGBA   (screen, x,   y,   x+(strlen(string)*8), y+8, 0, 255, 0, 255); // background colour   
   
  stringRGBA(screen, 257, offset+0*(space+lineheight), " ttyS0 ",     0, 0, 255, 255); // foregroud colour
  stringRGBA(screen, 257, offset+1*(space+lineheight), " 4800N81",     0, 0, 255, 255); // foregroud colour
  
   //-- drive vector
  sprintf((char*)&xloc, " X:%0.3d", x);
  stringRGBA(screen, 257, offset+2*(space+lineheight), xloc, 0, 0, 255, 255); // foregroud colour
  
  sprintf((char*)&yloc, " Y:%0.3d", y);
  stringRGBA(screen, 257, offset+3*(space+lineheight), yloc, 0, 0, 255, 255); // foregroud colour
  
  
  //-- centered drive vector
  sprintf((char*)&xloc, " Xo:%0.3d", x-128);
  stringRGBA(screen, 257, offset+4*(space+lineheight), xloc, 0, 0, 255, 255); // foregroud colour
  
  sprintf((char*)&yloc, " Yo:%0.3d", y-128);
  stringRGBA(screen, 257, offset+5*(space+lineheight), yloc, 0, 0, 255, 255); // foregroud colour
  
  
  //-- mouse vector
  sprintf((char*)&xloc, " MX:%0.3d", mx);
  stringRGBA(screen, 257, offset+6*(space+lineheight), xloc, 0, 0, 255, 255); // foregroud colour
  
  sprintf((char*)&yloc, " MY:%0.3d", my);
  stringRGBA(screen, 257, offset+7*(space+lineheight), yloc, 0, 0, 255, 255); // foregroud colour  
  
  
  //-- mouse vector cetered
  sprintf((char*)&xloc, " Mx:%0.3d", mx-128);
  stringRGBA(screen, 257, offset+8*(space+lineheight), xloc, 0, 0, 255, 255); // foregroud colour
  
  sprintf((char*)&yloc, " My:%0.3d", my-128);
  stringRGBA(screen, 257, offset+9*(space+lineheight), yloc, 0, 0, 255, 255); // foregroud colour  
  
  sprintf((char*)&yloc, "   %c", ticktext[ticks/2]);
  stringRGBA(screen, 257, offset+11*(space+lineheight), yloc, 0, 0, 255, 255); // foregroud colour 
  
  /*
  for (x = 0; x <= 128; x+=16) {
   circleRGBA (screen, 128, 128, x-1,  ((255-x)*2)-1, (x*2)-1, 0, 255 );
  }
  */
  
  // drive cross hair
  lineRGBA (screen, px-10, py,    px+10, py,    0, 0, 255, 255 );
  lineRGBA (screen, px,    py-10, px,    py+10, 0, 0, 255, 255 );
  
  Sulock(screen);
  SDL_Flip(screen);
  
}



int main(int argc, char *argv[]) {

  int done;
  SDL_Rect foo ={0, 0, WIDTH, HEIGHT};
  int dx, dy;
  int mx, my;
  int track;
  int serialPort;
  
  SDL_Event event;

  Init();
  serialPort = InitSerial();
  
  dx = dy = 128;
  mx = my = 0;
  track = 0;
  
  done = 0;
  
  while(done == 0) {   
    while ( SDL_PollEvent(&event) ) {
    
      if ( event.type == SDL_QUIT )  {  done = 1;  }
 
      if ( event.type == SDL_MOUSEBUTTONDOWN )  {  
        track = 1;
      }
      
      if ( event.type == SDL_MOUSEBUTTONUP )  {  
        track = 0;
      }

      if ( event.type == SDL_KEYDOWN ) {
        if ( event.key.keysym.sym == SDLK_ESCAPE ) { done = 1; }              
      }
      
      SDL_GetMouseState(&mx, &my);
      
      if (track) { dx = limit(mx, 0, 255); dy = limit(my, 0, 255); }
                     
    }
    SDL_FillRect(screen, &foo , 0);
    DrawScene(screen, dx, dy, limit(mx, 0, 255), limit(my, 0, 255));  
      
    ticktock(); 
    SendData(serialPort, dx, dy);
    fflush(stdout);
    
    // limit refresh to 50Hz, for serial xmitt
    usleep(20000); // stop the program from pulling 100% CPU. This is basically an entry point for the scheduler
 }

  return 0;
}


void Init(void) {

  if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
    printf("Unable to init SDL: %s\n", SDL_GetError());
    exit(1);
  }
  atexit(SDL_Quit);

  
  screen=SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_HWSURFACE|SDL_DOUBLEBUF);
  
  if ( screen == NULL ) {
    printf("Unable to set 256x256 video: %s\n", SDL_GetError());
    exit(1);
  }
  
  //turn off cursor...
  //SDL_ShowCursor(0);
}


void SendData(int fd, int x, int y) {
  char data[16];
// printf("PX%02XPY%02X", x, y);
   sprintf(data, "PX%02XPY%02X", x, y);
   write(fd, data, strlen(data));  
}

int InitSerial() {

  int fd; /* File descriptor for the port */
  struct termios options;
  
  
  if ((fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY)) != -1) {
  
    tcgetattr(fd, &options);
    cfsetispeed(&options, B4800);
    cfsetospeed(&options, B4800);

    options.c_cflag |= (CLOCAL | CREAD);

    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;
    
    tcsetattr(fd, TCSANOW, &options);
  }  else {
    printf("Unable to open ttyS0\n");
    exit(1);
  }
    
  return fd;  
    
}












