#include "receiver.h"
#include "dec.h"
#include <unistd.h>
#include <vdr/receiver.h>
#include <vdr/ringbuffer.h>
#include <vdr/osdcontroller.h>
#include <vdr/dvbsub.h>

#include "page.h"
#include "sync.h"
//#include <vdr/tools.h>

#define PAYLOAD_UNIT_START 0x40
#define TS_PACKET_SIZE 188
#define ADAPTATION_FIELD_CONTROL 0x30

using namespace NonInteractiveOsdPatch;
 
cSubtitlesReceiver::cSubtitlesReceiver(int SubPid, int Priority)
  : cReceiver(0, -1, SubPid), viewer(), subPid(SubPid),
priority(Priority),clearTime(0)
{
  //  fprintf(stderr, "receiver started with subtitling pid = %i\n",SubPid);
  mutex = new cMutex;
  decoder = new cDecoder();
  ringBuffer = new cRingBufferLinear(1024*188,188,true);
  subPid = SubPid;
  syncer = GetSynchronizer();
  subscribed = false;
}

cSubtitlesReceiver::~cSubtitlesReceiver()
{
  mutex->Lock();
  if (subscribed)
    OsdController.Unsubscribe(&viewer);
  mutex->Unlock();
  syncer->stop();
  Detach();

  //No more calls to the ::Receive
  delete ringBuffer;
  delete syncer;

  mutex->Lock();
  delete decoder;
  mutex->Unlock();
  delete mutex;

}

void cSubtitlesReceiver::Activate(bool On){

  if (On)
  {
    Start();
  }
  else
    {
      active=false;
      Cancel(3);
    }

  
}

void cSubtitlesReceiver::Receive(uchar *Data, int Length){

  if (!active || Length < 188)
    return;
  int p = ringBuffer->Put( Data, Length );
  if ( p < Length )
    esyslog("DvbSubtitles-receiver: Ring buffer overflow\n");

}

void cSubtitlesReceiver::Action( void ){

  active=true;  
  while (active) {
    
    {
      cMutexLock(mutex);
      int numBytes = TS_PACKET_SIZE;
      const uchar *b = ringBuffer->Get(numBytes);
      if ( b ) 
      {
	int numPackets = numBytes/TS_PACKET_SIZE;
	
	for (int i = 0; active && i < numPackets; i++ )
	{
	  processTSPacket( b + i*TS_PACKET_SIZE );
	}
      
	ringBuffer->Del( TS_PACKET_SIZE*numPackets );
      }
      if ( active && decoder->PageAvailable() )
      {
      
	if (!subscribed)
	{
	  OsdController.Subscribe(priority,&viewer);
	  subscribed = true;
	}
#if DEBUG
	fprintf(stderr, "Priority=%i receiver got page\n",priority);
#endif
	cSubtitlesPage* page = decoder->GetPage();
      
	syncer->sync(page->GetPts());
      
	viewer.SetPage( page );
	if (page->GetTimeout())
	  clearTime = msectime()+ page->GetTimeout()*1000;
	else
	  clearTime = 0;
	//delete page;
      }
    }
    // page timeout
    if (clearTime > 0 && msectime() > clearTime)
    {
      viewer.Clear();
      clearTime = 0;
    }
    usleep(10000);

  }
}

void cSubtitlesReceiver::processTSPacket(const uchar* Data)
{
  
  // XXX Handle transport errors
  bool newPacket = (Data[1] & PAYLOAD_UNIT_START) != 0;
  int  afc = ( Data[3] & ADAPTATION_FIELD_CONTROL ) >> 4;
  
  if ( afc == 0x2 )
    return;

  // Handle continuity counter

  int index = 4;
  if ( afc == 0x3 )
  {
    index += Data[index]+1;
  }
  decoder->addPesData( Data + index , TS_PACKET_SIZE-index, newPacket);
}

