#include <stdio.h>     // printf
#include <strings.h>   // str[n][case]cmp und so
#include <fcntl.h>     // open
#include <sys/stat.h>  // stat
#include <unistd.h>    // read/write
#include <stdlib.h>    // malloc
#include <time.h>      // localtime, asctime
#include <sys/types.h> // chmod

#undef RESTRICT
// IP nicht checken
#define MAX_FLUR 5
#define MIN_FLUR 0
#define ANZ_SAETZE 4
#define LOGFILE "logfile.txt"
#define PFAD    "/.../lift/"

#define FALSCH(wieso) { printf("Content-type: text/plain\n\nFehler!\n"); \
 printf(wieso); printf("\n"); return 1; }
#define DONE { \
 printf("Location: http://.../lift/\n\n"); \
 return 0; }

/* -------------------------------------------------------------- */
static int aufz_pause=0; // boolean
static int ziele[6]={0,0,0,0,0,0}; // Queue (booleans)
// static int ziel=0; // naechstes Ziel (von mir bisher ignoriert)
static int jetzt=0; // Position
static int richtung=0; // Lift: -1 down 0 stop 1 up
static int innentuer=0; // Schiebetuer: 0 zu 1 geht auf -1 geht zu 2 ist auf
static int sensoren=0; // 0 nix -1 Lichtschranke ausgeloest 1 nur Drehtuer auf
// innentuer und sensoren wird von mir dann zusammengefasst...
/* -------------------------------------------------------------- */

void log(char * satz, int zahl)
{
clock_t jetzt;
char * jetzt_asc;
FILE * logfile = fopen(PFAD LOGFILE,"a");
if (!logfile) return;
(void) chmod(LOGFILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
jetzt = time(NULL);
jetzt_asc = asctime(localtime(&jetzt));
jetzt_asc[strlen(jetzt_asc)-1]=0;
(void) fprintf(logfile, "%s: %s %d\n", jetzt_asc, satz, zahl);
(void) fclose(logfile);
return;
};

void image(char * dateiname, int refresh)
{
int fd;
char * buffer;
char dateipfad[200];
char header[200];
struct stat status;
// Bilder ggf im RAM puffern!!!

if (refresh<=0) refresh=60;
snprintf(header,190,"Content-type: image/gif\nExpires: %d\n\n",refresh);
write(1,header,strlen(header));

snprintf(dateipfad,180,PFAD); // Reihenfolge!
strncat(dateipfad, dateiname, 190-strlen(dateipfad)); dateipfad[199]=0;
fd = open(dateiname,O_RDONLY);
if (!fd) return;
if (stat(dateiname,&status)) return;
if (!(buffer = malloc(status.st_size))) return;
if (status.st_size != read(fd,buffer,status.st_size)) { free(buffer); return; };
   // bin zu faul fuer 2. read-anlauf...
if (status.st_size != write(1,buffer,status.st_size)) { free(buffer); return; };
   // read-write sollte Timeout haben, da Staus unter Userkontrolle sind!
   // obacht wenn stdout zu ist... evtl fstat(1) machen?

free(buffer);
(void) close(fd);
return;
};

// evtl void wave(int selection) nach dem gleichen Muster, aber mit
// /dev/dsp statt stdout ...

/* -------------------------------------------------------------- */

void toggle_pause(void) 
{ 
  aufz_pause = (aufz_pause) ? 0 : 1; 
  if (aufz_pause) { log("Aufzug vom Wizard festgehalten",0); }
     else    { log("Aufzug vom Wizard freigegeben",0); };

  /* HIER KONTROLLE ANBINDEN */

  return;
};

void enqueue(int flur) 
{ 
  if ((flur>MAX_FLUR) || (flur<MIN_FLUR)) return;
  ziele[flur-MIN_FLUR] |= 1;
  log("Neu in die Ziel-Liste aufgenommen: ",flur);

  /* HIER KONTROLLE ANBINDEN */
  /* SPRACHAUSGABE HIER TRIGGERN */
  /* oder file aus dem RAM gleich nach /dev/dsp schreiben... */

  return;
};

void speak(int satz) 
{ 
  if ((satz>ANZ_SAETZE) || (satz<1)) return;
  log("Sprachausgabe an den Fahrgast: ",satz);

  /* SPRACHAUSGABE HIER TRIGGERN */
  /* oder file aus dem RAM gleich nach /dev/dsp schreiben... */
  /* z.B. image() oben nachempfinden! */

  return;
};

/* -------------------------------------------------------------- */

void show_state(void) 
{ 

  /* HIER KONTROLLE ANBINDEN oder auch nicht */
  /* CASE BLABLA BLABLA, Kategorien sind:
   *  1. OK: ball_g.gif
   *  2. Halt, Aus: ball_r.gif
   *  3. Stop!, Test!, Feuer!, Fehler!: warnung.gif
   */

  image("ball_g.gif",5);
  return;
};

void query_request(int flur) 
{ 
  if ((flur>MAX_FLUR) || (flur<MIN_FLUR)) return;

  /* HIER KONTROLLE ANBINDEN oder auch nicht */

  if (ziele[flur-MIN_FLUR]) { image("ball_g.gif",5); } 
  else                      { image("ball_r.gif",5); };
  return;
};

void query_floor(int flur) 
{ 
  if ((flur>MAX_FLUR) || (flur<MIN_FLUR)) return;
  
  /* HIER KONTROLLE ANBINDEN oder auch nicht */
  /*    eventuell "gesehen" Flags setzen!    */
  
  if (jetzt!=flur) { image("none.gif",1); return; };
  if (richtung) { if (richtung>0) { image("up.gif",1); return; }
                  else            { image("down.gif",1); return; };
                }
  else          { if (!innentuer) { image("arrived.gif",1); return; };
                  if (innentuer==1)  { image("opening.gif",1); return; };
                  if (innentuer==-1) { image("closing.gif",1); return; };
                  // also ist die Innentuer jetzt auf...
                  if (!sensoren) { image("one_open.gif",1); return; };
                  if (sensoren==1) { image("both_open.gif",1); return; };
                  if (sensoren==-1) { image("guy.gif",1); return; };
                  image("warnung.gif",1);
                };
  return;
};

/* -------------------------------------------------------------- */

int main(int argc, char ** argv)
{
int n = -1;
char * query = getenv("QUERY_STRING");

if ((!query) || (strlen(query)<5) || (strlen(query)>7)) FALSCH("Len");
#ifdef RESTRICT
if ((!getenv("REMOTE_ADDR")) || 
    strcmp(getenv("REMOTE_ADDR"),"134.96.68.11"))
  FALSCH("Remote");
#endif

// Befehle: pause, set=n, say=n
// Fragen: stat=n isset=n state

n = query[strlen(query)-1];
if ((n>='0') && (n<='9')) { n -= '0'; } else { n = 0; };
// ggf vielseitigeren Code verwenden!

if (!strcasecmp(query,"pause")) { toggle_pause(); DONE; };
if (!strncasecmp(query,"set=",4)) { enqueue(n); DONE; };
if (!strncasecmp(query,"say=",4)) { speak(n); DONE; };

if (!strcasecmp(query,"state")) { show_state(); return 0; };
if (!strncasecmp(query,"isset=",6)) { query_request(n); return 0; };
if (!strncasecmp(query,"stat=",5)) { query_floor(n); return 0; };

return 0;
};
