/*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*+                                                   +*/
/*+ This program is free software; you can redistri-  +*/
/*+ bute it and/or modify it under the terms of the   +*/
/*+ GNU General Public License as published by the    +*/
/*+ Free Software Foundation; either version 2 of the +*/
/*+ License, or (at your option) any later version.   +*/
/*+ This program is distributed in the hope that it   +*/
/*+ will be useful, but WITHOUT ANY WARRANTY; without +*/
/*+ even the implied warranty of MERCHANTABILITY or   +*/
/*+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU     +*/
/*+ General Public License                            +*/
/*+ (http://www.fsf.org/copyleft/gpl.html)            +*/
/*+ for more details.                                 +*/
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*+ J. Anders, TU Chemnitz,                           +*/
/*+         ja@informatik.tu-chemnitz.de              +*/
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/********************************************************/
/*							*/
/*		      "ameise.c"			*/
/*							*/
/*   Implementierung des Verhaltens der "Ameise".	*/
/*							*/
/********************************************************/

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>		/* FILE, fprintf(), ...	*/
#include "pngencode.h"		/* PNG-Coder		*/	
#include "ameise.h"		/* gemeinsame Typen 	*/

#define MINSCHRITTZAHL 10       /* minimal und maximal  */
#define MAXSCHRITTZAHL 10000000 /* zul. Schrittzahl     */
#define PNGFILE "bild.png"      /* So heisst die Ausgabe*/


#ifndef MIT_X11
struct f_str {		/* Ein Element der Farbtabelle	*/
	unsigned red, green, blue;
}; 
#endif

static struct status_str status;

	
/* Mit der Farbtabelle kann experimeniert werden. Es	*/
/* muss lediglich darauf geachtet werden, dass das	*/
/* Makro "MAXFARBEN" gegebenenfalls korrigiert wird.	*/
/* Ausserdem sollte die Farbe mit dem Index "0" die	*/
/* Farbe "schwarz" sein.				*/

static struct f_str ftab[MAXFARBEN] = { /* Farbtabelle	*/
			 {0x00, 0x00, 0x00}, /* schwarz */
			 {0xff, 0x00, 0xff},
			 {0xff, 0x00, 0x00},
			 {0xff, 0xff, 0x00},
			 {0x00, 0xff, 0x00},
			 {0x00, 0x00, 0xff},
			 {0x00, 0xff, 0xff},
			 {0x00, 0x22, 0x70},
			 {0x22, 0x00, 0x88},
			 {0x44, 0x55, 0x66},
			 {0x44, 0x50, 0x20},
			 {0xe4, 0x36, 0x82},
			 {0xa0, 0x90, 0x60},
			 {0x72, 0x77, 0x00},
			 {0x00, 0x55, 0xee},
			 {0x78, 0x40, 0x30},
			 {0x67, 0x82, 0x90},
			 {0x44, 0x66, 0xff},
			 {0x66, 0x44, 0x99},
			 {0x66, 0x99, 0xaa},
};


static struct status_str status;

/* Die Funktion "GetPixel( x, y )" ermittelt den Index 	*/
/* der Farbe an der Position (x, y). Die tatsaechliche	*/
/* Auspraegung der Farbe kann der Farbtabelle "ftab"	*/
/* entnommen werden. 					*/
/* Da die "Punkte" in Wahrheit Rechtecke der Kanten-	*/
/* laenge "PUNKBREIT" sind, muss durch Integer-Division	*/
/* eine Anpassung der Darstellungsgroesse an die interne*/
/* Groesse des "spielfeld"-es vorgenommen werden.	*/


unsigned int GetPixel(int x, int y)
{
    int fidx;
    fidx = status.spielfeld[x/PUNKTBREIT][y/PUNKTBREIT];
    return ((unsigned int) (((ftab[fidx].red << 16) | (ftab[fidx].green << 8) |
		ftab[fidx].blue)));
}



/* Die Funktion "schritt()" aendert die Position der 	*/
/* Ameise durch Aktualisierung der Variablen "xpos" und	*/
/* "ypos". Da die Ameise bei jedem Schritt eine Drehung	*/
/* um 90 Grad vollzieht, werden auch die Richtungs-	*/
/* variablen "xricht" und "yricht" korrigiert. 		*/
/* Ausserdem wird dafuer gesorgt, dass das Spielfeld	*/
/* an der Position (xpos, ypos) den Regeln gemaess	*/
/* eingefaerbt wird. Der Rueckgabewert ist der Index	*/
/* dieser Farbe.					*/

static int schritt() {

	int farbe = status.spielfeld[status.xpos][status.ypos];
	int rueck;

	if (status.xricht == 0) { /* also senkrechte Bewegung */
		status.xricht = status.yricht * status.richtung[farbe];
		status.yricht = 0; /* von nun an waagerecht bewegen! */
		}
	else { /* also waagerechte Bewegung */
		status.yricht = -status.xricht * status.richtung[farbe];
		status.xricht = 0; /* von nun an senkrecht bewegen! */
	}

	/* Neue Farbe ermitten (und merken): 		*/
	rueck = status.spielfeld[status.xpos][status.ypos] = (farbe + 1) % status.farbzahl; 

	status.xpos += status.xricht; status.ypos += status.yricht; /* einen Schritt bewegen */

	/* Ueberlauf ?	*/
	if (status.xpos < 0) status.xpos = MAXX - 1;
	else if (status.xpos >= MAXX) status.xpos = 0;
	if (status.ypos < 0) status.ypos = MAXY - 1;
	else if (status.ypos >= MAXY) status.ypos = 0;
	return rueck; /* neu berechnete Farbe zurueckgeben	*/
}



/* In der folgenden Variante wird nicht nur das Endergebnis,	*/
/* sondern auch einige Zwischenschritte gesendet. Um	        */
/* ein Neuladen des jeweils neuen Bildes zu erreichen, wird	*/
/* der MIME-Type multipart/x-mixed-replace verwendet.		*/


int main(int argc, char *argv[]) {
	unsigned int f;			/* Hilfsvariablen	*/
	int i, laenge;				
	int x, y;
	unsigned char *pngcode;
   char *querrystring;
   char *tok1;
   char *key,*val;
   char tmp[1000];
   char cachename[1000];

   char name[1000];
   int fd;
   int last_pos=0;
   int step=0;
   int calc=0;
   
   


   querrystring=getenv("QUERY_STRING");

   //printf("%s bla \n",querrystring);

   //typ=rrl&itt=10000000&disp=1000&step=2
   
   last_pos=0;
   
   // printf("Content-type: text/plain\n\n");
   
   tok1=strtok(querrystring,"&");            // parsen des querystrings
   while (tok1) {
      strcpy(tmp,tok1);

      key=tok1;
      val=index(tok1,'=');
      val[0]=0;val++;
      
      //printf("k(%s) v(%s)\n",key,val);

      // berrechnet werden muss von zaehler bis zaehler+intervall<max
      
      status.zaehler=0;

      if (strcmp(key,"name")==0) {
         strcpy(name,val);
      } else 
      if (strcmp(key,"last")==0) {
         last_pos=atoi(val);
      } else 
      if (strcmp(key,"step")==0) {
         step=atoi(val);
      };

      tok1=strtok(NULL,"&");
   }

   //printf("name=%s zaehler=%i max=%i intervall=%i \n",
   //      name,status.zaehler,status.max,status.intervall);
      

	/* Das 2. Argument in seine Buchstaben zerlegen und ueberpruefen: */
	for (status.farbzahl = 0; status.farbzahl < MAXFARBEN && name[status.farbzahl] != '\0'; status.farbzahl++) {
		switch(name[status.farbzahl]) {
			case 'r':
			case 'R': status.richtung[status.farbzahl] = -1; break;
			case 'l':
			case 'L': status.richtung[status.farbzahl] =  1; break;
			default: fprintf(stderr, "Falsche Richtung: %c\n", name[status.farbzahl]);
				 exit(10);
		}
	}

   // herausfinden, ob wir ein cache-file haben

   // filename=name_step
   
   sprintf(cachename,"cache/%s_%i",name,step);
   fd=open(cachename,O_RDONLY);

   if (fd<1) {
      sprintf(cachename,"cache/%s_%i",name,last_pos);
      fd=open(cachename,O_RDONLY);
   }
   
   if (fd>0) {
      read(fd,&status,sizeof(status));
      
   } else {
      /* Anfangswerte: 
       *
       * setup */
      for (x = 0; x < MAXX; x++) {
         for (y = 0; y < MAXY; y++) {
            status.spielfeld[x][y] = 0;
         }
      }
      
      status.zaehler = 0;
      status.xpos = MAXX / 2; status.ypos = MAXY / 2;
      status.xricht = 0; status.yricht = 1;
   }
      
   while (status.zaehler<step) {
      f = schritt();
      status.zaehler++;
      calc++;
	}
  
   /*
   printf("Content-type: text/plain\n\n");
   printf("%i \n",calc);
   exit(1);
   */

   // in den cache sichern

   if (calc>0) {
      sprintf(cachename,"cache/%s_%i",name,status.zaehler);
      fd=open(cachename,O_RDWR|O_TRUNC|O_CREAT,ALLPERMS);
      write(fd,&status,sizeof(status));

      close(fd);
   }
   
   
   /* "spielfeld" als PNG kodieren:	
    * ausgabe des ergebnisses */
   printf("Content-type: image/png\n\n");
	pngcode = PNGCode (&laenge, MAXX * PUNKTBREIT, MAXY * PUNKTBREIT, GetPixel, MIT_KOMPRESSION);
   fwrite(pngcode,laenge,1,stdout);

   
	exit(1);
}

