/**************************************************
OpengateM - MAC address authentication system 
 module to control queue 

  As address check by database is time consuming procedure,
  the recently checked addresses are cached.
  The cache is implemented with HashTable and Queue.
  Queue has data odrered by checked time, and
  controls the remove sequence.

Copyright (C) 2011 Opengate Project Team
Written by Yoshiaki Watanabe

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

Email: watanaby@is.saga-u.ac.jp
**************************************************/

#include "opengatemmng.h"

/* Queue (linked-list) for storing string-key stirng-data pair */
struct queueNode{
  char keyStr[WORDMAXLN];
  char dataStr[WORDMAXLN];
  struct queueNode *next;
};
static struct queueNode* queueTail=NULL;
static struct queueNode* queueHead=NULL;

/***************************************************/
/* initialize Queue (linked-list)                  */
/* Queue                                           */
/* HeadNode -> DataNode -> DataNode -> TailNode    */
/*  (dummy)                             (dummy)    */
/*   ^                                   ^         */
/*   queueHead                           queueTail */
/***************************************************/
int initqueue(void){

  char keyStr[WORDMAXLN];
  char dataStr[WORDMAXLN];

  /* if not exist, prepare head and tail nodes */
  if(queueHead==NULL){
    queueHead=(struct queueNode*)malloc(sizeof(struct queueNode));
    if(queueHead==NULL){
      err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
      terminateProg(0);
    }
    queueTail=(struct queueNode*)malloc(sizeof(struct queueNode));
    if(queueTail==NULL){
      err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
      terminateProg(0);
    }
    queueHead->keyStr[0]='\0';
    queueHead->dataStr[0]='\0';
    queueTail->keyStr[0]='\0';
    queueTail->dataStr[0]='\0';
    queueHead->next=queueTail;
    queueTail->next=NULL;
  }
  
  /* if exist, reset all */
  else{
    while(Dequeue(keyStr, dataStr))
      ;
  }
  return TRUE;
}

/****************************************/
/* Add data to the tail of Queue        */
/* keyStr,dataStr:(input)               */
/****************************************/
int enqueue(char* keyStr, char* dataStr){
  struct queueNode *newNode;

  /* if not prepared, error */
  if(queueHead==NULL){
    err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
    return FALSE;
  }

  /* add item after the tail and set it as new tail*/
  newNode=(struct queueNode*)malloc(sizeof(struct queueNode));
  if(newNode==NULL){
    err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
    terminateProg(0);
  }
  strlcpy(queueTail->keyStr, keyStr, WORDMAXLN);
  strlcpy(queueTail->dataStr, dataStr, WORDMAXLN);
  queueTail->next=newNode;
  queueTail=newNode;
  queueTail->keyStr[0]='\0';
  queueTail->dataStr[0]='\0';
  queueTail->next=NULL;
  return TRUE;
}

/**********************************************/
/* Get and remove data from the head of Queue */
/*  keyStr, dataStr:(output)                  */
/**********************************************/
int dequeue(char* keyStr, char* dataStr){

  /* set null string as default */
  keyStr[0]='\0';
  dataStr[0]='\0';

  /* if not prepared, error */
  if(queueHead==NULL){
    err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
    return FALSE;
  }
  else if(queueHead->next==NULL){
    err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
    return FALSE;  
  }

  /* if no data, return false */
  else if(queueHead->next==queueTail){
    return FALSE;
  }

  /* get item from the head */
  else {
    struct queueNode *temp;
    temp=queueHead->next;
    queueHead->next=temp->next;
    strlcpy(keyStr, temp->keyStr, sizeof(temp->keyStr));
    strlcpy(dataStr, temp->dataStr, sizeof(temp->dataStr));
    free(temp);
  }
  return TRUE;
}

/******************************************/
/* Listing Queue items (for debugging)    */
/******************************************/
int listqueue(void){

  struct queueNode *temp;

  if(queueHead==NULL) return FALSE;
  temp=queueHead->next;
  while(temp->next!=NULL){
    printf("[%s][%s]\n", temp->keyStr, temp->dataStr);
    temp=temp->next;
  }
  return TRUE;
}


/*****************************/
/* free all memory for Queue */
/*****************************/
void freequeue(void){
  char keyStr[WORDMAXLN];
  char dataStr[WORDMAXLN];
  while(Dequeue(keyStr, dataStr));
  free(queueHead);
  free(queueTail);
  queueHead=queueTail=NULL;
}

/**********************************/
/**********************************/
int Initqueue(void){
  int ret;
  if(debug>1) err_msg("DEBUG:=>initqueue( )");
  ret = initqueue();
  if(debug>1) err_msg("DEBUG:(%d)<=initqueue( )",ret);
  return ret;

}
int Enqueue(char* keyStr, char* dataStr){
  int ret;
  if(debug>1) err_msg("DEBUG:=>enqueue(%s,%s)", keyStr, dataStr);
  ret = enqueue(keyStr, dataStr);
  if(debug>1) err_msg("DEBUG:(%d)<=enqueue( )",ret);
  return ret;

}
int Dequeue(char* keyStr, char* dataStr){
  int ret;
  if(debug>1) err_msg("DEBUG:=>dequeue( )");
  ret = dequeue(keyStr, dataStr);
  if(debug>1) err_msg("DEBUG:(%d)<=dequque(%s,%s)",ret, keyStr, dataStr);
  return ret;

}
int Listqueue(void){
  int ret;
  if(debug>1) err_msg("DEBUG:=>listQueue( )");
  ret = listqueue();
  if(debug>1) err_msg("DEBUG:(%d)<=listQueue( )",ret);
  return ret;
}

void Freequeue(void){
  if(debug>1) err_msg("DEBUG:=>freeQueue()");
  freequeue();
  if(debug>1) err_msg("DEBUG:<=freequeue()");
}


