#include "internal.h"
#include <strings.h>

/*-----------------------*/
/* Global Variables      */
/*-----------------------*/

extern int             sd;
extern int             port_to_pci;
extern int             noMoreGame;
extern KPlayer         *currentPlayer;
extern KPlayer         *player1;
extern KPlayer         *player2;
extern KPlayer         *player3;
extern KPlayer         *player4;
extern KTileList       *Bag;
extern KPlayer         *host;

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_mutex_t hostLock;

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 int             gameRestored;

extern sem_t           finishedGettingPlayers;
extern sem_t           finishedCurrentPlayerMove;
extern sem_t           waitForChallenge;


void
printGameState()
 {
  KGridRef pos;
  int    i,j;


  printf("Printing Bag State\n");
  KprintList(Bag);
  printf("Printing Player States\n");

  if (player1 != NULL)
   {
    printf("Player1\n");
    KprintPlayer(player1);
   }
  if (player2 != NULL)
   {
    printf("Player2\n");
    KprintPlayer(player2);
   }
  if (player3 != NULL)
   {
    printf("Player3\n");
    KprintPlayer(player3);
   }
  if (player4 != NULL)
   {
    printf("Player4\n");
    KprintPlayer(player4);
   }

  printf("Printing Board States\n");

  for (i = 0; i < LENGTH; i++)
   {
    for (j = 0; j < LENGTH; j++)
     {
      pos.x = i;
      pos.y = j;
      if (KEmptySquare(pos))
       printf(" ");
      else
       printf("%c",KTileSquare(pos));
     }
    printf("\n");
   }   
  
 }


void *
KplayerThread(void *p1)
 {
  GeneralPacket getPacket;
  GeneralPacket sendPacket;
  int packet_size;
  int temp;
  KPlayer *p = (KPlayer *)p1;
  struct hostent      *hp;
  struct sockaddr_in  server;
  struct sockaddr_in  sin;
  int len=sizeof(sin);

  /* Allow other threads to kill this one */
  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);


  packet_size = sizeof(GeneralPacket);
  
  /* Create a socket */   
  if ((p->playerIDsend = socket(AF_INET, SOCK_STREAM, 0)) == -1)
   {
    perror("Can't create socket\n");
    noMoreGame = 1;
   }

  /* Get and store server's info */
  bzero((char *)&server, sizeof(struct sockaddr_in));
    
  server.sin_family = AF_INET;
  server.sin_port = port_to_pci;


  if (getpeername(p->playerID,(struct sockaddr *)&sin,&len) < 0)
   {
    perror("Get peername error\n");
	exit(1);
   }
  
  if ((hp = gethostbyaddr((char *)&sin.sin_addr,sizeof(sin.sin_addr),AF_INET)) == NULL)
   {
    perror("Can't get server's address\n");
    exit(1);
   }
   
  bcopy((char *)hp->h_addr,(char *)&server.sin_addr.s_addr,hp->h_length);

  /* Connect to server */
  if (connect(p->playerIDsend, (struct sockaddr *)&server, sizeof(server)) == -1)
   {
    perror("Can't connect to client\n");
    exit(1);
   }
 

  /* Get data from client */
  while (read(p->playerID,&getPacket,packet_size) > 0)
   {
 
    bzero(&sendPacket,sizeof(GeneralPacket));
/*------------------------------*/

    if (getPacket.type == NEWGAME)
     {
      /*printf("Got a NEWGAME PACKET\n");*/
     
      pthread_mutex_lock(&numberOfPlayersLock);
      pthread_mutex_lock(&hostLock);

      if ((host == NULL) && (gameStarted == 0) && (numberOfPlayers + numberOfAP>= MINPLAYERS))
       {
        host = p;  
        pthread_mutex_unlock(&hostLock);
     
        pthread_mutex_unlock(&numberOfPlayersLock);

        sem_post(&finishedGettingPlayers);
        sendPacket.type = OK;

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }

       }
      else
       {
	    pthread_mutex_unlock(&hostLock);
        if (numberOfPlayers < MINPLAYERS)
          sendPacket.type = NOTENOUGHPLAYERS;
        else
          sendPacket.type = GAMEALREADYSTARTED;           
        pthread_mutex_unlock(&numberOfPlayersLock);


        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }

       }
     }

/*------------------------------*/

    else if (getPacket.type == CREATEAUTOMATEDPLAYER)
     {
      /*printf("Got a AUTOMATEDPACKET PACKET\n");*/
      if (gameStarted == 0)
       {
        pthread_mutex_lock(&numberOfAPLock);
        numberOfAP++;
        pthread_mutex_unlock(&numberOfAPLock);

        sendPacket.type = CREATEAUTOMATEDPLAYERRETURN;

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }

       }
      else
       {
        sendPacket.type = GAMEALREADYSTARTED;

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }

       }
     }

/*------------------------------*/


    else if ((getPacket.type == SCOREINFO) || (getPacket.type == WHO) || (getPacket.type == PLAYERINFO))
     {
      /*printf("Got a SCOREINFO PACKET\n");*/
      /*if (gameStarted == 1)*/
	   
	  if (1)
       {
        temp = KgetPlayerInfo((PlayerPacket *)(&sendPacket));

        /*printf("Sending back SCOREINFO\n");*/

        /* Send the info back to the client */

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }

       }
      else
       {
        sendPacket.type = GAMENOTSTARTED;

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }

       }
     }

/*------------------------------*/

    else if (getPacket.type == CHALLENGE)
     {
      /*printf("Got CHALLENGE packet\n");*/
      if ((gameStarted == 1) && (KgetPlayerStatus(p1) != RESIGNED))
       {
        pthread_mutex_lock(&canChallengeLock);
        if (canChallenge == 1)
         {

          temp = KChallenge(currentPlayer);


          if (temp == UNSUCCESSFULLCHALLENGE)
           {

            temp = KgetPlayerLostTurn(p);
            KsetPlayerLostTurn(p,temp+1);
            sendPacket.type = temp;
            

            if (write(p->playerID,&sendPacket,packet_size) < 0)
             {
              perror("Write failed\n");
              exit(1);
             }


            pthread_mutex_unlock(&canChallengeLock);
           }
          
          /* Challenge was successful */
          else
           {
		    pthread_cancel(timerTid);
		   
     		sendPacket.type = OK;
            

            if (write(p->playerID,&sendPacket,packet_size) < 0)
             {
              perror("Write failed\n");
              exit(1);
             }
		   
            canChallenge = 0;
            pthread_mutex_unlock(&canChallengeLock);
            KsendChallengeAccept(currentPlayer);
            sem_post(&waitForChallenge);
           }
         }
        else
         {
          pthread_mutex_unlock(&canChallengeLock);
          sendPacket.type = CANTCHALLENGENOW;


          if (write(p->playerID,&sendPacket,packet_size) < 0)
           {
            perror("Write failed\n");
            exit(1);
           }

         }
       }
      else
       {
        sendPacket.type = GAMENOTSTARTED;


        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }

       }
     }

/*--------------------------------*/

    else if (getPacket.type == SHOWTRAY)
     {
      /*printf("Got a SHOWTRAY PACKET\n");*/
      if (gameStarted == 1)
       {
        temp = KgetPlayerTray(p,(TrayPacket *)(&sendPacket));

        /* Send the info back to the client */

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }


       }
      else
       {
        sendPacket.type = GAMENOTSTARTED;

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }

       }
     }

/*--------------------------------*/

    else if (getPacket.type == TRYMOVE)
     {
      /*printf("Got TRYMOVE packet\n");*/
      if (gameStarted == 1)
       {
        ScoreReturnPacket *tempPacket;

        temp = KtryMove(p,(BMovePacket *)(&getPacket));

        sendPacket.type = SCOREINFORETURN;
        tempPacket = (ScoreReturnPacket *)(&sendPacket);
        tempPacket->score = temp;

        /*printf("Sending back TRYMOVE packet with score %i\n", temp);*/

        /* Send the info back to the client */

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }

       }
      else
       {
        sendPacket.type = GAMENOTSTARTED;

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }

       }
     }


/*------------------------------*/

    else if (getPacket.type == SHOWBOARD)
     {
      /*printf("Got a SHOWBOARD PACKET\n");*/
	  if(1)
      /*if (gameStarted == 1)*/
       {
        temp = KshowBoard((BoardPacket *)(&sendPacket));

        sendPacket.type = SHOWBOARDRETURN;
		
		/*printf("Sending SHOWBOARD PACKET\n"); */

        /* Send the info back to the client */

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }

       }
      else
       {
        sendPacket.type = GAMENOTSTARTED;

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }

       }
     }


/*------------------------------*/


    else if (getPacket.type == BMOVE)
     {
      /*printf("Got a BMOVE packet\n");*/
      if (gameStarted == 1)
       {

        pthread_mutex_lock(&currentPlayerLock);

        temp = KboardMove(p,(BMovePacket *)(&getPacket));

        pthread_mutex_unlock(&currentPlayerLock);

        sendPacket.type = temp;

        /* Send the info back to the client */
		

		

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }





        if (temp == OK)
          sem_post(&finishedCurrentPlayerMove);

       }
      else
       {
        sendPacket.type = GAMENOTSTARTED;

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }

       }
     }

/*------------------------------*/


    else if (getPacket.type == SMOVE)
     {
      /*printf("Got a SMOVE packet\n");*/
      if (gameStarted == 1)
       {
        pthread_mutex_lock(&currentPlayerLock);
		
        if ((Bag->length < 7) && ((SMovePacket *)&getPacket)->theMove.numMoves > 0)
		 {
		  temp = NOTENOUGHTILES;
          sendPacket.type = NOTENOUGHTILES;
		  pthread_mutex_unlock(&currentPlayerLock);
		 }
        else
         {  

          temp = KswapMove(p,(SMovePacket *)(&getPacket));

          pthread_mutex_unlock(&currentPlayerLock);

          sendPacket.type = temp;
         } 

        /* Send the info back to the client */

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }


        if (temp == OK)
         {
          lastPersonNotBMove = 1;
          sem_post(&finishedCurrentPlayerMove);
         }

       }
      else
       {
        sendPacket.type = GAMENOTSTARTED;
        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }
       }
     }

/*------------------------------*/


    else if (getPacket.type == RESIGN)
     {
      if (gameStarted == 1)
       {
        /*printf("Got a RESIGN packet\n");*/
        pthread_mutex_lock(&currentPlayerLock);
        temp = Kresign(p);
        pthread_mutex_unlock(&currentPlayerLock);


        sendPacket.type = temp;


        /* Send the info back to the client */

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }


        if (temp == OK)
         {
          KsendPlayerResign(p);
          lastPersonNotBMove = 1;
          sem_post(&finishedCurrentPlayerMove);
         }

       }
      else
       {
        sendPacket.type = GAMENOTSTARTED;

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }

       }
     }

/*------------------------------*/

    else if (getPacket.type == SAVEGAME)
     {
      /*printf("Got a SAVEGAME packet\n");*/
      if (gameStarted == 1)
       {
        pthread_mutex_lock(&currentPlayerLock);

        temp = KsaveGame(p);

        pthread_mutex_unlock(&currentPlayerLock);

        sendPacket.type = temp;

        /* Send the info back to the client */

        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }
       }
      else
       {
        sendPacket.type = GAMENOTSTARTED;
        if (write(p->playerID,&sendPacket,packet_size) < 0)
         {
          perror("Write failed\n");
          exit(1);
         }
       }
     }

/*------------------------------*/

    else if (getPacket.type == RESTOREGAME)
     {
      printf("Got a RESTOREGAME packet\n");

      pthread_mutex_lock(&currentPlayerLock);

		
      temp = KrestoreGame(p);

      pthread_mutex_unlock(&currentPlayerLock);

      sendPacket.type = temp;


      /* Send the info back to the client */

      if (write(p->playerID,&sendPacket,packet_size) < 0)
       {
        perror("Write failed\n");
        exit(1);
       }


      if (temp == OK)
       {
        lastPersonNotBMove = 1;
        gameRestored = 1;

        KsendGameStarted(p);
		KsendWholeRack(p);
        sem_post(&finishedCurrentPlayerMove);
       }

     }

/*------------------------------*/

   }
  return(NULL);
 }


