/****************************************************************************/
/* Copyright (c) 2014 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  : Interface to the Cathx M12 camera.                            */
/* Filename : CathxM12.h                                                    */
/* Author   : Henthorn                                                      */
/* Project  : Iceberg AUV                                                   */
/* Version  : 1.0                                                           */
/* Created  : 05/13/2015                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
#include "Syslog.h"
#include "CathxM12.h"
#include "CathxM12Msg.h"
#include "CathxM12Log.h"
#include "CathxM12Output.h"

static char   CathxM12::_response[2000];
static size_t CathxM12::_response_size;

// interface for use with the Cathx M12 Camera.
//
CathxM12::CathxM12(const char* name, const char* server_ip,
                   unsigned long port, int period)
  : PeriodicTask(name), _port(port), _period(period), _scnt(0)
{
   _name = strdup(name);
   _server_ip = strdup(server_ip);

   addPeriodicCallback(_period, (CallbackMethod)CathxM12::m12_callback);

  _msgQ   = new CathxM12Msg();
  _output = new CathxM12Output();
  _log    = new CathxM12Log(this, DataLog::BinaryFormat, "CathxM12");
  _output->write(); _log->write();
   curl_setup();
}

CathxM12::~CathxM12()
{
  if (_name) delete _name;
  if (_server_ip) delete _server_ip;
  if (_msgQ) delete _msgQ;
  if (_output) delete _output;
  if (_log) delete _log;
}

void CathxM12::m12_callback()
{
   // Process messages in queue
   //
   int nmsgs = 0;
   CathxM12Msg::Message msg;
   while (_msgQ->read(&msg) > 0) {

     nmsgs++;
     switch (msg._msg) {

     case CathxM12Msg::Action:
       if (msg._capture > 0)
         capture("true");
       else if (msg._capture == 0)
         capture("false");

       if (msg._profile >= 0)
         profile(msg._profile);

       break;

       default:
         nmsgs--;
         Syslog::write("CathxM12 - Invalid message: %d", msg._msg);
         break;
     }
  }
  if (++_scnt % 5 == 0) status();
}

#define URL  "http://%s/api/data_item_value/%s/0"

int CathxM12::capture(char *t_or_f)
{
  // We want to emulate the curl command line:
  // curl -i -H "Accept: application/json" -X PUT -d "value=true"
  // http://134.89.32.15/api/data_item_value/acq_enable/0
  //
  char json[20];
  sprintf(json, "value=%s", t_or_f);
  sprintf(_buf, URL,  _server_ip, "acq_enable");

  Syslog::write(
    "CathxM12::capture(%s)- curl -i -H \"Accept: application/json\" -X PUT -d \"%s\" %s",
     t_or_f, json, _buf);

  struct curl_slist *headers = NULL;
  headers = curl_slist_append(headers, "Accept: application/json");

  // Used the advice here:
  // http://stackoverflow.com/questions/7569826/send-string-in-put-request-with-libcurl
  //
  curl_setup();
  curl_easy_setopt(_curl, CURLOPT_HEADER, 1L); 
  curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headers); 
  curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "PUT"); /* !!! */
  curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, json); /* data goes here */
  curl_easy_setopt(_curl, CURLOPT_URL, _buf);

  int c = curl_execute();
  //Syslog::write("CathxM12::capture(%s) errors: %s", t_or_f, _errorbuf);

  curl_slist_free_all(headers);
  curl_cleanup();

  Boolean debug = False;
  dprintf("CathxM12::profile(%s) response: %s\n", t_or_f, _response);

  _output->data.req_capture = strcmp(t_or_f, "true")? 0 : 1;
  status();

  return c;
}


int CathxM12::profile(int profile_number)
{
  // We want to emulate the curl command line:
  // curl -i -H "Accept: application/json" -X PUT -d "value=N"
  // http://134.89.32.15/api/data_item_value/camera_active_profile/0
  //
  char json[20];
  sprintf(json, "value=%d", profile_number);
  sprintf(_buf, URL,  _server_ip, "camera_active_profile");

  Syslog::write(
    "CathxM12::profile(%d)- curl -i -H \"Accept: application/json\" -X PUT -d \"%s\" %s",
     profile_number, json, _buf);

  struct curl_slist *headers = NULL;
  headers = curl_slist_append(headers, "Accept: application/json");

  // Used the advice here:
  // http://stackoverflow.com/questions/7569826/send-string-in-put-request-with-libcurl
  //
  curl_setup();
  curl_easy_setopt(_curl, CURLOPT_HEADER, 1L); 
  curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, headers); 
  curl_easy_setopt(_curl, CURLOPT_CUSTOMREQUEST, "PUT"); /* !!! */
  curl_easy_setopt(_curl, CURLOPT_POSTFIELDS, json); /* data goes here */
  curl_easy_setopt(_curl, CURLOPT_URL, _buf);

  int c = curl_execute();
  //Syslog::write("CathxM12::profile(%d) errors: %s", profile_number, _errorbuf);

  curl_slist_free_all(headers);
  curl_cleanup();

  Boolean debug = False;
  dprintf("CathxM12::profile(%d) response: %s\n",profile_number,_response);

  _output->data.req_profile = profile_number;
  status();

  return c;
}

int CathxM12::status()
{
  // We want to emulate the curl command line:
  // curl http://134.89.32.15/api/data_item_value/camera_status/0/value.json
  //
  sprintf(_buf, "http://%s/api/data_item_value/camera_status/0/value.json",
    _server_ip);

  curl_setup();
  curl_easy_setopt(_curl, CURLOPT_URL, _buf);

  int c = curl_execute();
  curl_cleanup();

  Boolean debug = False;
  dprintf("CathxM12::status() response: %s\n", _response);

  _output->data.act_capture = 0;
  if (_response_size > 0)
  {
    _output->data.act_capture = strstr(_response, "Acquiring")? 1 : 0;
  }

  _output->write();
  _log->write();

  return c;
}

size_t CathxM12::read_response(void *buffer, size_t size, size_t nmemb, void *userp)
{
   Boolean debug = False;

   dprintf("**** curl buffer len = %d, buffer = %s\n", size*nmemb, (char*)buffer);

   memcpy((void*)_response, (void*)buffer, size*nmemb);
   _response_size = size;

   return size*nmemb;
}

// This function should be called before setting the URL or post options
// 
int CathxM12::curl_setup()
{
    curl_cleanup();
   _curl = curl_easy_init();
   if (_curl) {
      curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, read_response);
      /* complete within TIMEOUT seconds */
      curl_easy_setopt(_curl, CURLOPT_TIMEOUT, 2L);
      curl_easy_setopt(_curl, CURLOPT_NOSIGNAL, 1L);
      curl_easy_setopt(_curl, CURLOPT_ERRORBUFFER, _errorbuf);
      return 0;
    }
    else
    {
       Syslog::write("%s CathxM12::curl_setup() - CURL initialization failed %d", _name);
       return -1;
    }
}

int CathxM12::curl_execute()
{
   Boolean debug = True;

   _response[0] = '\0';
   int c = curl_easy_perform(_curl);
   if (c != CURLE_OK)
      dprintf("CathxM12::curl_execute() curl response - %d => %s\n",
         c, _errorbuf);

   return c;
}

int CathxM12::curl_cleanup()
{
   if (_curl)
   {
      curl_easy_cleanup(_curl);
      _curl = NULL;
      return 0;
   }
   return 1;   
}
