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


#include "globals.h"
#include "sizes.h"
#include "sound.h"
#include "netvariables.h"
#include "thread.h"
#include "object.h"
#include "ship.h"
#include "screen.h"


void SetStatus(char *GameStatus);


/*
  Function to read the data from the server and update the game variables as
  necessary.
*/
void *ReadServerThread(void *sockfd)
{
  int n, i;
  char type;
  char readdata[MAX_PACKET_SIZE];
  char GameStatus[MAX_OBJECTS+MAX_PLAYERS+1];
  SoundStruct SoundData;
  char *ptr;
  struct ObjectDesc ObjData;
  struct ShipDesc ShipData;
  struct Point tmpPoint;

  while (!GameStop) {
    if ((n=recvfrom(svrsock, (char *)readdata,
                    MAX_PACKET_SIZE, 0, NULL, NULL)) < 0) {
      printf("Network error\n");
    } else {
      ptr=readdata;

      pthread_mutex_lock(&ClientLock);
#ifdef DEBUG
      printf("Read Server Thread Awake\n");
#endif
      // Parse through server packet for game data
      while (n) {
        type=*ptr;
        ptr++;
        n--;
        if (type==SOUND_SEND_TYPE) {
          if (n>=sizeof(SoundStruct)) {
            memcpy(&SoundData, ptr, sizeof(SoundStruct));
            CalcPoint(&SoundData.Position, &tmpPoint);
            playsound(SoundData.type, &tmpPoint);
            ptr+=sizeof(SoundStruct);
            n-=sizeof(SoundStruct);
          }
        } else if (type==STATUS_SEND_TYPE) {
          if (n>=MAX_OBJECTS+MAX_PLAYERS+1) {
            memcpy(GameStatus, ptr, MAX_OBJECTS+MAX_PLAYERS+1);
            SetStatus(GameStatus);
            ptr+=MAX_OBJECTS+MAX_PLAYERS+1;
            n-=MAX_OBJECTS+MAX_PLAYERS+1;
          } else {
            break;
          }
        } else if (type==OBJ_SEND_TYPE) {
          memcpy(&ObjData, ptr, sizeof(struct ObjectDesc));
          ptr+=sizeof(struct ObjectDesc);
          n-=sizeof(struct ObjectDesc);
          if (!Objects[ObjData.Number]) {
            Objects[ObjData.Number]=new Object();
            Objects[ObjData.Number]->Age=0.0;
          }
          memcpy(&Objects[ObjData.Number]->Position, &ObjData.Position,
                 sizeof(struct Point));
          memcpy(&Objects[ObjData.Number]->RotationMatrix,
                 &ObjData.RotationMatrix, sizeof(float[3][3]));
          Objects[ObjData.Number]->Type=ObjData.Type;
          Objects[ObjData.Number]->Size=ObjData.Size;
          if (Objects[ObjData.Number]->Type==ASTEROID_TYPE) {
            Objects[ObjData.Number]->ObjModel=AsteroidModels[ObjData.Number];
          } else if (Models[Objects[ObjData.Number]->Type]) {
            Objects[ObjData.Number]->ObjModel=Models[Objects[ObjData.Number]->Type];
          }
        } else if (type==SHIP_SEND_TYPE) {
          memcpy(&ShipData, ptr, sizeof(struct ShipDesc));
          ptr+=sizeof(struct ShipDesc);
          n-=sizeof(struct ShipDesc);
          if (!Ships[ShipData.Number]) {
            Ships[ShipData.Number]=new Ship();
            Ships[ShipData.Number]->ObjModel=Models[0];
          }
          memcpy(&Ships[ShipData.Number]->Position,
                 &ShipData.Position, sizeof(struct Point));
          Ships[ShipData.Number]->Score=ShipData.Score;
          Ships[ShipData.Number]->Lives=ShipData.Lives;
          Ships[ShipData.Number]->Size=ShipData.Size;
          Ships[ShipData.Number]->ShieldOn=ShipData.ShieldOn;
          Ships[ShipData.Number]->Shield=ShipData.Shield;
          Ships[ShipData.Number]->Armor=ShipData.Armor;
          Ships[ShipData.Number]->Shaking=ShipData.Shaking;
          Ships[ShipData.Number]->Alive=ShipData.Alive;
          Ships[ShipData.Number]->Warps=ShipData.Warps;
          Ships[ShipData.Number]->Nukes=ShipData.Nukes;
          strcpy(Ships[ShipData.Number]->PlayerName, ShipData.PlayerName);
          if (ShipData.Number==myShip) {
            memcpy(&Ships[ShipData.Number]->CameraMatrix,
                   &ShipData.RotationMatrix, sizeof(float[3][3]));
            if (ShipData.Warping) {
              if (WarpSoundNum==-1) {
                WarpSoundNum=playsoundinloop(WarpSound);
              }
            } else {
              if (WarpSoundNum!=-1) {
                stopsoundinloop(WarpSoundNum);
                WarpSoundNum=-1;
              }
            }
          } else {
            memcpy(&Ships[ShipData.Number]->RotationMatrix,
                   &ShipData.RotationMatrix, sizeof(float[3][3]));
          }
        } else {
          break;
        }
      }
#ifdef DEBUG
      printf("Read Server Thread Sleeping\n");
#endif
      pthread_mutex_unlock(&ClientLock);
    }
  }

  close(svrsock);

  printf("Exiting Read Server Thread\n");
  pthread_exit(NULL);
}


void SetStatus(char *GameStatus)
{
  int i;

  for (i=0; i<MAX_OBJECTS; i++) {
    if (GameStatus[i]==0 && Objects[i]) {
      delete Objects[i];
      Objects[i]=NULL;
    }
  }
  for (i=0; i<MAX_PLAYERS; i++) {
    if (GameStatus[i+MAX_OBJECTS]==0 && Ships[i] && i!=myShip) {
      delete Ships[i];
      Ships[i]=NULL;
    }
  }

  GameRunning=GameStatus[MAX_OBJECTS+MAX_PLAYERS];
}
