
#include "textBuffer.h"
#include "loopScanner.h"

BufferEntry printBuffer[MAXBUFENTRIES];

QueueEntry eventQueue[MAXQUEUEENTRIES];

typedef struct {
  int event;
  DFuncIntParStrPtr handler;
  int hparam;
  String info;
} EventHandler;

EventHandler eventHandlers[MAXEVENTHANDLERS];
int numOfEventHandlers;

byte bufferCount;
byte bufferWritePointer;
byte bufferReadPointer;

int eventQueueCount;
int eventQueueWritePointer;
int eventQueueReadPointer;

void setupPrintBuffer() {
  bufferCount = 0;
  bufferWritePointer = 0;
  bufferReadPointer = 0;
}

void setupEventQueue() {
  bufferCount = 0;
  bufferWritePointer = 0;
  bufferReadPointer = 0;
  numOfEventHandlers = 0;
  addLoopScanner(1,eventLoop,0,"eventLoop");
  SERIAL_PRINTLN("event queue set up");
}

extern int getPrintBufferFreeEntries() {
  return MAXBUFENTRIES-bufferCount;
}

extern int getEventQueueFreeEntries() {
  return MAXQUEUEENTRIES-eventQueueCount;
}

extern int getPrintBufferCount() {
  return bufferCount;
}

extern int getEventQueueCount() {
  return eventQueueCount;
}

void dumpPrintBuffer() {
  SERIAL_PRINTLN(F("==== Print buffer ===="));
  SERIAL_PRINT("Count: ");
  SERIAL_PRINT(bufferCount);
  SERIAL_PRINT(F(", WritePointer: "));
  SERIAL_PRINT(bufferWritePointer);
  SERIAL_PRINT(F(", ReadPointer: "));
  SERIAL_PRINTLN(bufferReadPointer);
  for (int i=0; i<MAXBUFENTRIES; i++) {
    SERIAL_PRINT(i);
    SERIAL_PRINT(F(": "));
    SERIAL_PRINT(printBuffer[i].data.length());
    SERIAL_PRINTLN(F(" characters"));
  }
  SERIAL_PRINTLN(F("======================"));
}
  
void dumpEventQueue() {
  SERIAL_PRINTLN(F("==== Event Queue ===="));
  SERIAL_PRINT("Count: ");
  SERIAL_PRINT(eventQueueCount);
  SERIAL_PRINT(F(", WritePointer: "));
  SERIAL_PRINT(eventQueueWritePointer);
  SERIAL_PRINT(F(", ReadPointer: "));
  SERIAL_PRINTLN(eventQueueReadPointer);
  for (int i=0; i<MAXQUEUEENTRIES; i++) {
    SERIAL_PRINT(i);
    SERIAL_PRINT(F(": event: "));
    SERIAL_PRINT(eventQueue[i].event);
    SERIAL_PRINT(F(" - "));
    SERIAL_PRINT((eventQueue[i].data!=(String)0)?eventQueue[i].data.length():0);
    SERIAL_PRINTLN(F(" characters"));
  }
  SERIAL_PRINTLN(F("======================"));
}

BufferEntry getBufferEntry() {
  byte rp = bufferReadPointer;
  bufferReadPointer++;
  if (bufferReadPointer>=MAXBUFENTRIES) bufferReadPointer=0;
  bufferCount--;
  return printBuffer[rp];
}

QueueEntry getEventQueueEntry() {
  int rp = eventQueueReadPointer;
  eventQueueReadPointer++;
  if (eventQueueReadPointer>=MAXQUEUEENTRIES) eventQueueReadPointer=0;
  eventQueueCount--;
  return eventQueue[rp];
}

void putBufferEntry(BufferEntry be) {
  printBuffer[bufferWritePointer] = be;
  bufferCount++;
  bufferWritePointer++;
  if (bufferWritePointer>=MAXBUFENTRIES) bufferWritePointer=0;
}

void putEventQueueEntry(QueueEntry be) {
  eventQueue[eventQueueWritePointer] = be;
  eventQueueCount++;
  eventQueueWritePointer++;
  if (eventQueueWritePointer>=MAXQUEUEENTRIES) eventQueueWritePointer=0;
}

void putEventQueueEntry(int event) {
  putEventQueueEntry(event,0);
}

void putEventQueueEntry(int event, String data) {
  QueueEntry be;
  be.event = event;
  be.data = data;
  putEventQueueEntry(be);
}

void putEventQueueEntry(int event, int param, String data) {
  QueueEntry be;
  be.event = event;
  be.param = param;
  be.data = data;
  putEventQueueEntry(be);
}

void putEventQueueEntry(int event, String data, int param) {
  QueueEntry be;
  be.event = event;
  be.param = param;
  be.data = data;
  putEventQueueEntry(be);
}

void addEventHandler(int event, DFuncIntParStrPtr handler, int hparam, String info) {
  if (numOfEventHandlers>=MAXEVENTHANDLERS) return;
  eventHandlers[numOfEventHandlers].event = event;
  eventHandlers[numOfEventHandlers].handler = handler;
  eventHandlers[numOfEventHandlers].hparam = hparam;
  eventHandlers[numOfEventHandlers].info = String(info);
  numOfEventHandlers++;
}

void handleEvent(int event, int param, String data) {
  for (int hn=0; hn<numOfEventHandlers; hn++) {
    if (eventHandlers[hn].event==event) {
      eventHandlers[hn].handler(event,param,data);
    }
  }
}

void eventLoop(int param) {
  if (getEventQueueCount()<1) return;
  QueueEntry evt = getEventQueueEntry();
  handleEvent(evt.event,evt.param,evt.data);
}
