#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <dirent.h>
#include "protos.h"
#include "globals.h"

#define DBG 0

extern int filter_dotstar(const struct dirent *dep);

/* Returns true for ".rok" files and false for all others */
static int filter_dotrock(struct dirent *dep)
{
  int i;

/*   printf("%s\n",dep->d_name); */
  i = strlen(dep->d_name);
  if(i<4) return 0;
  else return (!strcmp(dep->d_name+i-4,".rok"));
}

/* Add rp to the rdag of *rpp */
void add_to_library(rock **rpp,rock *rp)
{
  if((!rpp) || (!rp)) return;
  else if(!(*rpp)) *rpp = rp;
  else {
    rp->prev = (*rpp);
    add_to_library(&(*rpp)->next,rp);
  }
}

unsigned int get_mission_checksum(char *name)
{
  FILE *file;
  unsigned int i=0;
  int j=0;
  int c;

  if(!(file = fopen(name,"r"))) return 0;
  while((c=getc(file))!=EOF) {
    /* First two unsigned int are for the checksums */
    if((++j)>(sizeof(unsigned int)*2)) i = (i^0xFACE0FF) + (c ^ 0xFA);
  }
  fclose(file);
/*   printf("Found magic number %ud for file %s\n",i,name); */
  return i;
}

void read_mission_levels(mission *miss)
{
  int popened = 0;
  struct stat filestat;
  static level l;
  int i;
  FILE *f;

  if(!miss) return;

  for(i=0;i<miss->numlevels;i++) {
    if(miss->level[i]->rocks) {
      miss->level[i]->rocks = NULL; /* ??? Yes, we will miss them */
    }
  }

  miss->numlevels = 0;
  if(stat(miss->name,&filestat) == -1) {
    printf("File system problem?  Could not stat() the Mission file\n");
    return;
  }
  if(filestat.st_mode & 0111) { /* If executable */
#if 0 && defined(__LINUX__)
    char *tmp;

    tmp = malloc(strlen(miss->name)+strlen("awk -f ")+1);

    strcpy(tmp,"awk -f ");
    strcat(tmp,miss->name);

    f = popen(tmp,"r");
    free(tmp);

    if(!f) syserr("Couldn't popen file");
    else popened = 1;
#else
    if(!(f = popen(miss->name,"r"))) syserr("Couldn't popen file");
    else popened = 1;
#endif
  } else if(filestat.st_mode & 0444) { /* If readable */
    if(!(f = fopen(miss->name,"r"))) syserr("Couldn't fopen file");
  } else {
    printf("I don't have permission to read the mission file\n");
    return;
  }
  print_missionname();
  while(1) {
    read_level(&l,f);
    if(!l.rocks) break;
    else {
      miss->level = (level **) 
	  realloc(miss->level,sizeof(level *)*(++miss->numlevels));
      miss->level[miss->numlevels-1] = (level *)malloc(sizeof(level));
      memcpy(miss->level[miss->numlevels-1],&l,sizeof(level));
/*       printf("Read mission %s\n",miss->level[miss->numlevels-1]->name); */
    }
  }
  if(miss->level[0]->numlives<=0) miss->level[0]->numlives = GIVEN_LIVES;
  if(popened) pclose(f);
  else fclose(f);
  read_mission_high(miss);
}

static mission **read_mission_dir(char *dir)
{
  struct stat fstat;
  mission **mpp;
  struct dirent **dirinfo;
  int i,j;

  Num_missions = scandir(dir,&dirinfo,filter_dotstar,alphasort);
/*   printf("Reading %d missions\n",Num_missions); */
  if(Num_missions <= 0) {
    fprintf(stderr,"Warning! Cannot locate any mission "
		  "data files in dir: %s\n",dir);
    return NULL;
  }
/*   else printf("Found %d missions in %s\n",Num_missions,dir); */

  mpp = (mission **)calloc(sizeof(mission *),Num_missions);
  for(i=j=0;j<Num_missions;i++,j++) {
    mpp[i] = (mission *)calloc(sizeof(mission),1);
    mpp[i]->name = (char *)malloc(strlen(dir)+1+strlen(dirinfo[j]->d_name)+1);
    strcpy(mpp[i]->name,dir);
    strcat(mpp[i]->name,"/");
    strcat(mpp[i]->name,dirinfo[j]->d_name);

    stat(mpp[i]->name,&fstat);
    if(fstat.st_mode & S_IFDIR) { /* Don't count directories as entries */
      free(mpp[i]->name);         /* Later, I might have submissions etc */
      free(mpp[i]);
      i--;
      continue;                   /* Don't really like the idea, though */
    }

#if DBG
    printf("Loading mission %s\n",dirinfo[i]->d_name);
#endif
/*    read_mission_levels(mpp[i]);  Read the levels for this mission */
/* I don't do this anymore, because some missions take a long time to load */
  }
  Num_missions=i;
  return mpp;
}

void free_mission(mission *mp)
{
  int j;

  if(!mp) return;

  for(j=0;j<mp->numlevels;j++) {
    if(mp->level[j]->rocks) free_geometry(mp->level[j]->rocks);
    if(mp->level[j]->name) free(mp->level[j]->name);
    if(mp->level[j]->author) free(mp->level[j]->author);
    free(mp->level[j]);
  }
}

static void free_missions(mission **mpp)
{
  int i,j;

  if(!mpp) return;

  for(i=0;i<Num_missions && mpp[i];i++) {
    if(mpp[i]) {
      free_mission(mpp[i]);
      free(mpp[i]);
    }
  }
  free(mpp);
}

void loadmissions(void)
{
  char *dir;

  if(!(dir = getenv("RAWK_MISSIONDIR"))) dir = "./.data/rawks/Mission";
  if(Mission_list && Num_missions) free_missions(Mission_list);
  Mission_list = read_mission_dir(dir);
}
