/***************************************************************************/
/*  Killer List Of Video-games Database.                                   */
/*  Copyright (C) 1993  John Keay                                          */
/*                                                                         */
/*  This program is free software; you can redistribute 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 for more details.                           */
/*                                                                         */
/*  You should have received a copy of the GNU General Public License      */
/*  along with this program; if not, write to the Free Software            */
/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
/*                                                                         */
/*  For more details see 'COPYING'                                         */
/*  John Keay (keay@tiuk.ti.com)                                           */
/***************************************************************************/

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

#include "proto.h"
#include "parse.h"
#include "game.h"

#ifndef TRUE
#define TRUE (!0)
#endif
#ifndef FALSE
#define FALSE 0
#endif

char *newstr(s)
char *s;
{ char *ptr = NULL;

  if(s && *s) {
    ptr = (char *)safe_malloc(strlen(s)+1);
    strcpy(ptr,s);
  }
  return(ptr);
} 

static int is_player PROTO((char *s));
static int is_player(s)
char *s;
{ int len = strlen(s);
  int i;

  if(!isdigit(s[0])) return(FALSE);
  if(s[len-1] != 'P') return(FALSE);
  for(i=1;i<len-1;i++)
    if(!isdigit(s[i]))
      return(FALSE);
  return(TRUE);
}

static int is_number PROTO((char *s));
static int is_number(s)
char *s;
{
  if(!s || !s[0])

    return(FALSE);
  for(;*s;s++)
    if(!isdigit(*s))
      return(FALSE);
  return(TRUE);
}

void game_print_brief(g,out)
game_ptr g;
FILE *out;
{
  if(g) {
    fprintf(out,"%s {",g->name);
    if(g->company)
      fprintf(out,"%s ",g->company);
    if(g->date)
      fprintf(out,"%s ",g->date);
    fprintf(out,"%s",(g->flags & F_3D)?"3D ":"");
    fprintf(out,"%s",(g->flags & F_PINBALL)?"Pinball ":"");
    fprintf(out,"%s",(g->flags & F_VECTOR)?"Vector ":"");
    fprintf(out,"%s",(g->flags & F_LASER)?"Laser ":"");
    fprintf(out,"%s",(g->flags & F_BNW)?"BnW ":"");
    if(g->players)
      fprintf(out,"%s ",g->players);
    if(g->produced)
      fprintf(out,"%s ",g->produced);
    fprintf(out,"}\n");
  }                                    
}

void game_print(g,out)
game_ptr g;
FILE *out;
{
  if(g) {
    game_print_brief(g,out);
    if(g->text)
      fprintf(out,"%s",g->text);
  }                                    
}

void game_destroy(g)
game_ptr g;
{
  if(g->name)     free(g->name);
  if(g->date)     free(g->date);
  if(g->company)  free(g->company);
  if(g->players)  free(g->players);
  if(g->produced) free(g->produced);
  if(g->text)     free(g->text);
  free(g);
}

static int get_name PROTO((parse_ptr p,char *name));
static int get_name(p,name)
parse_ptr p;
char *name;
{ char *s;

  if(p && name && p->line) {
    s = p->line;
    while(*s && *s != '{')     /* Find first '{'  */
      s++;
    if(!*s)
      return(0);               /* No '{' in string */
    *s = '\0';
    strcpy(name,p->line);
    *s = '{';
    return(1);
  }
  return(0);
}

static game_ptr entry PROTO((parse_ptr p));
static game_ptr entry(p)
parse_ptr p;
{ static char name[MAX_LINE_LEN];
  static char date[MAX_LINE_LEN];
  static char company[MAX_LINE_LEN];
  static char players[MAX_LINE_LEN];
  static char produced[MAX_LINE_LEN];
  static char first[MAX_LINE_LEN];
  ulong flags   = 0;
  game_ptr g = NULL;

  name[0]     = '\0';
  date[0]     = '\0';
  company[0]  = '\0';
  players[0]  = '\0';
  produced[0] = '\0';
  first[0]    = '\0';

  if(!get_name(p,name))
    return(g);

  while (its_not(p,"{"))
    parse_get_token(p);

  while (its_not(p,"}")) {                                   /* FLAGS */
    if(its(p,"BnW"))                 flags |= F_BNW;
    else if(its(p,"3D"))             flags |= F_3D;
    else if(its(p,"Laser"))          flags |= F_LASER;
    else if(its(p,"Vector"))         flags |= F_VECTOR;
    else if(its(p,"Raster"))         flags &= ~F_VECTOR;
    else if(its(p,"Pinball"))        flags |= F_PINBALL;
    else if(is_player(p->token)){                            /* # PLAYERS */
      strcat(players,p->token);
      parse_get_token(p);
      while(its(p,"or")) {
        strcat(players," or ");
        strcat(players,p->token);
        parse_get_token(p);
      }
    } else if(its(p,"(")) {                                  /* '(' */
      while(its_not(p,")"))
        parse_get_token(p);
    } else if(p->token[0] == '?' || p->token[0] == ',' ) {   /* SKIP THESE */
      parse_get_token(p);
    } else if(p->token[0] == '\'') {                         /* A DATE */
      if(date[0])
        strcat(date," ");
      strcat(date,p->token);
      parse_get_token(p);
      while(its(p,"or")) {
        strcat(date," or ");
        strcat(date,p->token);
        parse_get_token(p);
      }
    } else if(is_number(p->token)) {                         /* PLAYERS or */
      strcat(first,p->token);                                /* PRODUCED */
      parse_get_token(p);
      if(its(p,"or")) {
        if(is_player(p->token)){
          strcat(players,first);
          strcat(players," or ");
          strcat(players,p->token);
          parse_get_token(p);
        }
      } else {   
        if(its(p,"produced")) {
        } else 
          mustbe(p,"pro");
        strcat(produced,first);
        strcat(produced," pro");
      }
    } else {                                                 /* COMPANY */
      if(company[0])
        strcat(company," ");
      strcat(company,p->token);
      parse_get_token(p);
    }
  }

  while (its_not(p,"\n"))
    parse_get_token(p);

  if(name[0]) {
    g = (game_ptr) safe_malloc(sizeof(game_t));
    g->name     = newstr(name);
    g->date     = newstr(date);
    g->company  = newstr(company);
    g->players  = newstr(players);
    g->produced = newstr(produced);
    g->flags    = flags;
    g->text     = NULL;
    g->next     = NULL;
/*    printf("name:%-40s (%-4s) (%-8s) date:%-8s company:%s\n",name,
             players,produced,date,company);  */
  }
  return(g);
}

static char *description PROTO((parse_ptr p));
static char *description(p)
parse_ptr p;
{ static char text[MAX_TEXT];
  char *ptr= NULL;

  text[0] = '\0';

  while(!p->eof && p->token_pos) {
    strcat(text,p->line);
    while (its_not(p,"\n")) 
      parse_get_token(p);
  }
  if(text[0]) {
    ptr = (char *) safe_malloc(strlen(text)+1);
    strcpy(ptr,text);
  }
  return(ptr);
}

void list_append(l,filename)
list_ptr l;
char *filename;
{ parse_ptr input;

  input = parse_open(filename);

  if(input) {
    while(!input->eof) {
      game_ptr g;
      do {
        while(its(input,"[")) {
          while (its_not(input,"\n"))
            parse_get_token(input);
        }
      } while(its(input,"\n"));
      g = entry(input);
      if(g) {
        g->text = description(input);
        if(l->head) {
          l->tail->next = g;
          l->tail = g;
        } else {
          l->head = l->tail = g;
        }
      }
    }
    parse_close(input);
  }
}

list_ptr list_create()
{ list_ptr l;

  l = (list_ptr) safe_malloc(sizeof(list_t));
  l->head = NULL;
  l->tail = NULL;

  return(l);
}

list_ptr list_read(filename)
char *filename;
{ list_ptr l = list_create();
  list_append(l,filename);
  return(l);
}

void list_destroy(l)
list_ptr l;
{ game_ptr g;
  game_ptr next;

  if(l) {
    g = l->head;
    free(l);
    for(;g;g=next) {
      next = g->next;
      game_destroy(g);
    }
  }
}
