#include "serial_communications.h"

/** @name list.c 

    This file contains functions to handle all lists.

    @author Daniel Storey, UWA, 1998
    @version 1.0   */

/*@{*/

/*************************************************************************/
/** Increment the send field of a packet in the queue.
    Increment the value of the "send" field of a packet in a certain location in the queue.

    @param q Queue*, a pointer to the queue structure.
    @param item_number int, the item number of the packet in the queue.
    @return void. */
/*************************************************************************/
void increment_packet_in_queue(Queue *q, int item_number)
{
  q->item[item_number].packet.sent++;
  
  return;
}

/*************************************************************************/
/** Initialise the queue.
    Increment the variables involved in a queue. Set all index values to -1 (invalid).

    @param q Queue*, a pointer to the queue structure.
    @return void. */
/*************************************************************************/
void initialise_queue(Queue *q)
{
  int i;
  
  for(i=0; i<QUEUE_ELEMENTS; i++) {
    q->item[i].index = -1;
  }
  q->cnt = 0;
}

/*************************************************************************/
/** Match the packet number with a packet in the queue and remove that entry.
    Find a packet in the queue with a packet number the same as that which has been passed, then set the value of the index to -1 (invalid).

    @param q Queue*, a pointer to the queue structure.
    @param packet_number char, the character that represents the number of a particular packet in the queue.
    @return int, 0 if the operation has been sucessfull, -1 if the packet has not been found. */
/*************************************************************************/
bool match_and_remove(Queue *q, char packet_number)
{
  int i;
  
  for(i=0; i<QUEUE_ELEMENTS; i++) {
    if(q->item[i].index!=-1) {
      if(q->item[i].packet.number[0] == packet_number) {
	q->item[i].index = -1;
	q->cnt--;
	return TRUE;
      }
    }
  }
  return FALSE;
}

/*************************************************************************/
/** Remove a packet in the queue.
    Set the index value of a packet in the specified location in the queue to -1 (invalid).

    @param q Queue*, a pointer to the queue structure.
    @param item_number int, the position number of the packet that is to be removed.
    @return Packet, the packet that has been removed. */
/*************************************************************************/
void remove_from_queue(Queue *q, int item_number)
{
  q->item[item_number].index = -1; /* Nullify entry */
  q->cnt--;
}


bool valid_queue_entry(Queue *q, int item_number)
{
  return (q->item[item_number].index!=-1); 
}

/*************************************************************************/
/** Get a packet from the queue.
    Get a packet from the specified location in the queue.

    @param q Queue*, a pointer to the queue structure.
    @param item_number int, the position number of the packet that is to be retrieved.
    @return Packet, the packet that has been retrieved. */
/*************************************************************************/
Packet get_from_queue(Queue *q, int item_number)
{
  return q->item[item_number].packet;
}

/*************************************************************************/
/** Add a packet to the queue.
    Find an empty position in the queue, then add the packet that has been passed to this location. Print an error to the screen if there are no positions available.

    @param q *Queue, a pointer to the queue structure.
    @param p Packet, the packet that is to be queued.
    @return int, always 0. */
/*************************************************************************/
int enqueue(Queue *q, Packet p)
{
  int i = 0;

  if(q->cnt >= QUEUE_ELEMENTS) {
    LCDPrintf("Comms Error: Q len\n");
    return -1;
  }
  q->cnt++;
  
  /* find a queue position without an entry */
  while(q->item[i].index!=-1)
    i++;
  q->item[i].packet = p;
  q->item[i].index = q->cnt;
  
  return 0;
}

/*************************************************************************/
/** Remove a packet from the end of the queue.
    Remove a packet from the end of the queue and return it.  Print an error if a request has been made from an empty queue.

    @param q *Queue, a pointer to the queue structure.
    @return Packet, the packet that has been dequeued. */
/*************************************************************************/
Packet dequeue(Queue *q)
{
  Packet p;
  int i;

  if(q->cnt == 0)
    LCDPrintf("Request from empty q\n");
  for(i=0; i<QUEUE_ELEMENTS; i++) {
    if(q->item[i].index!=-1) {
      q->cnt--;
      q->item[i].index = -1;
      return q->item[i].packet;
    }
  }
  
  return p;
}

/*************************************************************************/
/** Return the length of the queue.
    Return the length of the queue.

    @param q *Queue, a pointer to the queue structure.
    @return int, the length of the queue. */
/*************************************************************************/
int queue_length(Queue *q)
{
  return q->cnt;
}

bool empty(Queue *q)
{
  return(queue_length(q)==0);
}

/*************************************************************************/
/** Initialise a special queue.
    Initialise a special queue.

    @param q *Special_Queue, a pointer to the queue structure.
    @return void. */
/*************************************************************************/
void initialise_special_queue(Special_Queue *q)
{
  int i;
  
  for(i=0; i<SPECIAL_QUEUE_ELEMENTS; i++) {
    q->item[i].index = -1;
  }
  q->cnt = 0;
}

/*************************************************************************/
/** Add a packet to the special queue.
    Find an empty position in the queue, then add the packet that has been passed to this location. Print an error to the screen if there are no positions available.

    @param q *Special_Queue, a pointer to the queue structure.
    @param p Packet, the packet that is to be queued.
    @return int, always 0. */
/*************************************************************************/
int special_enqueue(Special_Queue *q, Packet p)
{
  int i = 0;

  if(q->cnt >= SPECIAL_QUEUE_ELEMENTS) {
    LCDPrintf("Comms Error: Spec Q len\n");
    return -1;
  }
  q->cnt++;
  
  /* find a queue position without an entry */
  while(q->item[i].index!=-1)
    i++;
  q->item[i].packet = p;
  q->item[i].index = q->cnt;
  
  return 0;
}

/*************************************************************************/
/** Get a packet from the special queue.
    Get a packet from the end of the special queue.

    @param q Queue*, a pointer to the special queue structure.
    @return Packet, the packet that has been retrieved. */
/*************************************************************************/
Packet special_dequeue(Special_Queue *q)
{
  Packet p;
  int i;

  if(q->cnt == 0)
    LCDPrintf("Request from empty q\n");
  for(i=0; i<SPECIAL_QUEUE_ELEMENTS; i++) {
    if(q->item[i].index != -1) {
      q->cnt--;
      q->item[i].index = -1;
      return q->item[i].packet;
    }
  }
  
  return p;
}

/*************************************************************************/
/** Get the length of a special queue.
    Get the length of a special queue.

    @param q Special_Queue*, a pointer to the special queue structure.
    @return int, the length of the queue. */
/*************************************************************************/
int special_queue_length(Special_Queue *q)
{
  return q->cnt;
}

/*************************************************************************/
/** Initialise a string queue.
    Initialise a string queue.

    @param q *String_Queue, a pointer to the queue structure.
    @return void. */
/*************************************************************************/
void initialise_string_queue(String_Queue *q)
{
  int i;
  
  for(i=0; i<STRING_QUEUE_ELEMENTS; i++) {
    q->string_item[i].index = -1;
  }
  q->cnt = 0;

  return;
}

/*************************************************************************/
/** Add a data string to the string queue.
    Find an empty position in the queue, then add the string to this location. Print an error to the screen if there are no positions available.

    @param q *String_Queue, a pointer to the queue structure.
    @param string string, the string that is to be queued.
    @return int, always 0. */
/*************************************************************************/
int string_enqueue(String_Queue *q, char* string, char* address)
{
  int i = 0;

  if(q->cnt >= STRING_QUEUE_ELEMENTS) {
    LCDPrintf("Comms Error: Str Q len\n");
    return -1;
  }
  q->cnt++;
  
  /* find a queue position without an entry */
  while(q->string_item[i].index!=-1)
    i++;
  string_copy(&q->string_item[i].string[0], string);
  string_copy(&q->string_item[i].address[0], address);
  q->string_item[i].index = q->cnt;
  
  return 0;
}

/*************************************************************************/
/** Get a data string from the string queue.
    Get a packet from the end of the string queue.

    @param q Queue*, a pointer to the string queue structure.
    @param string string, a string to which the queued data is to be written.
    @param address char* a pointer to which the queued address data is to be writen.
    @return char*, a pointer to the beginning of the string that has been dequeued. */
/*************************************************************************/
int string_dequeue(String_Queue *q, char *string, char* address)
{
  int i;

  if(q->cnt == 0)
    LCDPrintf("Request from empty q\n");
  for(i=0; i<STRING_QUEUE_ELEMENTS; i++) {
    if(q->string_item[i].index != -1) {
      q->cnt--;
      q->string_item[i].index = -1;
      string_copy(string, q->string_item[i].string);
      string_copy(address, q->string_item[i].address);

      /* ok */
      return 0;
    }
  }
  string[0] = '\0';

  /* error */
  return -1;
}

/*************************************************************************/
/** Get the length of a string queue.
    Get the length of a string queue.

    @param q String_Queue*, a pointer to the string queue structure.
    @return int, the length of the queue. */
/*************************************************************************/
int string_queue_length(String_Queue *q)
{
  return q->cnt;
}


void initialise_recframe_queue(RecFrame_Queue *q)
{
  int i;
  
  for(i=0; i<RECENT_FRAME_QUEUE_ELEMENTS; i++) {
    q->recframe_item[i].index = -1;
    q->recframe_item[i].age = 0;
  }
  q->cnt = 0;

  return;
}

int recframe_dequeue(RecFrame_Queue *q)
{
  int i;

  if(q->cnt == 0)
    LCDPrintf("Request from empty q\n");
  for(i=0; i<RECENT_FRAME_QUEUE_ELEMENTS; i++) {
    if(q->recframe_item[i].index != -1) {
      q->cnt--;
      q->recframe_item[i].index = -1;
      /* ok */
      return 0;
    }
  }

  /* error */
  return -1;
}

int recframe_enqueue(RecFrame_Queue *q, char* number, char* address)
{
  int i = 0;

  if(q->cnt >= RECENT_FRAME_QUEUE_ELEMENTS) {
    recframe_dequeue(q);
  }
  q->cnt++;
  
  /* find a queue position without an entry */
  while(q->recframe_item[i].index!=-1)
    i++;
  q->recframe_item[i].number = *number;
  strncpy(q->recframe_item[i].address, address, ADDRESS_LEN);
  q->recframe_item[i].age = 0;
  q->recframe_item[i].index = q->cnt;
  
  return 0;
}

void recframe_increment_age(RecFrame_Queue *q)
{
  int i;
  
  for(i=0; i<RECENT_FRAME_QUEUE_ELEMENTS; i++) {
    if(q->recframe_item[i].index!=-1) {
      q->recframe_item[i].age++;
      if(q->recframe_item[i].age>MAXIMUM_RECEIVED_FRAME_AGE)
	q->recframe_item[i].index = -1;
    }
  }
}

bool recframe_match(RecFrame_Queue *q, char* number, char* address)
{
  int i;
  
  for(i=0; i<RECENT_FRAME_QUEUE_ELEMENTS; i++) {
    if(q->recframe_item[i].index!=-1)
      if(q->recframe_item[i].number==*number)
	if(strncmp(address, q->recframe_item[i].address, ADDRESS_LEN)==0)
	  return TRUE;
  }
  return FALSE;
}

int recframe_queue_length(RecFrame_Queue *q)
{
  return q->cnt;
}


/* main() */
/* { */
/*   Queue q; */
/*   Packet p; */
/*   int i, j; */
/*   char string[100]; */
  
/*   initialise_queue(&q); */
  
  
/*   strncpy(p.data, "Daniel", 6); */
/*   enqueue(&q, p); */
/*   strncpy(p.data, "Second", 6); */
/*   enqueue(&q, p); */
/*   strncpy(p.data, "Third Entry", 11); */
/*   enqueue(&q, p); */
/*   strncpy(p.data, "Quadrouple Entry", 16); */
/*   enqueue(&q, p); */

/*   LCDPrintf("Count = %d\n", q.cnt); */
  
/*   for(i=0; i<4; i++) { */
/*     p = dequeue(&q); */
/*     LCDPrintf("Entry %d: '%s', count = %d\n", i, p.data, q.cnt); */
/*   } */

/*   strncpy(p.data, "Second", 6); */
/*   enqueue(&q, p); */
/*   strncpy(p.data, "Third Entry", 11); */
/*   enqueue(&q, p); */
/*   strncpy(p.data, "Quadrouple Entry", 16); */
/*   enqueue(&q, p); */

/*   for(j=0; j<QUEUE_ELEMENTS; j++) { */
/*     if(valid_queue_entry(&q, j)) { */
/*       increment_packet_in_queue(&q, j); */
/*       p = get_from_queue(&q, j); */
/*       if(p.data[0] == 'D') { */
/* 	remove_from_queue(&q, j); */
/* 	LCDPrintf("Err: '%s'\n", p.data); */
/*       } */
/*     } */
/*   } */
/*   while(q.cnt!=0) { */
/*     p = dequeue(&q); */
/*     LCDPrintf("Entry %d: '%s', count = %d\n", i, p.data, q.cnt); */
/*     } */
/*     } */







