#include "internal.h"

/*-----------------------*/
/* Global Variables      */
/*-----------------------*/

extern int             sd;
extern KPlayer          *currentPlayer;
extern KPlayer          *player1;
extern KPlayer          *player2;
extern KPlayer          *player3;
extern KPlayer          *player4;
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_mutex_t writeLock;

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;


void
KprintTile(KTile *t)
 {
  /* Print info about tile */
  printf("[%c, %i]", t->letter, t->score);
 }

/*--------------------------------------------------------------*/

void
KprintList(KTileList *group)
 {
  /* Prints info about list and tiles in list */

  KTile *current;

  if (group == NULL)
    return;

  /* Print group type */
  if (group->type == RACK)
    printf("Rack");
  else if (group->type == BAG)
    printf("Bag");
  else

  printf("Unknown List Type");
  printf(" %i\n",group->length);

  current = group->Tiles;

  while (current != NULL)
   {
    printf(" ");
    KprintTile(current);
    current = current -> link;
   }

  printf("\n");
  return;
 }

/*--------------------------------------------------------------*/

KTileList *
KgetQueue(KTile *t)
 {
  /* Determines in which list a tile is in
   * Pre: t must be defined
   * Post: Returns a pointer to the head or NULL if t does not exist */


  if (t != NULL)
    return(t->inlist);
  return(NULL);
 }

/*--------------------------------------------------------------*/

KTile *
KallocTile(char letter, int score)
 {
  /* Builds a new KTile
   * Pre:  letter, and score must be defined
   * Post: Returns a pointer to the new node */

  KTile *newTile;  /* A new node */

  /* Allocate space for the new node */
  newTile = (KTile *)malloc(sizeof(KTile));
  if (newTile == NULL)
    printf("Error in allocTile");
  else
   {
    newTile->letter = letter;
    newTile->score  = score;
    newTile->link   = NULL;
    newTile->inlist = NULL;
   }
  return(newTile);
 }

/*--------------------------------------------------------------*/

int
KdeallocTile(KTile *t)
 {
  /* Frees up the memory taken by a tile
   * Pre: *t must be defined
   * Post: Returns OK if success, or MISCERROR if *t points to nothing */

  if (t == NULL)
    return(MISCERROR);

  /* Be sure that the node is not in any list */
  if (t -> inlist != NULL)
    KdequeueTile(t);

  /* Free the memory */
  free(t);
  t = NULL;
  return(OK);
 }

/*--------------------------------------------------------------*/

int
KgetTileScore(KTile *t)
 {
  /* Returns the score of a KTile
   * Pre: *t must be defined
   * Post: Returns score of KTile if KTile exists, otherwise returns MISCERROR */

  if (t != NULL)
    return(t -> score);
  else
    return(MISCERROR);
 }

/*--------------------------------------------------------------*/

char
KgetTileLetter(KTile *t)
 {
  /* Returns the letter of a KTile
   * Pre: *t must be defined
   * Post: Returns letter of a KTile if t exists, otherwise returns MISCERROR*/

  if (t != NULL)
    return(t -> letter);
  else
    return(MISCERROR);
 }


/*--------------------------------------------------------------*/

KTileList *
KcreateGroup(KListType type)
 {
  /* Allocates and properly initializes a group structure
   * Pre: type must be defined
   * Post: Returns a pointer the new list structure or NULL */

  KTileList *newGroup=NULL;     /* A new head */

  if ((type == BAG) || (type == RACK))
   {
    /* Allocate space for the new head */
    newGroup = (KTileList *)malloc(sizeof(KTileList));
    if (newGroup == NULL)
      printf("\nError in createGroup");
    else
     {
      /* Initialize members of the structure */
      newGroup -> length = 0;
      newGroup -> type  = type;
      newGroup -> Tiles = NULL;
     }
   }
  else
    printf("Invalid type\n");
  return(newGroup);
 }

/*--------------------------------------------------------------*/


KTile *
KdequeueHead(KTileList *group)
 {
  /* Dequeues the KTile at the head of list and returns a pointer to it
   * Pre: *group must be defined
   * Post: Returns a pointer to the first KTile or NULL */

  KTile *t;   /* KTile to be returned */

  /* Be sure that a TD exits in the list */
  if ((group != NULL) && (group->Tiles != NULL))
   {
    /* Take the first TD out of the list and return it */
    t = group->Tiles;
    group->Tiles = group->Tiles->link;
    t->inlist = NULL;
    t->link = NULL;
    group->length = group->length - 1;
    return(t);
   }
  else
    return(NULL);
 }

/*--------------------------------------------------------------*/

int
KdestroyWholeList(KTileList *group)
 {
  /*  Destroys list, and frees memory
   *  Pre: list must be defined.
   *  Post:  Returns OK with *list being NULL*/

  KTile *temp1;

  /* List is already not allocated */
  if (group == NULL)
    return(OK);

  /* List is not empty, dequeue list and dealloc the TD's until list is empty */
  if (group -> Tiles != NULL)
   {
    while (group -> Tiles != NULL)
     {
      temp1 = KdequeueHead(group);
      KdeallocTile(temp1);
     }
    free(group);
    group = NULL;
    return(OK);
   }

  /* List was empty, free it and return */
  else
   {
    free(group);
    group = NULL;
    return(OK);
   }
 }
/*--------------------------------------------------------------*/


int
KdestroyList(KTileList *group)
 {
  /*  Destroys list, and frees memory if group is empty
   *  Pre: group must be defined.
   *  Post:  Returns MISCERROR if list is not empty, and OK otherwise. with *list being NULL*/

  /* List is already not allocated */
  if (group == NULL)
    return(OK);

  /* List is not empty */
  if (group -> Tiles != NULL)
   {
    return(MISCERROR);
   }

  /* List was empty, free it and return */
  else
   {
    free(group);
    group = NULL;
    return(OK);
   }
 }
/*--------------------------------------------------------------*/

int
KnumberEnqueue(KTile *t, KTileList *group, int n)
 {
  /* Puts t n spaces into the group.
   * Pre: *t, *group amd n must be defined
   * Post: Returns MISCERROR if group, or t are are null, or if n is negative and OK otherwise.  */

  /* Check for invalid input */
  if ((group != NULL) && (t != NULL) && (n > 0))
   {

    /* Add the pd in the correct location, and set the inlist member */
    KaddTNumb(&(group->Tiles),t,n);
    t->inlist=group;
    (group->length)++;
    return(OK);
   }
  else
   {
    return(MISCERROR);
   }
 }

/*--------------------------------------------------------------*/

void
KaddTNumb(KTile **pT, KTile *t, int n)
 {
  /* Adds a new node to the list
   * Pre: **pTD, *newTD are defined.
   * A new node is added to **pTD */

  KTile *current = *pT;         /* A temporary pointer to a node */
  KTile *previous = *pT;        /* A temporary pointer to the node before current */
  int i;                        /* Priority of the PD to be inserted */

  /* Add the new node to its proper position in the link list */

  /* Search for the position to add the the new tile */
  for (i = 0; i < n; i++)
   {
    if (current != NULL)
     {
      previous = current;
      current = current->link;
     }
    else
     break;
   }

  /* List is empty or node to be added is the first one */
  if (current == *pT)
   {
    t -> link = current;
    *pT = t;
   }

  /* List is not empty and node to be added is not the first */
  else
   {
    t -> link = current;
    previous -> link = t;
   }
 }

/*--------------------------------------------------------------*/

int
KheadEnqueue(KTile *t, KTileList *group)
 {
  /* Enqueues *t at the head of the group
   * Pre: *t, *group must be defined
   * Post: Returns MISCERROR if the group is invalid and OK otherwise.  */

  KTile *temp; /* temp tile */

  /* Check for NULL inputs */
  if ((group != NULL) && (t != NULL))
   {
    /* Add the TD to the beginning of the list */
    temp = group->Tiles;
    group->Tiles = t;
    t->link = temp;
    t->inlist = group;
    group->length = group->length + 1;
    return(OK);
   }
  else
   {
    return(MISCERROR);
   }
 }

/*--------------------------------------------------------------*/

KTile *
KfindLetter(char c, KTileList *group)
 {
  /* Searches list for the first KTile with letter c
   * Pre: *group and c must be defined
   * Post: Returns a pointer to the KTile.  If the element cannot be found NULL is returned.  */

   KTile *tempPtr;       /* To traverse linked list */
   int found=0;         /* To indicate if the KTile was found */

   /* Check for valid inputs */
   if (group != NULL)
    {
     /* Go through list and search */
     tempPtr = group->Tiles;
     while ((tempPtr != NULL) && (found == 0))
      {
       if (tempPtr->letter == c)
         found = 1;
       else
         tempPtr = tempPtr -> link;
      }

     /* If found return the pointer */
     if (found == 1)
       return(tempPtr);
     else
      {
       /*printf("\nTile not found in FindLetter");*/
       return(NULL);
      }
    }
   else
    {
     return(NULL);
    }
 }

/*--------------------------------------------------------------*/

void
KdequeueTile(KTile *t)
 {
  /* Dequeues *t from whatever list it might be in, if it is in one.
   * Pre: *t must be defined
   * Post: the tile is removed from list */

  KTile *current;     /* pointer to node currently at */
  KTile *previous;    /* pointer to node previously at */

  /* Check for valid input */
  if (t == NULL)
    printf("\nTile is NULL");
  else if (t->inlist != NULL)
   {

    /* Initialize list value by going through inlist of pd */
    current = t->inlist->Tiles;
    previous = current;

    /* Traverse the list and search for pointer equivalency */
    while ((current != NULL) && (current != t))
     {
      previous = current;
      current = current -> link;
     }
   
    if (current != NULL)
     {
      /* t is the first element */
      if (current == previous)
       {

        /* Remove the node from the list */
        current -> inlist -> Tiles = current -> link;
        current -> link = NULL;
        (current->inlist->length)--;
        current -> inlist = NULL;
       }
      /* t is not the first element */
      else
       {
        /* Remove the node from the list */
        previous -> link = current -> link;
        current -> link = NULL;
        (current->inlist->length)--;
        current -> inlist = NULL;
       }
     }
    
   }
  else
    printf("\nTile is not in any list");
 }











