#include "qmqueue.h"
#include <stdio.h>
#include "declarations.h"

/* Log Management */
#define FATAL_QMQUEUE
#define ERROR_QMQUEUE
#define INFO_QMQUEUE
//#define WARN_QMQUEUE
//#define DEBUG_QMQUEUE

T_QMQueue_ptr QMQ_create() {
  T_QMQueue_ptr queue;

  queue = (T_QMQueue_ptr)malloc(sizeof(struct T_QMQueue));
  queue->first = queue->last = NULL;
  return queue;
}

void QMQ_printR(T_QMQueue_ptr queue) {
  QMQ_item_ptr current;

#ifdef INFO_QMQUEUE
  printf("QMprintR: ");
#endif
  current = queue->last;
  while (current != NULL) {
#ifdef INFO_QMQUEUE
    printf("Transaction %d,", current->item->trans.transaction.tid);
#endif
    current = current->prev;
  }
#ifdef INFO_QMQUEUE
  printf("\n");
#endif
}

void QMQ_printFirstAndNumElements(T_QMQueue_ptr queue) {
  QMQ_item_ptr current;
  T_Transaction *t = NULL;//TODO Quitar
  int num_elements = 0;

#ifdef INFO_QMQUEUE
  //printf("print: ");
#endif

  current = queue->first;
#ifdef INFO_QMQUEUE
  if (current != NULL){
    t = current->trans;//TODO Quitar
  }
#endif

  while (current != NULL) {
/*
#ifdef INFO_QUEUE
    printf("%d(%d),", current->item->transaction.tid, current->item->executing);
#endif
*/
    num_elements++;
    current = current->next;
  }

#ifdef INFO_QMQUEUE
  //printf("\n");
#endif

#ifdef INFO_QMQUEUE
  printf("Number of elements <%d>\n", num_elements);
  if (t != NULL){
    printf("First Transaction\n");
    printT_TransactionCompact(t);//TODO Quitar
  }
  printf("\n");
#endif
};

void QMQ_print(T_QMQueue_ptr queue) {
  QMQ_item_ptr current;

#ifdef INFO_QMQUEUE
  printf("QMprint: ");
#endif
  current = queue->first;
  while (current != NULL) {
#ifdef INFO_QMQUEUE
    printf("Transaction %d,", current->item->trans.transaction.tid);
#endif
    current = current->next;
  }
#ifdef INFO_QMQUEUE
  printf("\n");
#endif
}

void QMQ_enqueue(T_QMQueue_ptr queue, QM_message *mess, T_Transaction * trans) {
  QMQ_item_ptr item;

  item = (QMQ_item_ptr)malloc(sizeof(struct QMQ_item));
  item->item = mess;
  item->trans = trans;
  item->prev = item->next = NULL;
  if (queue->first == NULL) {
    queue->first = item;

#ifdef DEBUG_QMQUEUE
    printf("insert in empty queue\n");
#endif
  } else {
    queue->last->next = item;
    item->prev = queue->last;

#ifdef DEBUG_QMQUEUE
    printf("insert in non empty queue\n");
#endif
  }
  queue->last = item;

  //QMQ_printFirstAndNumElements(queue);//TODO Quitar
}

T_Transaction * QMQ_getFirst(T_QMQueue_ptr queue) {

  if (queue->first == NULL) {
    printf("the queue is empty\n");
    exit(1);
  } //if
  return queue->first->trans;
} // QMQ_getFirst

hot_uint32 QMQ_getFirstThId(T_QMQueue_ptr queue) {
  if (queue->first == NULL) {
#ifdef FATAL_QMQUEUE
    printf("The queue is empty (FATAL ERROR)\n");
#endif
    exit(1);
  }

  return queue->first->trans->mclientId;
} // QMQ_getFirstThId

bool QMQ_isEmpty(T_QMQueue_ptr queue) {
#ifdef DEBUG_QMQUEUE
  if (queue->first != NULL) {
    printf(" the queue is not empty %d \n", queue->first->item->transaction.tid);
  }
#endif

  return queue->first == NULL;
}

QM_message* QMQ_dequeue(T_QMQueue_ptr queue) {
  QMQ_item_ptr current;
  QM_message *res;

  current = queue->first;
  if (current == NULL){
#ifdef ERROR_QMQUEUE
    printf("ERROR getAndRemove from an empty queue\n");
#endif
  }

  // now current points to the searched item
  // unlink it from the list
  if (current->prev != NULL)
    current->prev->next = current->next; else
    queue->first = current->next;
  if (current->next != NULL)
    current->next->prev = current->prev; else
    queue->last = current->prev;
  res = current->item;

#ifdef DEBUG_QMQUEUE
  printf("qm_message dequeued\n");
#endif

  free(current);

  //QMQ_printFirstAndNumElements(queue);//TODO Quitar

  return res;
}

QM_message *QMQ_getFirstQM_message(T_QMQueue_ptr queue) {

  if (queue->first == NULL) {
    printf("the queue is empty\n");
    exit(1);
  } //if
  return queue->first->item;
}


