/*
  usb serial command processor. streams in data from usb cdc 
  serial and dispatches it to the appropriate handler.

  this work is based on heavily on the original concept implemented
  by andrewcapon. any genius may safely be attributed to him and any
  faults can be attributed to lowfatcode.

  author: lowfatcode (standing on the shoulders of andrewcapon)
  created: 23rd feb 2020
*/

#include "32blit.h"
#include "core-debug.hpp"
#include "usbd_cdc.h"
#include "usbd_core.h"
#include "usb-serial.hpp"

#include <cstring>
#include <string>
#include <stdint.h>
#include <queue>

extern USBD_HandleTypeDef hUsbDeviceHS;

namespace cdc {

  std::map<std::string, CommandHandler> handlers;

  constexpr uint32_t MAX_PACKETS = 16;
  Packet packets[MAX_PACKETS];
  std::vector<Packet*> free_packets;

  Packet *rx_packet = nullptr;
  std::queue<Packet*> parse_queue;
  
  void request_new_packet();

  void init() {
    // push the packet buffers into the free packets collection
    for(uint32_t i = 0; i < MAX_PACKETS; i++) {
      free_packets.push_back(&packets[i]);
    }

    request_new_packet();
  }
  
  void request_new_packet() {    
    // if we have space to receive more packets then return false
    if(rx_packet == nullptr && free_packets.size() > 0) {
      rx_packet = free_packets.back();
      free_packets.pop_back();

      USBD_CDC_SetRxBuffer(&hUsbDeviceHS, rx_packet->data);
      USBD_CDC_ReceivePacket(&hUsbDeviceHS); 
    }
  }

  void data_received(uint32_t length) {      
    // take a copy of the newly received packet into the parse queue
    rx_packet->length = length;
    parse_queue.push(rx_packet);

    // request a new packet of data
    rx_packet = nullptr;
    request_new_packet();
  }

  // register a function to handle a new USB serial command
  void register_command_handler(std::string command, CommandHandler handler) {
    handlers[command] = handler;
  }

  // check for the incoming command identifier and matches it to the 
  // appropriate handler, then streams all incoming data directly to
  // the handler until the command processing is complete
  void parse_command() {
    constexpr uint32_t PARSE_STREAM_TIMEOUT = 250;
    static    uint32_t last_packet_time_ms = blit::now();

    static CommandHandler handler = nullptr;
        
    request_new_packet();
    
    while(parse_queue.size() > 0) {      
      // fetch the oldest packet from the queue
      Packet *packet = parse_queue.front();
      parse_queue.pop();
      
      if(!handler) {              
        // if no handler assigned yet then we're waiting for the command
        // search through the handler list to see if we have a matching one
        for(auto c : handlers) {
          if(strcmp(c.first.c_str(), packet->data) == 0) {
            // found the command so assign the handler and call it with the
            // first packet of data
            handler = c.second;

            // trim the command from this packet and adjust the length allowing
            // the rest of the packet to be processed by the handler
            uint32_t command_length = strlen(packet->data) + 1;            
            packet->length -= command_length;
            memcpy(packet->data, packet->data + command_length, packet->length);            
          }
        }
      } 
      
      if(handler) {
        if(packet->length > 0) {
          // the command handle must return true when it has finished processing
          // the entire command (even if this is across multiple packets)
          CommandState result = handler(CommandState::STREAM, packet->data, packet->length);

          if(result == CommandState::END) {    
            // command stream is complete, detach handler
            handler = nullptr;
          }

          if(result == CommandState::ERROR) {          
            // TODO: show error message
            handler = nullptr;
          }
        }  
      }

      free_packets.push_back(packet);   
      last_packet_time_ms = blit::now();               
    }        

    // check that the time since the last packet we received hasn't exceeded
    // the timeout. if it has then notify the current handler so that it can
    // tidy up and prepare to receive any future commands.
    uint32_t ms_since_last_packet = blit::now() - last_packet_time_ms;
    if(handler && (ms_since_last_packet > PARSE_STREAM_TIMEOUT)) {
      CommandState result = handler(CommandState::TIMEOUT, nullptr, 0);
      handler = nullptr;
    }
  }
}
