#include "internal.h"
#include <strings.h>

/*-----------------------*/
/* Global Variables      */
/*-----------------------*/

int temp;

extern int             sd;
extern KPlayer         *currentPlayer;
extern KPlayer         *player1;
extern KPlayer         *player2;
extern KPlayer         *player3;
extern KPlayer         *player4;
extern KPlayer         *host;
extern KTileList       *Bag;

extern KWordList       *newWords;

extern pthread_mutex_t p1Lock;
extern pthread_mutex_t p2Lock;
extern pthread_mutex_t p3Lock;
extern pthread_mutex_t p4Lock;
extern pthread_mutex_t bagLock;
extern pthread_mutex_t currentPlayerLock;
extern pthread_mutex_t canChallengeLock;
extern pthread_mutex_t numberOfAPLock;
extern pthread_mutex_t numberOfPlayersLock;


extern pthread_t       getPlayersTid;
extern pthread_t       timerTid;
extern int             numberOfPlayers;
extern int             gameStarted;
extern int             gameFinished;
extern int             canChallenge;
extern int             numberOfAP;
extern int             lastPersonNotBMove;

extern sem_t           finishedGettingPlayers;
extern sem_t           finishedCurrentPlayerMove;
extern sem_t           waitForChallenge;


int
KsendYourTurn(KPlayer *p)
 {
  /* Debugged by Navid Azizi on October 4th */

  /* This function sends a packet to player p indicating that it is their turn to plays
   * Pre: p is currentplayer
   * Post: OK is returned on success, and MISCERROR on failure */
  
  pthread_mutex_t *lock;
  GeneralPacket packet;

  if (currentPlayer != p)
    return(NOTCURRENTPLAYER);

  /* Can't send to automated player */
  if (KgetPlayerType(p) == AUTOMATED)
    return(MISCERROR);

  lock = KgetLockForPlayer(p);

  if (lock == NULL)
    return(MISCERROR);

  pthread_mutex_lock(lock);

  packet.type = YOURMOVE;

  /* Send to player */

  if (write(p->playerIDsend,&packet,sizeof(GeneralPacket)) < 0)
   {
    perror("Write failed\n");
    exit(1);
   }


  pthread_mutex_unlock(lock);  

  return(OK);
 }

/*----------------------------------------------------*/

int
KsendChallengeRequest(KPlayer *p)
 {
  /* Debugged by Navid Azizi on October 4th */

  /* This function sends a packet to every player other than p indicating that it 
     they can challenge
   * Pre: p is currentplayer
   * Post: OK is returned on success, and MISCERROR on failure */


  KPlayer *next;
  pthread_mutex_t *lock;
  GeneralPacket packet;
  int i;

  /* Check to see if they are the current player */
  if (currentPlayer != p)
    return(NOTCURRENTPLAYER);

  /* For numberof players - 1 send out a request */
  next = KgetNextPlayer(p);
  for (i = 0; i < numberOfPlayers-1; i++)
   {
    /* Skip for automated players */
    if (KgetPlayerType(next) == AUTOMATED)
     {
      next = KgetNextPlayer(next);
      continue;
     }

    lock = KgetLockForPlayer(next);

    if (lock == NULL)
      return(MISCERROR);

    pthread_mutex_lock(lock);

    packet.type = CHALLENGEREQUEST;

    /* Send the request */

    if (write(next->playerIDsend,&packet,sizeof(GeneralPacket)) < 0)
     {
      perror("Write failed\n");
      exit(1);
     }

 
    pthread_mutex_unlock(lock);
    next = KgetNextPlayer(next);
   }
  return(OK);
 }

/*----------------------------------------------------*/


int
KsendGameFinished()
 {
  /* Debugged by Navid Azizi on October 4th */

  KPlayer *next;
  KPlayer *winner;
  WinnerPacket packet;
  int i;
  int maxscore;
  
  packet.numberOfPlayers = numberOfPlayers;

  maxscore = KgetPlayerScore(currentPlayer);
  winner = currentPlayer;
  
  packet.pid[0] = currentPlayer->playerID;
  packet.score[0] = currentPlayer->score;


  next = KgetNextPlayer(currentPlayer);

  for (i = 0; i < numberOfPlayers-1; i++)
   {
    packet.pid[i+1] = next->playerID;
    packet.score[i+1] = next->score;
    
    if (KgetPlayerScore(next) > maxscore)
     {
      maxscore = KgetPlayerScore(next);
      winner = next;
     }
    next = KgetNextPlayer(next);
   }

  /* Create packet */
  packet.type = WINNER;
  packet.winner = winner->playerID;
      

  /* For numberof players send out winner packet */
  for (i = 0; i < 4; i++)
   {
    if (i == 0)
      next = player1;
    else if (i == 1)
      next = player2;
    else if (i == 2)
      next = player3;
    else if (i == 3)
      next = player4;

    /* Only send to human players */
    if (KgetPlayerType(next) != HUMAN)
      continue;

    /* Send the request */
  
    if (write(next->playerIDsend,&packet,sizeof(GeneralPacket)) < 0)
     {
      perror("Write failed\n");
      exit(1);
     }

   } 
  return(OK);
 }

/*----------------------------------------------------*/

int
KsendPlayerResign(KPlayer *p)
 {
  /* Debugged by Navid Azizi on October 4th */

  /* This function sends a packet to every player other than p indicating that it 
     player p has resigned
   * Pre: p is the player resigning
   * Post: OK is returned on success, and MISCERROR on failure */


  KPlayer *next;
  pthread_mutex_t *lock;
  ResignPacket packet;
  int i;

  /* Check to see if they are the current player */
  if (currentPlayer != p)
    return(NOTCURRENTPLAYER);

  /* Set up packet */
  packet.type = PLAYERHASRESIGNED;
  packet.resigned = p->playerID;


  /* For numberof players - 1 send out a request */

  next = KgetNextPlayer(p);

  /* This is numberOfPlayers because p has already resigned at the moment */
  for (i = 0; i < numberOfPlayers; i++)
   {
    /* Skip for automated players */
    if (KgetPlayerType(next) == AUTOMATED)
     {
      next = KgetNextPlayer(next);
      continue;
     }

    lock = KgetLockForPlayer(next);

    if (lock == NULL)
      return(MISCERROR);

    pthread_mutex_lock(lock);

    /* Send the request */


    if (write(next->playerIDsend,&packet,sizeof(GeneralPacket)) < 0)
     {
      perror("Write failed\n");
      exit(1);
     }

    pthread_mutex_unlock(lock);

    next = KgetNextPlayer(next);
   }
  return(OK);
 }

/*----------------------------------------------------*/

int
KsendChallengeAccept(KPlayer *p)
 {
  /* Debugged by Navid Azizi on October 4th */

  /* This function sends a packet to every player saying that player p's move was
     successfully challenged
   * Pre: p is the current player that has been challenged successfully
   * Post: OK is returned on success, and MISCERROR on failure */


  KPlayer *next;
  pthread_mutex_t *lock;
  ChallengePacket packet;
  int i;
  KBMove *theMove;



  /* Check to see if they are the current player */
  if (currentPlayer != p)
    return(NOTCURRENTPLAYER);

  next = p;


  theMove = KLastMove();
  
  if ((KHowManyMoves() == 0))
    KsetLastMoveNULL();


  /* Set up packet */
  packet.type = SUCCESSFULLCHALLENGE;
  packet.playerID = p->playerID;
  bcopy(theMove,&(packet.theMove),sizeof(KBMove));


  /* For numberof players send out a request */
  for (i = 0; i < numberOfPlayers; i++)
   {

    /* Skip for automated players */
    if (KgetPlayerType(next) == AUTOMATED)
     {
      next = KgetNextPlayer(next);
      continue;
     }

    lock = KgetLockForPlayer(next);


    if (lock == NULL)
      return(MISCERROR);


    pthread_mutex_lock(lock);

    /* Send the request */

    if (write(next->playerIDsend,&packet,sizeof(GeneralPacket)) < 0)
     {
      perror("Write failed\n");
      exit(1);
     }

    pthread_mutex_unlock(lock);
    next = KgetNextPlayer(next);
   }
   
  return(OK);
 }

/*----------------------------------------------------------*/

int
KsendPlayerMove(KPlayer *p)
 {
  /* This function sends a packet to every player other than p indicating that it
     player p has played a move
   * Pre: p is current and has just completed a move
   * Post: OK is returned on success, and MISCERROR on failure */


  KPlayer *next;
  pthread_mutex_t *lock;
  MoveCompletedPacket packet;
  int i;
  KBMove *theMove;

  /* Check to see if they are the current player */
  if (currentPlayer != p)
    return(NOTCURRENTPLAYER);

  theMove = KLastMove();

  /* Set up packet */
  if (theMove->type == SWAP)
    packet.type = SMOVECOMPLETED;
  else
    packet.type = BMOVECOMPLETED;
  packet.playerID = p->playerID;
  bcopy(theMove,&(packet.theMove),sizeof(KBMove));


  /* For numberof players - 1 send out a request */
  for (i = 0; i < 4; i++)
   {
    if (i == 0)
      next = player1;
    else if (i == 1)
      next = player2;
    else if (i == 2)
      next = player3;
    else if (i == 3)
      next = player4;

    /* Only send to human players */
    if ((KgetPlayerType(next) != HUMAN) || (next == p))
      continue;

    lock = KgetLockForPlayer(next);

    if (lock == NULL)
      return(MISCERROR);

    pthread_mutex_lock(lock);

    /* Send the request */

    if (write(next->playerIDsend,&packet,sizeof(GeneralPacket)) < 0)
     {
      perror("Write failed\n");
      exit(1);
     }

 
    pthread_mutex_unlock(lock);
    next = KgetNextPlayer(next);
   }
  return(OK);
 }

/*----------------------------------------------------------*/

int
KsendGameStarted(KPlayer *h)
 {

  KPlayer *next;
  pthread_mutex_t *lock;
  GameStartedPacket packet;
  int i;

  /* Create packet */


  packet.type = GAMENOWSTARTED;

  next = currentPlayer;

  /* For numberof players send out a request */
  for (i = 0; i < numberOfPlayers; i++)
   {
    /* Skip for automated players */
    if (KgetPlayerType(next) == AUTOMATED)
     {

      next = KgetNextPlayer(next);
      continue;
     }


    lock = KgetLockForPlayer(next);

    if (lock == NULL)
      return(MISCERROR);

    pthread_mutex_lock(lock);

    /* Send the request */
    packet.pid = next->playerID;


    if (write(next->playerIDsend,&packet,sizeof(GeneralPacket)) < 0)
     {
      perror("Write failed\n");
      exit(1);
     }

    pthread_mutex_unlock(lock);
    next = KgetNextPlayer(next);
   }

  return(OK);
 }



int
KsendWholeRack(KPlayer *h)
 {

  KPlayer *next;
  pthread_mutex_t *lock;
  TrayPacket packet;
  KTile *t;
  int i;
  int j;

  /* Create packet */
  packet.type = NEWTILES;

  next = currentPlayer;

  /* For numberof players send out a request */

  for (i = 0; i < numberOfPlayers; i++)
   {
    /* Skip for automated players */
    if (KgetPlayerType(next) == AUTOMATED)
     {
      next = KgetNextPlayer(next);
      continue;
     }

    lock = KgetLockForPlayer(next);

    if (lock == NULL)
      return(MISCERROR);

    pthread_mutex_lock(lock);
	
	j = 0;
	t = next->rack->Tiles;
    /* Take a tile out of the bag and place in rack */
    while (t != NULL)
     {
      packet.letters[j] = t->letter;
      packet.scores[j] = t->score;
	  t = t->link;
      j++;
     }
    packet.numberOfTiles = j;

    /* Send the request */
    if (write(next->playerIDsend,&packet,sizeof(GeneralPacket)) < 0)
     {
      perror("Write failed\n");
      exit(1);
     }

    pthread_mutex_unlock(lock);
    next = KgetNextPlayer(next);
   }

  return(OK);
 }









