/* Last updated by Navid Azizi on September 22th */
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
#include <malloc.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/uio.h>
#include <errno.h>
#include <semaphore.h>



#define MINPLAYERS 2
#define MAXPLAYERS 4
#define LENGTH 15
#define MAXTILES 7

#define MAXSIZE 240

#define BOOL  int 
#define FALSE 0 
#define TRUE  1 

/* Error messages */

#define PROBLEMRESTORINGGAME -17
#define PROBLEMSAVINGGAME -16
#define NOTENOUGHTILES -15
#define NOTENOUGHPLAYERS -11
#define CANTCHALLENGENOW -10
#define GAMEALREADYSTARTED -9
#define GAMENOTSTARTED -8
#define INVALID -7
#define UNSUCCESSFULLCHALLENGE -6
#define MISCERROR -5
#define NOTCURRENTPLAYER -4

/* Packet types for successful completion */

#define OK 1

/* Packet types that the GM will
   initiate */

#define CHALLENGEREQUEST 2
#define PLAYERHASRESIGNED 3
#define WINNER 4
#define YOURMOVE 5
#define SUCCESSFULLCHALLENGE 6
#define SMOVECOMPLETED 7
#define BMOVECOMPLETED 8
#define GAMENOWSTARTED 9
#define NEWTILES 23

/* Packet types and return messages
 that PCI will initiate */

#define BMOVE 12
#define PLAYERINFO 14
#define PLAYERINFORETURN 15
#define NEWGAME 16
#define SCOREINFO 18
#define SCOREINFORETURN 19
#define CHALLENGE 20
#define SHOWTRAY 22
#define SHOWTRAYRETURN 23
#define TRYMOVE 24
#define SHOWBOARD 26
#define SHOWBOARDRETURN 27
#define RESIGN 28
#define SMOVE 30
#define WHO 32
#define CREATEAUTOMATEDPLAYER 34
#define CREATEAUTOMATEDPLAYERRETURN 35
#define SAVEGAME 36
#define RESTOREGAME 37

typedef int KScore;

typedef enum {SCORE_MULT_DOUBLE_LETTER, SCORE_MULT_TRIPLE_LETTER,
              SCORE_MULT_DOUBLE_WORD, SCORE_MULT_TRIPLE_WORD, 
              SCORE_MULT_NONE,
              NUM_SCORE_MULTS} KScoreMultiplier;

typedef enum { NOPLAYER, HUMAN, AUTOMATED } KPlayerType;
typedef enum { NOTEXIST, ACTIVE, RESIGNED } KPlayerStatus;
typedef enum { BAG, RACK } KListType;
typedef enum { PLACE, SWAP, NOMOVE } KMoveType;

typedef struct sGridRef
 { 
  int x; 
  int y; 
 } KGridRef; 

typedef struct sSsingleMove
 {
  char letter;
  KGridRef Pos;
  int fromBlank;
 } KSingleMove;

typedef struct sBMove
 { 
  KMoveType type;
  int numMoves;
  KSingleMove moves[7];
 } KBMove;

typedef struct sSMove
 { 
  KMoveType type;
  int numMoves;
  char letters[7];
 } KSMove;

typedef struct sWordList
 {
  char *words[15];       
  int num_words;
 } KWordList;

typedef struct sTile
 {
  struct sTile *link;
  char letter;
  KScore score;
  struct sTileList *inlist;
 } KTile;

typedef struct sTileList
 {
  int type;
  int length;
  struct sTile *Tiles;
 } KTileList;


typedef struct sPlayer
 {
  int playerID;
  int playerIDsend;
  pthread_t  tid;
  int type;
  int alive;
  int score;
  int howManyMoves;
  int lostturn;
  KTileList *rack;
  struct sockaddr_in client;
  int client_len;
 } KPlayer;



typedef struct packet
 {
  int type;
  char message[MAXSIZE];
 } GeneralPacket;

typedef struct packet2
 {
  int type;
  KScore Player1;
  KScore Player2;
  KScore Player3;
  KScore Player4;
  char message[224];
 } ScorePacket;

typedef struct packet3
 {
  int type;
  int numberOfPlayers;
  int pid[4];
  KScore score[4];
  char message[202];
 } PlayerPacket;

typedef struct packet4
 {
  int  type;
  int  numberOfTiles;
  char letters[7];
  KScore scores[7];
  char message[200];
 } TrayPacket;

typedef struct packet5
 {
  int type;
  KBMove theMove;
  char message[117];
 } BMovePacket;

typedef struct packet55
 {
  int type;
  KSMove theMove;
  char message[221];
 } SMovePacket;

typedef struct packet6
 {
  int type;
  KScore score;
  char message[236];
 } ScoreReturnPacket;

typedef struct packet7
 {
  int type;
  char board[15][15];
  char message[14];
 } BoardPacket;

typedef struct packet8
 {
  int type;
  int winner;
  int numberOfPlayers;
  int pid[4];
  KScore score[4];
  char message[200];
 } WinnerPacket;

typedef struct packet9
 {
  int type;
  int resigned;
  char message[236];
 } ResignPacket;

typedef struct packet10
 {
  int type;
  int playerID;
  KBMove theMove;
  char message[113];
 } ChallengePacket;

typedef struct packet11
 {
  int type;
  int playerID;
  KBMove theMove;
  char message[113];
 } MoveCompletedPacket;

typedef struct packet120
 {
  int type;
  int pid;
  char message[236];
 } GameStartedPacket;


void KaddTNumb(KTile **pT, KTile *t, int n);
void KdequeueTile(KTile *t);
void KprintTile(KTile *t);
void KprintList(KTileList *group);
KTileList *KgetQueue(KTile *t);
KTile *KallocTile(char letter, int score);
int KdeallocTile(KTile *t);
int KgetTileScore(KTile *t);
char KgetTileLetter(KTile *t);
KTileList *KcreateGroup(KListType type);
KTile *KdequeueHead(KTileList *group);
int KdestroyWholeList(KTileList *group);
int KdestroyList(KTileList *group);
int KnumberEnqueue(KTile *t, KTileList *group, int n);
int KheadEnqueue(KTile *t, KTileList *group);
KTile *KfindLetter(char c, KTileList *group);


void *KplayerThread(void *p);

/*-----------------------*/
/* In gm.c               */
/*-----------------------*/

pthread_mutex_t *KgetLockForPlayer(KPlayer *p);
KPlayer *KgetNextPlayer(KPlayer *p);
KPlayer *KgetNextPlayerWithOutLock(KPlayer *p);
void KinitializeBag();
void KprintLetter(int n);
int KplaceLetterInBag(KTile *t);
int KfillUpRack(KPlayer *p);
int KplayerDropsLetter(KPlayer *p, KTile *t);
int KplayerPickLetter(KPlayer *p);
char KgetLetter(int n);
int KBagSize();
KScore KCurrentScore(int pid);
int KMove(int pid,KBMove m);
int KHowManyMoves();
KScore KAverageScore(int pid);
int KcallAP(KPlayer *p);


/*-----------------------*/
/* In send.c             */
/*-----------------------*/

int KsendYourTurn(KPlayer *p);
int KsendChallengeRequest(KPlayer *p);
int KsendGameFinished();
int KsendPlayerResign(KPlayer *p);
int KsendChallengeAccept(KPlayer *p);
int KsendPlayerMove(KPlayer *p);
int KsendGameStarted(KPlayer *h);
int KsendWholeRack(KPlayer *h);


/*-----------------------*/
/* In player.c           */
/*-----------------------*/

void KprintPlayer(KPlayer *p);
KPlayer *KallocPlayer();
int KdeallocPlayer(KPlayer *p);
KScore KgetPlayerScore(KPlayer *p);
int KaddPlayerScore(KPlayer *p, KScore score);
int KsubPlayerScore(KPlayer *p, KScore score);
int KnumberOfMovesPlayer(KPlayer *p);
int KincrementMovesPlayer(KPlayer *p);
KPlayerType KgetPlayerType(KPlayer *p);
int KsetPlayerType(KPlayer *p, KPlayerType type);
KPlayerStatus KgetPlayerStatus(KPlayer *p);
int KsetPlayerStatus(KPlayer *p, KPlayerStatus status);
int KgetPlayerLostTurn(KPlayer *p);
int KsetPlayerLostTurn(KPlayer *p, int lostTurn);
int KgetPlayerID(KPlayer *p);
int KswapPlayers(KPlayer *p1, KPlayer *p2);


/*-----------------------*/
/* In auxilliary.c       */
/*-----------------------*/

int KgetPlayerInfo(PlayerPacket *packet);
int Kresign(KPlayer *p);
int KgetPlayerTray(KPlayer *p, TrayPacket *packet);
int KswapMove(KPlayer *p, SMovePacket *packet);
int KboardMove(KPlayer *p, BMovePacket *packet);
KScore KtryMove(KPlayer *p,BMovePacket *packet);
int KshowBoard(BoardPacket *packet);
int KChallenge(KPlayer *p);
int KrestoreGame(KPlayer *p);
int KsaveGame(KPlayer *p);





/*-----------------------*/
/* Internal BM Interface */
/*-----------------------*/

int KAddBMove(KBMove);
void KInitializeBoard();
KScoreMultiplier KSquareScore(KGridRef);
int KRemoveTile(KGridRef);
int KCheckBMove(KBMove);
int KScoreBMove(KBMove);
KWordList *KNewWords(KBMove);
int KEmptySquare(KGridRef);
char KTileSquare(KGridRef);
KBMove *KLastMove(void);
void KsetLastMoveNULL(void);
void KsetNewBoard(char a[][LENGTH]);
void KsetLastMove(KBMove *temp);

/*-----------------------*/
/* Internal AP Interface */
/*-----------------------*/

KBMove *KAPMove(KTileList *);
void KinitialiseAP();



