#include <iostream>
#include <unistd.h>
#include <SDL.h>
#include <math.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "sdlcommon.h"
#include "car.h"
#include "shmdata.h"

using namespace std;

Car::Car()
	{
	initShm();
	reset();
	showbar=1;
	angstep=5;
	for(int i=0;i<CAMVECT;i++) camera[i]=0;
	carimage=0;
	for(int i=0;i<TRAINEESIZE;i++) { trainee[i][0]=0; trainee[i][1]=0; }
	traineepos=0;
	traineesize=1;
	}

void Car::loadImage(char *imagefile)
	{
	SDL_Surface *voitsurf;
	Uint32 cur=SDL_GetTicks();
	voitsurf=SDL_LoadBMP(imagefile);
	printf("Precaching Surfaces ..... \n");
	for(int i=0;i<360;i++) 
		{
		Surface_car[i]=SDL_CreateRGBSurface(SDL_HWSURFACE, voitsurf->w, voitsurf->h, 32, 0,0,0,0);
		if(SDL_SetColorKey(Surface_car[i], SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(Surface_car[i]->format, 255,0,255)) == -1)
			fprintf(stderr, "Warning: colorkey will not be used, reason: %s\n", SDL_GetError());
		rotatesurface(voitsurf,Surface_car[i],i);
		}
	carimage=1;
	printf("Done ... (%d ms)\n",SDL_GetTicks()-cur);
	}

void Car::updateCar(SDL_Surface* screen)
	{
			int i;
			for(i=0;(SData->read!=0) && i<200;i++) usleep(5); // on attends 1 seconde 
			if(i==200) 
				{
				cout << "AutoPilot Timed Out ...";
				exit(0);
				}
	if(SData->Res[0]) decAngle();
	if(SData->Res[1]) incAngle();
	SData->Res[0]=0;
	SData->Res[1]=0;
	SData->pos_x+=getSpeed()*(cos(SData->angle*PI/180));
	SData->pos_y+=getSpeed()*(sin(SData->angle*PI/180));
	showTrainee(screen);
	showCamera(screen);	/* obligé pour avoir les pixels :-) */
	// CAMERASIZE // CAMERASTEP
	if(carimage)			/* on blit la voiture */
		{
		SDL_Rect r;
		r.w=Surface_car[SData->angle]->w;
		r.h=Surface_car[SData->angle]->h;
		r.x=(int)SData->pos_x-(r.w/2);
		r.y=(int)SData->pos_y-(r.h/2);
		SDL_BlitSurface( Surface_car[SData->angle], NULL, screen, &r);
		}
	else for(int i=0;i<20;i++)	/* affichage de la voiture simplifiée (ligne rouge) */
		{
		setpixel(screen,(int)(SData->pos_x-(cos(SData->angle*PI/180)*i)),(int)(	SData->pos_y-(sin(SData->angle*PI/180)*i)),255,0,0);
		}
	for(int i=0;i<CAMVECT;i++) 
		{
	//	cout << camera[i];
		SData->V[i]=camera[i];
		}
	SData->read=1;			/* on a lu :D */
	//cout << endl;
	}
	
void Car::showTrainee(SDL_Surface* screen)
	{
	int k;
	trainee[traineepos][0]=(int)SData->pos_x;
	trainee[traineepos][1]=(int)SData->pos_y;
	traineepos=(traineepos+1)%traineesize;
	k=traineepos;
	k=(k+1)%traineesize;
	for(int i=0; /*i < traineesize &&*/ k!=traineepos;i++) /* affichage de la trainée */
		{
		//setpixel(screen,trainee[k][0],trainee[k][1],0,(int)(i*(256.0/traineesize))%256,255);
		int x0,y0,x1,y1;
		x0=trainee[(k+traineesize-1)%traineesize][0];
		y0=trainee[(k+traineesize-1)%traineesize][1];
		x1=trainee[k][0];
		y1=trainee[k][1];
		if(x0==0) x0=x1;
		if(y0==0) y0=y1;
		if(x1==0) x1=x0;
		if(y1==0) y1=y0;
		DrawLine(screen,x0,y0,x1,y1,0,0,255);
		k=(k+1)%traineesize;
		}
	
	}

void Car::showCamera(SDL_Surface* screen)
	{
	double x,y;
	int k,ang;
	x=SData->pos_x + ( cos(SData->angle*PI/180) * CAMERADISTANCE );
	y=SData->pos_y + ( sin(SData->angle*PI/180) * CAMERADISTANCE );
	ang=(SData->angle+90)%360;
	x-=CAMERASIZE/2*cos(ang*PI/180);
	y-=CAMERASIZE/2*sin(ang*PI/180);
	k=0;
	for(int i=0;i<CAMERASIZE;i++)
		{
		x+=cos(ang*PI/180);
		y+=sin(ang*PI/180);
		if(!(i%CAMERASTEP))
			{
			camera[k]=1;
			if(inCarArea(screen,(int)x,(int)y)) //if(x>0 && x<screen->w && y>0 && y<screen->h)
				camera[k]=(((getpixel(screen,(int)x,(int)y))%2)+1)%2;
			else	camera[k]=0;
			
			if(camera[k] && showbar)
				{
				setpixel(screen, (int)x, (int)y,255,0,0);
				//setpixel(screen, (int)x, (int)y-1,255,0,0);
				//setpixel(screen, (int)x-1, (int)y,255,0,0);
				//setpixel(screen, (int)x-1, (int)y-1,255,0,0);
				}
			else if(showbar)
				{
				setpixel(screen, (int)x, (int)y,0,255,0);
				//setpixel(screen, (int)x, (int)y-1,0,255,0);
				//setpixel(screen, (int)x-1, (int)y,0,255,0);
				//setpixel(screen, (int)x-1, (int)y-1,0,255,0);
				}
			k++;
			}
		else 
			{
			if(showbar) setpixel(screen, (int)x, (int)y,0,0,255);
			}
		}
	}

void Car::incAngle()
	{
	SData->angle=(SData->angle+angstep)%360;
	}
void Car::decAngle()
	{
	SData->angle=(SData->angle+360-angstep)%360;
	}
int Car::incAngleStep(int i)
	{
	angstep+=i;
	return angstep;
	}
void Car::incSpeed()
	{
	if(SData->Res[2]==0)
		{
		SData->Res[0]=0;
		SData->Res[1]=0;
		SData->Res[2]=1;
		if(SData->speed==0) SData->speed=1;
		}
	SData->speed++;
	}
void Car::decSpeed()
	{
	SData->speed--;
	}
bool Car::APToggle()
	{
	SData->APon=(SData->APon+1)%2;
	return SData->APon;
	}
	
bool Car::APState() const
	{
	return SData->APon;
	}
bool Car::neurToggle()
	{
	SData->Neuron=(SData->Neuron+1)%2;
	return SData->Neuron;
	}
	
bool Car::neurState() const
	{
	return SData->Neuron;
	}
void Car::initShm()
	{
	if ((shmid = shmget(SHMKEY, sizeof(struct shmdata), 0666)) < 0) 
		{
		perror("shmget");
		exit(1);
		}
	if (( SData = (struct shmdata *)shmat(shmid, NULL, 0)) == (struct shmdata *) -1) 
		{
		perror("shmat");
		exit(1);
		}
	}
int  Car::getSpeed() const
	{
	if(SData->Res[2])
		return SData->speed;
	return 0;
	}
int  Car::getAngle() const
	{
	return SData->angle;
	}
bool Car::showBar(int i)
	{
	showbar=(showbar+i)%2;
	return showbar;
	}
bool* Car::getVect()
	{
	return SData->Res;
	}
bool* Car::getView()
	{
	return SData->V;
	}
void Car::reset()
	{
	SData->pos_x=200;
	SData->pos_y=200;
	SData->speed=1;
	SData->angle=0;
	SData->Res[2]=1;
	}
void Car::turn180()
	{
	SData->angle=(SData->angle+180)%360;
	}
int Car::incTraineeSize(int s)
	{
	int i,k;
	if(s==0) return traineesize;
	if(traineesize==1 && s<0) return traineesize;
	if(traineesize+s > TRAINEESIZE) s=TRAINEESIZE-traineesize-1;
	if(traineesize+s < 0) 		s=1-TRAINEESIZE;
	int tmp[traineesize+s][2];
	k=traineepos;
	if(s<0) k=(traineesize+traineepos-s)%traineesize;
	for(i=0;i<(traineesize+s);i++)
		{
		if(i>traineesize)
			{
			tmp[i][0]=0;
			tmp[i][1]=0;
			}
		else
			{
			tmp[i][0]=trainee[k][0];
			tmp[i][1]=trainee[k][1];
			}
		k=(k+1)%traineesize;
		}
	for(i=0;i<traineesize+s;i++)
		{
		trainee[i][0]=tmp[i][0];
		trainee[i][1]=tmp[i][1];
		}
	traineepos=traineesize-1;
	// if(traineesize<1) { traineesize=1;  traineepos=0; }
	if(s<0)traineepos=0;
	traineesize+=s;
	return traineesize;
	}
void Car::setDelay(int del)
	{
	SData->delay=del;
	}
void Car::harakiri()
	{
	cout << " EXIT INTERFACE ...\n";
	SData->read=666;
	usleep(100);
	SData->read=666;
	usleep(100);
	SData->read=666;
	}
void Car::saveState()
	{
	SData->action=SAVE_STATE;
	}
void Car::loadState()
	{
	SData->action=RELOAD_STATE;
	}
void Car::showNetwork(bool a)
	{
	SData->viewNetwork=a;
	}
bool Car::showNetworkState()
	{
	return SData->viewNetwork;
	}
