#include <stdio.h>
#include "LibAard.h"
#include "Commands.h"
#include "AardRemoteMessage.h"
#include "RawIR.h"

bool
Validate(AardRemoteMessage * msg,
         unsigned char msg_kind,
         unsigned char msg_code,
         unsigned short msg_len) {
   if (msg == NULL) {
      printf("No message seen\n");
      return false;
   } else if (! ((msg->MessageKind() == msg_kind) &&
                 (msg->FunctionCode() == msg_code) &&
                 (msg->MessageLength() == msg_len))) {
      printf("Unexpected message: ");
      msg->DebugDump();
      return false;
   }
   return true;
}

int
main(int argc, char ** argv) {
   AardRemoteMessage * msg;

   if (argc != 2) {
      fprintf(stderr, "usage: testaard devicename\n");
      return 2;
   }
   LibAard l;
   if (l.OpenAardRemote(argv[1]) < 0) {
      fprintf(stderr, "open of %s failed\n", argv[1]);
      return 2;
   }

   // Get synced up and make sure the aardremote is talking.

   l.WaitForStartup();
   if (l.HasError()) {
      printf("HasError returned true following WaitForStartup()\n");
      return 2;
   }

   // Now query everything that can be queried.

   l.SendCommand(MKCR_QMICROS);
   msg = l.WaitMessage(100);
   if (Validate(msg, MK_REPLY, MKCR_QMICROS, 3)) {
      printf("AardRemote microsecond clock is 0x%04x%04x\n",
             msg->MessageBody()[2], msg->MessageBody()[1]);
   }
   delete msg;

   l.SendCommand(MKCR_QVERSION);
   msg = l.WaitMessage(100);
   if (Validate(msg, MK_REPLY, MKCR_QVERSION, 2)) {
      printf("AardRemote microcode version is %u\n", msg->MessageBody()[1]);
   }
   delete msg;

   l.SendCommand(MKCR_QRECEIVER);
   msg = l.WaitMessage(100);
   if (Validate(msg, MK_REPLY, MKCR_QRECEIVER, 2)) {
      printf("AardRemote receiver is %s\n",
             msg->MessageBody()[1] ? "on" : "off");
   }
   delete msg;

   l.SendCommand(MKCR_QFREQUENCY);
   msg = l.WaitMessage(100);
   if (Validate(msg, MK_REPLY, MKCR_QFREQUENCY, 2)) {
      printf("AardRemote IR modulation set to %ukHz\n",
             msg->MessageBody()[1]);
   }
   delete msg;

   l.SendCommand(MKCR_QUEUESIZE);
   msg = l.WaitMessage(100);
   if (Validate(msg, MK_REPLY, MKCR_QUEUESIZE, 2)) {
      printf("AardRemote IR buffer size is %u\n", msg->MessageBody()[1]);
   }
   delete msg;

   l.SendCommand(MKCR_QMICROS);
   msg = l.WaitMessage(100);
   if (Validate(msg, MK_REPLY, MKCR_QMICROS, 3)) {
      printf("AardRemote microsecond clock is 0x%04x%04x\n",
             msg->MessageBody()[2], msg->MessageBody()[1]);
   }
   delete msg;

   l.SendCommand(MKCR_RECEIVER, 1);
   msg = l.WaitMessage(100);
   if (Validate(msg, MK_REPLY, MKCR_RECEIVER, 1)) {
      printf("AardRemote IR receiver turned ON, press a remote button.\n");
   }
   delete msg;

   bool seen_end_of_ir = false;
   std::vector<unsigned short> irseq;
   bool goodseq = true;
   while (! seen_end_of_ir) {
      if (l.HasError()) {
         printf("HasError() returned true while waiting for IR data\n");
         return 2;
      }
      msg = l.WaitMessage(0);
      if (msg == NULL) {
         printf("No message from WaitMessage(0)\n");
         return 2;
      }
      if ((msg->MessageKind() == MK_ASYNC) &&
          (msg->FunctionCode() == MKAS_RAWIR)) {
         const std::vector<unsigned short> & dat = msg->MessageBody();
         for (int i = 1; i < dat.size(); ++i) {
            unsigned short code = dat[i];
            if (BGIR_IS_STATUS(code)) {
               printf("status:");
               if (code & BGIR_END) {
                  printf(" end");
                  seen_end_of_ir = true;
               }
               if (code & BGIR_LOST_DATA) {
                  printf(" lost-data");
                  goodseq = false;
               }
               if (code & BGIR_LOST_TIME) {
                  printf(" lost-time");
                  goodseq = false;
               }
               if (code & BGIR_DISABLED) {
                  printf(" int-disabled");
               }
               printf("\n");
            } else {
               if (BGIR_IS_MARK(code)) {
                  irseq.push_back(code);
                  printf("M %u\n", BGIR_DURATION(code));
               } else if (BGIR_IS_SPACE(code)) {
                  irseq.push_back(code);
                  printf("S %u\n", BGIR_DURATION(code));
               } else {
                  printf("Unrecognized IR data: 0x%04x\n", code);
               }
            }
         }
      } else {
         printf("Unexpected message while waiting for IR data\n");
         msg->DebugDump();
      }
      delete msg;
   }
   if ((irseq.size() > 0) && goodseq) {
      printf("OK, I'm about to send that same sequence...\n");
      usleep(1000000);
      printf("Here goes...\n");
      l.SendCommand(MKCR_SENDRAW,irseq);
      printf("I sent %u pulese to AardRemote\n", irseq.size());
      msg = l.WaitMessage(100);
      if (Validate(msg, MK_REPLY, MKCR_SENDRAW, 2)) {
         printf("AardRemote got %u pulses from me.\n", msg->MessageBody()[1]);
      }
      delete msg;
      l.SendCommand(MKCR_WAITSEND);
      msg = l.WaitMessage(100);
      if (Validate(msg, MK_REPLY, MKCR_WAITSEND, 1)) {
         printf("AardRemote finished sending IR stream\n");
      }
      delete msg;
   }
   return 0;
}
