/*
 * msgreceiver.c: A plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 * Date: 11.04.05 - 10.12.05, horchi 
 */

//***************************************************************************
// Includes
//***************************************************************************

#include <sys/stat.h>
#include <sys/msg.h>
#include <signal.h>

#include <vdr/interface.h>
#include "pin.h"

//***************************************************************************
// Object
//***************************************************************************

MessageReceiver::MessageReceiver()
{ 
   struct msgbuf* theMsg  = (struct msgbuf*)buffer;

   active = false; 
   msgID = na;
   header = (Header*)theMsg->mtext;
   message = theMsg->mtext + sizeof(Header);
}

MessageReceiver::~MessageReceiver()
{
   if (active)
   {
      StopReceiver();
      Cancel(3);
   }

   if (msgctl(msgID, IPC_RMID, 0) < 0)
      dsyslog("Error: Closing message queue failed, errno (%d), '%s'", 
              errno, strerror(errno));
}

//***************************************************************************
// Start Receiver
//***************************************************************************

int MessageReceiver::StartReceiver()
{
   if (!active)
   {
      if ((msgID = msgget(0xd8000000, IPC_CREAT|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0)
      {
         dsyslog("Creation of message queue failed");
         return fail;
      }

      dsyslog("Message queue (%d) created", msgID);
      
      Start();
   }
   else
   {
      active = false;
      Cancel(3);
      usleep(250);
      Start();
   }

   return success;
}

//***************************************************************************
// Stop Receiver
//***************************************************************************

int MessageReceiver::StopReceiver()
{
   active = false;
   dsyslog("Try to stop receiver thread (%d)", pid);
   kill(pid, 15);

   return success;
}

//***************************************************************************
// Action
//***************************************************************************
   
void MessageReceiver::Action()
{
   active = true;
   pid = getpid();

   dsyslog("PIN plugin receiver thread started (pid=%d)", pid);

   while (active)
   {
      wait();
   }  
    
   active = false;
   dsyslog("PIN plugin receiver thread ended (pid=%d)", pid);
    
   Cancel(0);
}

//***************************************************************************
// Wait
//***************************************************************************
   
int MessageReceiver::wait()
{
   int result;
   long from;
   struct msgbuf* theMsg = (struct msgbuf*)buffer;

   memset(buffer, 0, sizeBuffer);

   if ((result = msgrcv(msgID, theMsg, sizeBuffer, 0, 0)) < 0)
   {
      if (errno == EINTR)
         return wrnSysInterrupt;
      else if (errno == E2BIG)
         return errMessageToBig;
      else if (errno != ENOMSG)
         dsyslog("Receiving message failed, errno (%d), '%s'", 
                 errno, strerror(errno));

      return wrnNoMessage;
   }

   from = getHeader()->sender;

   // info

   dsyslog("Got event (%d) from (%ld) with message [%s]", 
           getHeader()->event, getHeader()->sender, 
           getMessage() ? getMessage() : "");

   // perform request

   switch (getHeader()->event)
   {
      case evtShow:
      {
         if (getMessage() && *getMessage())
         {
            Skins.QueueMessage(mtInfo, getMessage());
            dsyslog("Got '%s'", getMessage());
         }

         break;
      }

      case evtCheck:
      {
         int evt;   
         int sizeMsg = sizeof(Header);

         evt = cOsd::pinValid ? evtConfirm : evtAbort;
         theMsg->mtype = 1;
         header->sender = msgID;
         header->receiver = from;
         header->event = evt;
         *message = 0;

         if (msgsnd(header->receiver, theMsg, sizeMsg, 0) < 0)
            dsyslog("Sending event (%d) to (%ld) failed, errno (%d), '%s'", 
                    header->event, header->receiver, errno, strerror(errno));
      }
   }
   
   return success;
}
