#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>


#include "globals.h"
#include "sound.h"
#include "sizes.h"
#include "status.h"
#include "score.h"
#include "thread.h"
#include "star.h"
#include "asteroid.h"
#include "texture.h"
#include "object.h"
#include "ship.h"
#include "screen.h"
#include "model.h"
#include "menu.h"
#include "configuration.h"
#include "serverconfig.h"


int GameRunning;
struct KeyValuesStruct KeyValues;
Object *Objects[MAX_OBJECTS];
Ship *Ships[MAX_PLAYERS];
struct Model *Models[MAX_MODELS];
struct Model *AsteroidModels[MAX_OBJECTS];
struct Point ZeroPosition;
pthread_mutex_t ClientLock;
pthread_mutex_t ServerLock;


void LoadSpec(char *dirname, char *filename);
int copyfile(char *ConfDirName, char *FileName);


void DoInitializations()
{
  int i;
  char SpecFileName[1000];
  char DirName[1000];

  ZeroPosition.x=0.0;
  ZeroPosition.y=0.0;
  ZeroPosition.z=0.0;

  for (i=0; i<MAX_MODELS; i++) {
    Models[i]=NULL;
  }

  for (i=0; i<MAX_OBJECTS; i++) {
    AsteroidModels[i]=NULL;
  }

  InitScreen();
  InitStars();

  playsound(PrizeAppears);

  // Load the models into memory
#ifdef WINDOWS
  sprintf(DirName, "models/");
#else
  sprintf(DirName, "%s/atr3d/models/", DATADIR);
#endif

  LoadSpec(DirName, "ship.spec");
  LoadSpec(DirName, "shot.spec");
  LoadSpec(DirName, "a.spec");
  LoadSpec(DirName, "h.spec");
  LoadSpec(DirName, "n.spec");
  LoadSpec(DirName, "s.spec");
  LoadSpec(DirName, "nuke.spec");

  InvertModel(Models[0], 2);
  ShrinkModel(Models[0], 1.0/FindFurthestPoint(Models[0]));
  ShrinkModel(Models[6], 1.0/FindFurthestPoint(Models[6]));
  ShrinkModel(Models[7], 1.0/FindFurthestPoint(Models[7]));
  ShrinkModel(Models[8], 1.0/FindFurthestPoint(Models[8]));
  ShrinkModel(Models[9], 1.0/FindFurthestPoint(Models[9]));
  ShrinkModel(Models[10], 1.0/FindFurthestPoint(Models[9]));

  for (i=0; i<MAX_OBJECTS; i++) {
    InitAsteroid(i);
  }

  InitColors();
  InitHighScores();
  ReadHighScores();

  InitMainMenu();
  InitConfMenu();
  InitScoreMenu();

  for (i=0; i<MAX_OBJECTS; i++) {
    Objects[i]=NULL;
  }

  for (i=0; i<MAX_PLAYERS; i++) {
    Ships[i]=NULL;
  }

  GameRunning=0;
  ShowScore=0;
  ServerStarted=0;

  pthread_mutex_init(&ClientLock, NULL);
  pthread_mutex_init(&ServerLock, NULL);
}


void LoadSpec(char *dirname, char *filename)
{
  FILE *fileptr;
  char entry[80];
  char *c;
  int type;
  float floatvalue;
  int i, j, k;
  char fullfilename[2000];

  sprintf(fullfilename, "%s%s", dirname, filename);

  if (!(fileptr=fopen(fullfilename, "r"))) {
    printf("Error opening spec file %s\n", filename);
    exit(1);
  }

  c=entry;
  while ((*c=fgetc(fileptr))!=EOF) {
    if (*c==':' || *c=='\n') {
      break;
    }
    c++;
  }
  *c='\0';
  type=atoi(entry);
  if (type < MAX_MODELS && type >= 0) {
    if (Models[type]) {
      free(Models[type]);
    }
    Models[type]=(struct Model *)malloc(sizeof(struct Model));
  }

  c=entry;
  while ((*c=fgetc(fileptr))!=EOF) {
    if (*c==':' || *c=='\n') {
      break;
    }
    c++;
  }
  *c='\0';
  Models[type]->NumSides=atoi(entry);
  Models[type]->Points=NULL;

  Models[type]->Sides=(struct Triangle *)malloc(sizeof(struct Triangle)*Models[type]->NumSides);
  for (i=0; i<Models[type]->NumSides; i++) {
    Models[type]->Sides[i].Vertices[0]=(struct Point *)malloc(sizeof(struct Point));
    Models[type]->Sides[i].Vertices[1]=(struct Point *)malloc(sizeof(struct Point));
    Models[type]->Sides[i].Vertices[2]=(struct Point *)malloc(sizeof(struct Point));
    Models[type]->Sides[i].VertexColors[0]=(struct Color *)malloc(sizeof(struct Color));
    Models[type]->Sides[i].VertexColors[1]=(struct Color *)malloc(sizeof(struct Color));
    Models[type]->Sides[i].VertexColors[2]=(struct Color *)malloc(sizeof(struct Color));
    while (fgetc(fileptr)!='\n');

    for (j=0; j<3; j++) {
      for (k=0; k<3; k++) {
        c=entry;
        while ((*c=fgetc(fileptr))!=EOF) {
          if (*c==':' || *c=='\n') {
            break;
          }
          c++;
        }
        *c='\0';

        if (k==0) {
          Models[type]->Sides[i].Vertices[j]->x=strtod(entry, NULL);
        } else if (k==1) {
          Models[type]->Sides[i].Vertices[j]->y=strtod(entry, NULL);
        } else if (k==2) {
          Models[type]->Sides[i].Vertices[j]->z=strtod(entry, NULL);
        }
      }
      for (k=0; k<3; k++) {
        c=entry;
        while ((*c=fgetc(fileptr))!=EOF) {
          if (*c==':' || *c=='\n') {
            break;
          }
          c++;
        }
        *c='\0';

        if (k==0) {
          Models[type]->Sides[i].VertexColors[j]->red=strtod(entry, NULL);
        } else if (k==1) {
          Models[type]->Sides[i].VertexColors[j]->green=strtod(entry, NULL);
        } else if (k==2) {
          Models[type]->Sides[i].VertexColors[j]->blue=strtod(entry, NULL);
        }
      }
    }
  }
  fclose(fileptr);
}


void InitKeyValues()
{
  KeyValues.FireKey=0;
  KeyValues.ShieldKey=0;
  KeyValues.WarpKey=0;
  /*
    KeyValues.xForwardKey=0;
    KeyValues.xBackwardKey=0;
    KeyValues.yForwardKey=0;
    KeyValues.yBackwardKey=0;
  */
  KeyValues.zForwardKey=0;
  KeyValues.zBackwardKey=0;
  KeyValues.xFRotateKey=0;
  KeyValues.xBRotateKey=0;
  KeyValues.yFRotateKey=0;
  KeyValues.yBRotateKey=0;
  KeyValues.zFRotateKey=0;
  KeyValues.zBRotateKey=0;
}


void SetupConfiguration()
{
  DIR *dir;
  char ConfDirName[80];

#ifdef WINDOWS
  sprintf(ConfDirName, "conf");
#else
  sprintf(ConfDirName, "%s/.atr3d", getenv("HOME"));

  if (!(dir=opendir(ConfDirName))) {
    if (mkdir(ConfDirName, 0755)) {
      printf("Error opening atr directory\n");
      exit(1);
    }
    if (!copyfile(ConfDirName, "scores.dat")) {
      printf("Error creating scores.dat file\n");
      exit(1);
    }
    if (!copyfile(ConfDirName, "ATRConfig")) {
      printf("Error creating ATRConfig file\n");
      exit(1);
    }
    if (!copyfile(ConfDirName, "ATRServerConfig")) {
      printf("Error creating ATRServerConfig file\n");
      exit(1);
    }
    if (!copyfile(ConfDirName, "ATRServerSingleConfig")) {
      printf("Error creating ATRServerSingleConfig file\n");
      exit(1);
    }
  } else {
    closedir(dir);
  }
#endif

  sprintf(ScoreFileName, "%s/scores.dat", ConfDirName);
  sprintf(ConfigFileName, "%s/ATRConfig", ConfDirName);
  sprintf(ServerConfigFileName, "%s/ATRServerConfig", ConfDirName);
  sprintf(ServerSingleConfigFileName, "%s/ATRServerSingleConfig", ConfDirName);
}


int copyfile(char *ConfDirName, char *FileName)
{
  FILE *oldfd, *newfd;
  char oldFileName[80], newFileName[80];
  int c;

  sprintf(oldFileName, "%s/atr3d/conf/%s", DATADIR, FileName);
  sprintf(newFileName, "%s/%s", ConfDirName, FileName);

  if (!(oldfd=fopen(oldFileName, "r"))) {
    return(0);
  }
  if (!(newfd=fopen(newFileName, "w"))) {
    fclose(oldfd);
    return(0);
  }
  while ((c=fgetc(oldfd))!=EOF) {
    fputc(c, newfd);
  }
  fclose(oldfd);
  fclose(newfd);

  return(1);
}
