/*
*
*  Program to simulate devices to help debug messages. 
*  Not in release code / binary for AqualinkD
*
*/


#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>

#include <fcntl.h>
#include <time.h>

// #include "serial_logger.h"
#include "aq_serial.h"
#include "utils.h"
#include "packetLogger.h"
#include "rs_msg_utils.h"

#define CONFIG_C // Make us look like config.c when we load config.h so we get globals.
#include "config.h"


#define SWG
//#define HEATPUMP

#ifdef SWG
unsigned char DEVICE_ID = 0x50;
#else
unsigned char DEVICE_ID = 0x70;
#endif

bool _keepRunning = true;
int _rs_fd;

void intHandler(int dummy)
{
  _keepRunning = false;
  LOG(SLOG_LOG, LOG_NOTICE, "Stopping!\n");
}

bool isAqualinkDStopping() {
  return !_keepRunning;
}

void process_swg_packet(unsigned char *packet_buffer, const int packet_length);
void process_heatpump_packet(unsigned char *packet_buffer, const int packet_length);

int main(int argc, char *argv[])
{
  int logLevel = LOG_INFO;

  int packet_length;
  unsigned char packet_buffer[AQ_MAXPKTLEN];

  int blankReads = 0;
  bool returnError = false;

  if (argc < 2 || access(argv[1], F_OK) == -1)
  {
    fprintf(stderr, "ERROR, first param must be valid serial port, ie:-\n\t%s /dev/ttyUSB0\n\n", argv[0]);
    return 1;
  }

  setLoggingPrms(logLevel, false, NULL);

  LOG(SLOG_LOG, LOG_NOTICE, "Starting %s\n", basename(argv[0]));

  // _rs_fd = init_serial_port(argv[1]);
  _rs_fd = init_blocking_serial_port(argv[1]);

  if (_rs_fd < 0)
  {
    LOG(SLOG_LOG, LOG_ERR, "Unable to open port: %s\n", argv[1]);
    displayLastSystemError(argv[1]);
    return -1;
  }

  signal(SIGINT, intHandler);
  signal(SIGTERM, intHandler);

  // Force all packets to be printed.
  addDebugLogMask(RSSD_LOG);
  _aqconfig_.RSSD_LOG_filter[0] = DEVICE_ID;

  while (_keepRunning)
  {
    if (_rs_fd < 0)
    {
      LOG(SLOG_LOG, LOG_ERR, "ERROR, serial port disconnect\n");
      _keepRunning = false;
    }

    packet_length = get_packet(_rs_fd, packet_buffer);

    if (packet_length == AQSERR_READ)
    {
      // Unrecoverable read error. Force an attempt to reconnect.
      LOG(SLOG_LOG, LOG_ERR, "ERROR, on serial port! Please check %s\n", argv[1]);
      _keepRunning = false;
      returnError = true;
    }
    else if (packet_length == AQSERR_TIMEOUT)
    {
      // Unrecoverable read error. Force an attempt to reconnect.
      LOG(SLOG_LOG, LOG_ERR, "ERROR, Timeout on serial port, nothing read! Please check %s\n", argv[1]);
      _keepRunning = false;
      returnError = true;
    }
    else if (packet_length < 0)
    {
      // Error condition
      if (packet_length == AQSERR_CHKSUM)
      {
        LOG(SLOG_LOG, LOG_WARNING, "Checksum error\n");
      }
      else if (packet_length == AQSERR_2LARGE)
      {
        LOG(SLOG_LOG, LOG_WARNING, "Packet too large error\n");
      }
      else if (packet_length == AQSERR_2SMALL)
      {
        LOG(SLOG_LOG, LOG_WARNING, "Packet too small error\n");
      }
      else
      {
        LOG(SLOG_LOG, LOG_WARNING, "Unknown error reading packet\n");
      }
    }
    else if (packet_length == 0)
    {
      if (++blankReads > 10)
      {
        LOG(SLOG_LOG, LOG_ERR, "ERROR, too many blank reads! Please check %s\n", argv[1]);
        _keepRunning = false;
        returnError = true;
      }
      delay(1);
    }
    else if (packet_length > 0)
    {
      blankReads = 0;
      //debuglogPacket(SLOG_LOG, packet_buffer, packet_length, true, true);

      if (packet_buffer[PKT_DEST] == DEVICE_ID)
      {
#ifdef SWG
        process_swg_packet(packet_buffer, packet_length);
#else
        process_heatpump_packet(packet_buffer, packet_length);
#endif
      }
    }
  }

  LOG(SLOG_LOG, LOG_NOTICE, "Stopping!\n");

  close_serial_port(_rs_fd);

  if (returnError)
    return 1;

  return 0;
}


/*
* Reply to message 
*/


void process_heatpump_packet(unsigned char *packet_buffer, const int packet_length)
{
  //LOG(SLOG_LOG, LOG_NOTICE, "Replying to packet 0x%02hhx!\n",packet_buffer[PKT_DEST]);

  //  reply to off 0x10|0x02|0x00|0x0d|0x40|0x00|0x00|0x5f|0x10|0x03|
  static unsigned char hp_off[] = {0x00, 0x0d, 0x40, 0x00, 0x00};
  static unsigned char hp_heat[] = {0x00, 0x0d, 0x48, 0x00, 0x00};
  static unsigned char hp_cool[] = {0x00, 0x0d, 0x68, 0x00, 0x00};
  

  if (packet_buffer[PKT_CMD] == CMD_PROBE)
  {
    send_ack(_rs_fd, 0x00);
    LOG(SLOG_LOG, LOG_NOTICE, "Replied to Probe packet to 0x%02hhx with ACK\n",packet_buffer[PKT_DEST]);
  }
  else if (packet_buffer[3] == 0x0c)
  {
    if (packet_buffer[4] == 0x00)
    { // Off
      send_jandy_command(_rs_fd, hp_off, 5);
      LOG(SLOG_LOG, LOG_NOTICE, "Replied to OFF 0x%02hhx packet to 0x%02hhx with ACK\n",packet_buffer[4],packet_buffer[PKT_DEST]);
    } 
    else if (packet_buffer[4] == 0x09) // Heat
    { // Enable
      send_jandy_command(_rs_fd, hp_heat, 5);
      LOG(SLOG_LOG, LOG_NOTICE, "Replied to HEAT 0x%02hhx packet to 0x%02hhx with ACK\n",packet_buffer[4],packet_buffer[PKT_DEST]);
    }
    else if (packet_buffer[4] == 0x29) // Cool
    { // Enable
      send_jandy_command(_rs_fd, hp_cool, 5);
      LOG(SLOG_LOG, LOG_NOTICE, "Replied to COOL 0x%02hhx packet to 0x%02hhx with ACK\n",packet_buffer[4],packet_buffer[PKT_DEST]);
    }
    else 
    { // Enable
      LOG(SLOG_LOG, LOG_ERR, "************* Unknown State Request 0x%02hhx *************",packet_buffer[4]);
      LOG(SLOG_LOG, LOG_NOTICE, "NOT Replying to UNKNOWN 0x%02hhx packet to 0x%02hhx with ACK\n",packet_buffer[4],packet_buffer[PKT_DEST]);
      //send_jandy_command(_rs_fd, hp_unknown, 5);
    }
  }
}


void process_swg_packet(unsigned char *packet_buffer, const int packet_length)
{
  //(packet[3] = 0x16
  //(packet[4] * 100) = PPM
  static unsigned char swg_ack[] = {0x00,0x01,0x00,0x00};
  static unsigned char swg_ppm[] = {0x00, 0x16, 0x1f, 0x00, 0x00, 0x00};
  //static unsigned char swg_id[] = {0x00,0x03,0x00,0x49,0x6e,0x74,0x65,0x6c,0x6c,0x69,0x63,0x68,0x6c,0x6f,0x72,0x2d,0x2d,0x34,0x30};
  //static unsigned char swg_id[] = {0x00,0x03,0x00,0x41,0x71,0x75,0x61,0x50,0x75,0x72,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
  static unsigned char swg_id[] = {0x00,0x03,0x01,0x41,0x71,0x75,0x61,0x50,0x75,0x72,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
   // 0x11  set SWG %
  if (packet_buffer[PKT_CMD] == CMD_PROBE)
  {
    //send_ack(_rs_fd, 0x00);
    send_jandy_command(_rs_fd, swg_ack, 4);
    LOG(SLOG_LOG, LOG_NOTICE, "Replied to Probe packet to 0x%02hhx with ACK\n",packet_buffer[PKT_DEST]);
  }
  else if (packet_buffer[3] == 0x11)
  {
    //int percent = (int)packet_buffer[4]; 
    send_jandy_command(_rs_fd, swg_ppm, 6);
    LOG(SLOG_LOG, LOG_NOTICE, "Received %%=%d, Replied PPM=%d\n",(int)packet_buffer[4],swg_ppm[2] * 100);
  } 
  else if (packet_buffer[3] == 0x14) 
  {
    send_jandy_command(_rs_fd, swg_id, 19);
    LOG(SLOG_LOG, LOG_NOTICE, "Receive ID request, replied\n");
  } 
  else 
  {
     LOG(SLOG_LOG, LOG_ERR, "************* Unknown Request 0x%02hhx *************",packet_buffer[3]);
  }
}

