#include "lirc.hpp"

#include "config.h"

#include "gettext.hpp"
#include "config.hpp"
#include "common.hpp"
#include "print.hpp"

#include <stdio.h>

#include <signal.h>
#include <fcntl.h>
#include <unistd.h>

#include <iostream>

#include "lirc/lirc_client.h"

Lirc::Lirc()
  : running(false), next_time(0), this_time(0),
    dump_fast(0), flush(false)
{
  timeinterv = Config::get_instance()->p_lirc_delay();

  connect();

  running = true;
}

void Lirc::connect()
{
  if ((irsd = lirc_init("mms",1)) == -1) {
    DebugPrint perror(gettext("Could not connect to lirc daemon"), 
		      Print::DEBUGGING, DebugPrint::CRITICAL, "LIRC");
    std::exit(1);
  }

  int flags = fcntl(irsd, F_GETFL);
  flags |= O_NONBLOCK;
  fcntl(irsd, F_GETFL, &flags);
}

Lirc::~Lirc()
{
  terminate();
  lirc_deinit();
}

void Lirc::suspend()
{
  running = false;
  lirc_deinit();
}

void Lirc::wake_up()
{
  connect();

  Input i; 
  input = i;


  struct timeval tv;
  gettimeofday(&tv,NULL);
  next_time = (unsigned long long) tv.tv_sec*1000+tv.tv_usec/1000 + 200;
  flush=true;
  running = true;
}

void ir_parsebuf(IR * irs) {
  sscanf(irs->buf,"%x%x%s%s",&(irs->code),&irs->serial,irs->key,irs->remote);
}

void Lirc::run()
{
  Input_master *input_master = Input_master::get_instance();

  struct timeval tv;
  IR irdata;

  while (true) {

    dump_fast = 2;
    
    input_done_.signal();
    input_ready.wait();
    input_ready.reset();
    
    char buffer[64];

  nogood:

    size_t len = read(irsd, buffer, 64);

    if (dump_fast > 0) {
      gettimeofday(&tv,NULL);
      this_time = (unsigned long long) tv.tv_sec*1000+tv.tv_usec/1000;
      if (next_time > this_time) {
        if (!flush)
	  --dump_fast;
        goto nogood;
      } else {
	next_time = timeinterv+this_time;
        flush=false;
      }
    }
    
    if (len < 0)
      continue;

    if (!running)
      continue;
    
    for(size_t i = 0; i<len; ++i) {
      if (buffer[i] == '\n') {
	buffer[i] = '\0';
	break;
      }
    }
    
    irdata.buf = buffer;
    
    ir_parsebuf(&irdata);
    
    input_map::iterator im = input_master->cur_map->find(irdata.key);

    if (irdata.serial > 0 && !im->second.multiple)
      goto nogood;
  
    if (accept_all) {

      Input i;

      im = input_master->cur_map->find(irdata.key);
      if (im != input_master->cur_map->end())
	if (im->second.mode == "search")
	  i = im->second;

      i.key = irdata.key;
      input = i;

    } else {
      
      if (im != input_master->cur_map->end())
	input = im->second;
      else
	goto nogood;
    }

    DebugPrint perror("got command " + input.command + " ( " + 
		      conv::itos(irdata.serial) + " ) ", 
		      Print::INFO, DebugPrint::ALL, "LIRC");
  }
}

