/*
 * extb plugin to VDR (C++)
 *
 * (C) 2004 - 2007 Andreas Brachold <vdr04-at-deltab-dot-de>
 *
 * This code is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This code is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
 */

#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>

#include "lirc.h"
#include "extb_lircwatch.h"

#include <vdr/tools.h>

#define REPEATLIMIT  20 // ms
#define REPEATDELAY 350 // ms
#define KEYPRESSDELAY 150 // ms

cExtBLircWatch::cExtBLircWatch(const char *DeviceName)
: m_bShutdown(false)
, m_bWatchSuccess(false)
, m_bWatch(false)
{
  struct sockaddr_un addr;
  addr.sun_family = AF_UNIX;
  strncpy(addr.sun_path, DeviceName, sizeof(addr.sun_path));
  if ((m_fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) {
    if (connect(m_fd, (struct sockaddr *)&addr, sizeof(addr)) >= 0) {
	    dsyslog("extb: cExtBLircWatch::open(fd=%d)", m_fd);
      Start();
      return;
    }
    esyslog("extb: cExtBLircWatch: could not connect to socket: %s",strerror(errno));
  }
  else
    {
    esyslog("extb: cExtBLircWatch: could not open socket: %s", strerror(errno));
    }
  close();
}

cExtBLircWatch::~cExtBLircWatch()
{
  m_bShutdown = true;
  close();
  Cancel();
}

void cExtBLircWatch::close()
{
  if(-1 == m_fd) {
	    dsyslog("extb: cExtBLircWatch::close(fd=%d)", m_fd);
	    ::close(m_fd);
	    m_fd = -1;
	}
}

void cExtBLircWatch::StartWatch()
{
  m_bWatch = true;
  m_bWatchSuccess = false;
  m_nVideoModes = 0;
  m_nScartBootModes = 0;
  m_bVideoFound = false;
  m_bScartBootFound = false;
}

void cExtBLircWatch::Action(void)
{
  dsyslog("extb: cExtBLircWatch thread started (pid=%d)", getpid());

  char buf[LIRC_BUFFER_SIZE];
  int timeout = -1;

  for (; m_fd >= 0 && !m_bShutdown;) {
    
    LOCK_THREAD;
    memset(buf, 0, sizeof(buf));
    bool bReady = cFile::FileReady(m_fd, timeout);
    int ret = bReady ? safe_read(m_fd, buf, sizeof(buf)) : -1;

    if(m_bShutdown)
      break;
    if (bReady && ret <= 0 ) {
      esyslog("extb: cExtBLircWatch::Action connection lost");
      close();
      break;
    }
    
    if (bReady && ret > 21) {
      char KeyName[LIRC_KEY_BUF];
      char Remote[256];
      sscanf(buf, "%*x %*x %29s %s", KeyName, Remote); // '29' in '%29s' is LIRC_KEY_BUF-1!
    
      moredsyslog("extb: cExtBLircWatch: %s / %s", KeyName, Remote);
    
      if(m_bWatch && 0 == strncmp("EXTB_RX", Remote,7)) {
        moredsyslog("extb: checking key: >%s<", KeyName);
        
        if(0 == strncmp(KeyName, "V", 1)) {
          dsyslog("extb: video mode found");
          m_nVideoModes = atoi(&KeyName[1]);
          m_bVideoFound = true;
        }
        
        if(0 == strncmp(KeyName, "SB", 2)) {
          dsyslog("extb: scart boot mode found");
          sscanf(&KeyName[2], "%x", &m_nScartBootModes);
          m_bScartBootFound = true;
        }
      
        if(m_bVideoFound && m_bScartBootFound) {
            dsyslog("extb: answer from extb complete");
            m_bWatchSuccess = true;
        }
      }
    }
  }
  dsyslog("extb: cExtBLircWatch thread closed (pid=%d)", getpid());
}
