/********************************************************************************
 * scan.c
 * provides scanning through given tansponder lists
 * writen by reel-multimedia
 *
 * Contact to mhahn@reel-multimedia.com
 ********************************************************************************/


#include <time.h>
#include <sys/ioctl.h>
#include <vdr/device.h>
#include "channelscan.h"
#include "csmenu.h"
#include "scan.h"


#define SCAN_DELAY 15

bool scanning_on_receiving_device = false;

using std::list;
using std::cout;

cScan::cScan()
{
   cTransponders &transponders = cTransponders::GetInstance();
   sourceCode = transponders.SourceCode();
   newChannels = 0;
   fd_frontend= -1;
   cardnr = -1;
   currentTp = 0;

   PFilter=NULL;
   SFilter=NULL;
}

//--------- Destuctor ~cScan -----------------------------------

cScan::~cScan()
{
  currentTp = 0;
  //worst case
  cMenuChannelscan::scanning = false;
  Cancel(5000);

  if (fd_frontend > 0)
     close(fd_frontend);
  
  scanning_on_receiving_device = false;
  scanning_by_channelscan = false;

  if (PFilter)
    cDevice::GetDevice(cardnr)->Detach(PFilter);
  if (SFilter)
    cDevice::GetDevice(cardnr)->Detach(SFilter);

  PFilter=NULL;
  SFilter=NULL;
}

//---------  cMainMenu::Action()  -----------------------------------

void cScan::Action()
{
   dsyslog(DBG " Action ");
   
   displayVideo = true;

   device = cDevice::GetDevice(cardnr);
   cChannel *c = new cChannel;

   dsyslog(DBG " loop thrugh all transponders ");
   cTransponders &transponders = cTransponders::GetInstance();
   // loop through all Transponders
   for (vTpIter tp = transponders.v_tp_.begin(); tp != transponders.v_tp_.end(); ++tp)
   {
        
     if (!cMenuChannelscan::scanning)
        break;

	  // get counter
     currentTp = tp - transponders.v_tp_.begin();

     dsyslog(DBG " SetTransponder data ");
     (*tp)->SetTransponderData(c, sourceCode);

     dsyslog(DBG " switch channel ");
     if (!device->SwitchChannel(c,true))
        esyslog(ERR "SwitchChannel(c)  failed");
    
     if (cDevice::GetDevice(cardnr)->HasLock(transponders.LockMs()))
     {
        dsyslog(DBG "  ------------- HAS LOCK -------------     ");
        PFilter = new PatFilter();
        SFilter = new SdtFilter(PFilter);
        PFilter->SetSdtFilter(SFilter);
        device->AttachFilter(SFilter);
        device->AttachFilter(PFilter);

        time_t start=time(NULL);

        while(!PFilter->EndOfScan() && time(NULL) - start < SCAN_DELAY && cMenuChannelscan::scanning)
           usleep(10);

        device->Detach(PFilter);
        device->Detach(SFilter);
        PFilter = NULL;
        SFilter = NULL;
    }
    else 
        dsyslog(DBG "  !!!! NO  LOCK -------------     ");
            
  } // Scanning loop

  cMenuChannelscan::scanning = false;
    
    if(channel) //  && scanning_on_receiving_device)
        cDevice::PrimaryDevice()->SwitchChannel(channel,true);
       //cDevice::PrimaryDevice()->Play();

    delete c;
    scanning_on_receiving_device = false;
    scanning_by_channelscan = false;

    return;
} // END of Action()

bool cScan::StartScanning()
{
  dsyslog(DBG " StartScanning"); 

  cTransponders &transponders = cTransponders::GetInstance();
  dsyslog(DBG " Ping "); 

  channel = Channels.GetByNumber(cDevice::CurrentChannel());
  scanning_by_channelscan = true;
  bool needsDetachReceivers = true;
    
  cDevice::PrimaryDevice()->StopReplay();
  // ask device.Provides(sourceCode) if reciving 
  cardnr = -1;
  // lockup which device provides this  source

  cChannel tempchannel;
  
  transponders.v_tp_[0]->SetTransponderData(&tempchannel, transponders.SourceCode());

  for (int i=0; i<cDevice::NumDevices(); i++)
  {
     if (cDevice::GetDevice(i)->ProvidesSource(sourceCode))
     {
        cerr << "Device " << i << "provides Source " << sourceCode << endl;
        if (cDevice::GetDevice(i)->ProvidesChannel(&tempchannel, 0 ,&needsDetachReceivers))
        {
           dsyslog(DBG  "????  Device %d providesTestChannel; needsDetachReceiver? %s",
                           i, needsDetachReceivers?"YES":"NO");
           if(!needsDetachReceivers) 
           {
              cardnr=i;
              scanning_on_receiving_device = true;
              break;
           }
            
        }
        else
           cerr << "Device " << i << "++ !!!! provides NOT TestTransponder +++ !!!\n";
                
     
     }
     if (cDevice::GetDevice(i)->ProvidesSource(sourceCode) && 
                !cDevice::GetDevice(i)->Receiving(true)) // test all  reciever
     {
        dsyslog(DBG " Source %d  device %d", sourceCode, i);
        cerr << "Source " <<  sourceCode << "device" << i << endl;

		  // if blindscan is active  this methode will fail!

            // switch channel in background 
        cDevice::GetDevice(i)->SwitchChannel(&tempchannel, false);

        if (cDevice::GetDevice(i)->HasLock(1000))
        {
            cardnr=i;
            scanning_on_receiving_device = true;
            break;
         }
         dsyslog(DBG " ******** Source  %d   device %d", sourceCode, i);
         cerr << " *********  Source " <<  sourceCode << "device" << i << endl;
      }
  }

  if (cardnr==-1)
  {
     for (int i=0; i<cDevice::NumDevices(); i++) 
     {

         if (cDevice::GetDevice(i)->ProvidesSource(sourceCode)
                && cDevice::GetDevice(i)->Receiving(true) // test all reciver
                && !cDevice::GetDevice(i)->Receiving())   // test current  reciever
         {
                cardnr=i;
                dsyslog(DBG " ******** Device found: Source %d  device %d", sourceCode, i);
                cerr << " *********  Device found:  " <<  sourceCode << "device" << i << endl;
                scanning_on_receiving_device = true;
                break;
         }
     }
  }

  if (cardnr==-1)
  { 
     cardnr = 0;
     scanning_by_channelscan = false;
     dsyslog(DBG " +++++++++++++++++++++++++  No valid Card found");
     return false;
  }

  char *buffer;
  asprintf(&buffer,"/dev/dvb/adapter%d/frontend0", cardnr);

  fd_frontend = open(buffer,O_RDONLY | O_NONBLOCK);
  if (fd_frontend <= 0)
    cerr << "cant open device: " << buffer << endl;
  
  free(buffer);

     // setting scanning state only here
  cMenuChannelscan::scanning = true;
  dsyslog(DBG " End Start scanning CallStart");
  Start();

  return true;
}
