
#include "xineCommon.h"

#include "xineLib.h"



namespace PluginXine
{
  
  static eKeys KeyMap[] =
  {
    kNone,
    kUp,
    kDown,
    kMenu,
    kOk,
    kBack,
    kLeft,
    kRight,
    kRed,
    kGreen,
    kYellow,
    kBlue,
    k0, k1, k2, k3, k4, k5, k6, k7, k8, k9,
    kPlay,
    kPause,
    kStop,
    kRecord,
    kFastFwd,
    kFastRew,
    kPower,
    kChanUp,
    kChanDn,
    kVolUp,
    kVolDn,
    kMute,
    kSchedule,
    kChannels,
    kTimers,
    kRecordings,
    kSetup,
    kCommands,
    kUser1, kUser2, kUser3, kUser4, kUser5, kUser6, kUser7, kUser8, kUser9,
#if APIVERSNUM >= 10318
    kAudio,
#else
    kNone,
#endif
#if APIVERSNUM >= 10338
    kInfo,
#else
    kNone,
#endif
#if APIVERSNUM >= 10347
    kChanPrev,
    kNext,
    kPrev,
#else
    kNone,
    kNone,
    kNone,
#endif
#if APIVERSNUM >= 10510
    kSubtitles,
#else
    kNone,
#endif
  };

  cXineRemote::cXineRemote(const bool remoteOn)
    : cRemote("XineRemote")
    , cThread()
    , m_remoteOn(remoteOn)
    , m_xineLib(0)
  {
#if APIVERSNUM >= 10300
    SetDescription("XineRemote control");
#endif
    
    // ::fprintf( stderr, "XineRemote constructor\n");
    m_active = false;
    Start ();  // calls Action
  }
  
  cXineRemote::~cXineRemote()
  {
    {
      cMutexLock activeMutexLock(&m_activeMutex);
      m_active = false;
      m_activeCondVar.Broadcast();
    }
    
    // Close();
    Cancel(3);
  }
  
  void cXineRemote::setXineLib(cXineLib *const xineLib)
  {
    m_xineLib = xineLib;
  }

  bool cXineRemote::isConnected()
  {
    if (!m_xineLib)
      return false;

    return m_xineLib->isConnected();
  }
  
  void cXineRemote::Action (void)
  {
    dsyslog ("Entering cXineRemote thread\n");

    bool externalStreamFinished = false;
    bool osdReshowRequired = false;
    bool discontinuityDetected = false;
    int frameLeft = 0;
    int frameTop = 0;
    int frameWidth = 0;
    int frameHeight = 0;
    int frameZoomX = 0;
    int frameZoomY = 0;
    
    m_active = true;
    
    while (m_active)
    {
      if (isConnected())
      {
        if (osdReshowRequired)
        {
          osdReshowRequired = false;

          if (m_xineLib)
            m_xineLib->ReshowCurrentOSD(frameLeft, frameTop, frameWidth, frameHeight, frameZoomX, frameZoomY);
        }
        
        if (externalStreamFinished)
        {
          externalStreamFinished = false;

          if (m_xineLib)
            m_xineLib->ExternalStreamFinished();
        }
        
        if (discontinuityDetected)
        {
          discontinuityDetected = false;

          if (m_xineLib)
            m_xineLib->DiscontinuityDetected();
        }

        cPoller Poller(m_xineLib->getRemoteFD());
        errno = 0;
        if (Poller.Poll(100)
            && 0 == errno)
        {
          event_union_t event_union;
          
          //printf( "fd_fifo read: %d\n", fd_fifo0);
          
          if (isConnected())
          {
            int n = m_xineLib->xread(m_xineLib->getRemoteFD(), (char *)&event_union.header, sizeof (event_union.header));
            if (n == sizeof(event_union.header))
            {
              // could check that we have header we expected
              //::fprintf(stderr, "got Key: %d\n", userInput.key);
              
              if (func_key == event_union.header.func)
              {
                event_key_t *event = &event_union.key;
                int n = m_xineLib->xread(m_xineLib->getRemoteFD(), (char *)event + sizeof (event->header), sizeof (*event) - sizeof (event->header));

                if (n == sizeof (*event) - sizeof (event->header))
                {
                  if (m_remoteOn)
                  {
                    if (event->key < (sizeof (KeyMap) / sizeof (*KeyMap)))
                      cRemote::Put( KeyMap[ event->key ]);
//                    ::fprintf(stderr, "Putting Key: 0x%08x\n", KeyMap[ event->key ]);
                  }
                }
                else
                {
                  m_xineLib->disconnect();
                }
              }
              else if (func_frame_size == event_union.header.func)
              {
                event_frame_size_t *event = &event_union.frame_size;
                int n = m_xineLib->xread(m_xineLib->getRemoteFD(), (char *)event + sizeof (event->header), sizeof (*event) - sizeof (event->header));

                if (n == sizeof (*event) - sizeof (event->header))
                {
                  osdReshowRequired = true;

                  frameLeft   = event->left;
                  frameTop    = event->top;
                  frameWidth  = event->width;
                  frameHeight = event->height;
                  frameZoomX  = event->zoom_x;
                  frameZoomY  = event->zoom_y;

                  if (frameLeft  < 0) frameLeft  = 0;
                  if (frameTop   < 0) frameTop   = 0;
                  if (frameZoomX < 0) frameZoomX = 100;
                  if (frameZoomY < 0) frameZoomY = 100;

                  xfprintf(stderr, "frame: (%d, %d)-(%d, %d), zoom: (%.2lf, %.2lf)\n", frameLeft, frameTop, frameWidth, frameHeight, frameZoomX / 100.0, frameZoomY / 100.0);
                }
                else
                {
                  m_xineLib->disconnect();
                }
              }
              else if (func_discontinuity == event_union.header.func)
              {
                event_discontinuity_t *event = &event_union.discontinuity;
                int n = m_xineLib->xread(m_xineLib->getRemoteFD(), (char *)event + sizeof (event->header), sizeof (*event) - sizeof (event->header));

                if (n == sizeof (*event) - sizeof (event->header))
                {
                  discontinuityDetected = true;
                }
                else
                {
                  m_xineLib->disconnect();
                }
              }
              else if (func_play_external == event_union.header.func)
              {
                event_play_external_t *event = &event_union.play_external;
                int n = m_xineLib->xread(m_xineLib->getRemoteFD(), (char *)event + sizeof (event->header), sizeof (*event) - sizeof (event->header));

                if (n == sizeof (*event) - sizeof (event->header))
                {
                  externalStreamFinished = true;
                }
                else
                {
                  m_xineLib->disconnect();
                }
              }
              else
              {
                ::fprintf(stderr, "vdr-xine: unknown event %d!\n", event_union.header.func);
                m_xineLib->disconnect();
              }
            }
            else
            {
              m_xineLib->disconnect();
            }
          }
        }
      }
      else
      {
        if (m_active)
        {
          cMutexLock activeMutexLock(&m_activeMutex);
          if (m_active)
            m_activeCondVar.TimedWait(m_activeMutex, 100);
        }
      }
    }
    
    dsyslog ("Leaving cXineRemote thread\n");
  }

}; // namepsace PluginXine


