/********************************************************************************
 * transponders.c
 * supports transponder data.
 * writen by reel-multimedia
 *
 * Contact to mhahn@reel-multimedia.com
 ********************************************************************************/

#include "transponders.h"
#include <vdr/plugin.h>
#include <vdr/sources.h>
#include <linux/dvb/frontend.h>

using std::cerr;
using std::endl;
using std::string;
using std::list;
using std::ifstream;
using std::ofstream;
using std::cout;

//----------- Class Transponder -------------------------------


cTransponder::cTransponder(int Frequency)
:frequency_(Frequency)
{
   transponderNum_ = 0;
};

int cTransponder::IntToFec(int val)
{
   int fec;
   switch (val) {
     case 12: return fec = FEC_1_2;
     case 23: return fec = FEC_2_3;
     case 34: return fec = FEC_3_4;
     case 45: return fec = FEC_4_5;
     case 56: return fec = FEC_5_6;
     case 67: return fec = FEC_6_7;
     case 78: return fec = FEC_7_8;
     default : return fec = FEC_AUTO;
   }
   return FEC_NONE;
}

//----------- Class cSatTransponder -------------------------------

cSatTransponder::cSatTransponder()
:cTransponder(0)
{
   dsyslog(DBG " cSatTransponder");
   symbolRate_ = 0;
   pol_ = ' ';
   fec_ = 0;
}

cSatTransponder::cSatTransponder(int Frequency, char Pol, int SymbolRate, int FEC)
:cTransponder(Frequency)        
{
   //frequency_ = Frequency;
   transponderNum_ = 0; // XXX
   symbolRate_ = SymbolRate;
   pol_ = Pol;
   fec_ = FEC;
}

bool cSatTransponder::SetTransponderData(cChannel *c, int Code)
{
   dsyslog (DBG " SetSatTransponderData(s:%d,f:%d,p:%c,sRate:%d,fec%d", Code, frequency_, pol_, symbolRate_, fec_);
   return c->SetSatTransponderData(Code, frequency_, pol_, symbolRate_, fec_);
}

 
bool cSatTransponder::Parse(string Line)
{
   string tpNumb(Line);
   //    cerr << "Line : " << Line << endl;

   int index = tpNumb.find_first_of('=');
   if (index == -1)
      return false;

    //cerr << "index " << index << endl;
   tpNumb =  tpNumb.erase(index);

    //   chop  string
   string tmp = Line.substr(index+1);

    // get Frequenz
   index = tmp.find_first_of(',');

   if (index == -1)
      return false;

   string freq = tmp;  // tmp.substr(index);
   freq.erase(index);

    // get Polarisatzion
   string polar =  tmp.substr(index+1);
   index = polar.find_first_of(',');
   if (index == -1)
       return false;

    // get SymbolRate
   string symRate =  polar.substr(index+1);
   polar.erase(index);


   index = symRate.find_first_of(',');
   if (index == -1)
       return false;

   string sFec = symRate.substr(index+1);
   symRate.erase(index);


   transponderNum_ = strToInt(tpNumb.c_str());
   frequency_ = strToInt(freq.c_str());
   if (frequency_ == -1) return false;
   pol_ = polar[0];
   symbolRate_ = strToInt(symRate.c_str());
   if (symbolRate_  == -1) return false;
   fec_ = IntToFec(strToInt(sFec.c_str()));

   return true;
}


//----------- Class cTerrTransponder -------------------------------

cTerrTransponder::cTerrTransponder(int ChannelNr, int Frequency, int Bandwith)
:cTransponder(Frequency)
{
   dsyslog (DBG  " cTerr Channel: %d f: %d",ChannelNr, Frequency);

   channelNum_ = ChannelNr;
   symbolrate_ = 27500;
   bandwidth_ = Bandwith;
   // fec is called Srate in vdr 
   fec_h_ = FEC_AUTO;
   fec_l_ = FEC_AUTO;
   hierarchy_ = HIERARCHY_NONE;
   modulation_ = FE_OFDM;
   guard_ =  GUARD_INTERVAL_AUTO;
   transmission_ = TRANSMISSION_MODE_AUTO;
}

cTerrTransponder::~cTerrTransponder()
{
}

bool cTerrTransponder::SetTransponderData(cChannel *c, int Code)
{
   
   int type = cSource::stTerr;

   dsyslog (DBG " SetTerrTransponderData(s:%d,f: %d ,BW: %d, mod %d, Hier %d\n,fec_h %d/l %d,G %d,T %d ", type, 
                 frequency_, bandwidth_, modulation_, hierarchy_, fec_h_, fec_l_, guard_, transmission_);
   return c->SetTerrTransponderData(type, frequency_, bandwidth_, modulation_, hierarchy_, fec_h_,
                                     fec_l_, guard_, transmission_);//
   
}

cCableTransponder::cCableTransponder(int ChannelNr, int Frequency, int Bandwith, int sRate, int Mod)
:cTransponder(Frequency)
{
   dsyslog (DBG  " cCable Channel: %d f: %d",ChannelNr, Frequency);

   channelNum_ = ChannelNr;
   symbolrate_ = sRate;
   bandwidth_ = Bandwith;

   fec_h_ = FEC_AUTO;
   hierarchy_ = HIERARCHY_NONE;
   modulation_ = Mod;
}

cCableTransponder::~cCableTransponder()
{
}

bool cCableTransponder::SetTransponderData(cChannel *c, int Code)
{
   int type = cSource::stCable;

   dsyslog(DBG " SetCableTransponderData(s:%d,f:%d,p:%c,sRate:%d,fec%d", type ,frequency_,modulation_,
                                                                         symbolrate_,fec_h_);
   return c->SetCableTransponderData(type, frequency_, modulation_, symbolrate_, fec_h_);
}

//----------- Class Transponders -------------------------------

cTransponders::cTransponders()
{
  // type S/T/C
  sourceCode_ = 0;
} 

void cTransponders::Load(int Source, int Frequency, char Pol, int Symbolrate, int FEC)
{
   //dsyslog (DBG " Manual SatLoad  --- source %d char %c Symbolrate %d fec %d",
                   //Source, Pol, Symbolrate, FEC);
   lockMs_ = 500;
   sourceCode_ = Source;
   Clear();
   cSatTransponder *t = new cSatTransponder(Frequency, Pol, Symbolrate, FEC);
   v_tp_.push_back(t);
} 

void cTransponders::Load(int Source, int SRate, int Mod)
{
  // type S/T/C
  Clear();
  sourceCode_ = Source;
  if (cSource::IsSat(sourceCode_))
  {
     dsyslog (DBG "Load SatTpls");
     fileName_ = TplFileName(Source);
     position_ = SetPosition(fileName_);
     LoadTpl(fileName_);
  }
  else if (cSource::IsTerr(sourceCode_))
  {
     dsyslog (DBG "Load TerrTpls");
     CalcTerrTpl();
  }
  else if (cSource::IsCable(sourceCode_))
  {
    CalcCableTpl(SRate, Mod);
  }
  else 
    esyslog(DBG "   Wrong  sourceCode %d",sourceCode_);

}

bool cTransponders::LoadTpl(string tplFileName)
{

  lockMs_ = 500;
  dsyslog (DBG " in LoadSatTpls %s",tplFileName.c_str());
  cerr << "Loadini(): " << tplFileName << endl;

  sourceCode_ = cSource::FromString(position_.c_str());

  ifstream tpFH(tplFileName.c_str());

  if (!tpFH)
  {
    cerr << "can`t open File: " << tplFileName << endl;
    return false;
  }

      //< flash *this first

   char line[200];
   int lc = 0;
   while (tpFH.getline(line,200))
   {
     unsigned int pos = 0;
     string l = line;
       // lookup for [
     pos =l.find('[');

     if (pos == l.npos)
     {
       cSatTransponder *t = new cSatTransponder();
       if (t->Parse(l))
          v_tp_.push_back(t);
     }
     lc++;
  }
  return true;
}


void cTransponders::CalcCableTpl(int SRate6875, int Mod256) 
{

   lockMs_ = 5000;
   Clear();

   int sRate = SRate6875==0 ?6900:6875;
   int qam = Mod256==0 ? QAM_64 : QAM_128;
      
   
   int f; 
   int channel=0;
   for (channel=2; channel <= 4; channel++)
   {
      f=36500000 + channel*7000000;
      cCableTransponder *t = new cCableTransponder(channel, f, BANDWIDTH_7_MHZ, sRate, qam);
      v_tp_.push_back(t);
   }
   
   for (channel=1; channel <= 10; channel++)
   {
      f=100500000 + channel*7000000;
      cCableTransponder *t = new cCableTransponder(channel, f, BANDWIDTH_7_MHZ, sRate, qam);
      v_tp_.push_back(t);
   }
   
   // 97,0 MHz chan + 8MHz 6,9 MHz
   for (channel=1; channel <= 9; channel++)
   {
      f=97000000 + channel*8000000;
      cCableTransponder *t = new cCableTransponder(channel, f, BANDWIDTH_8_MHZ, sRate, qam);
      v_tp_.push_back(t);
   }

   for (channel=5; channel <= 22; channel++) {
      f=142500000 + channel*7000000;
      cCableTransponder *t = new cCableTransponder(channel, f, BANDWIDTH_7_MHZ, sRate, qam);
      v_tp_.push_back(t);
   }

   for (channel=21; channel <= 90; channel++)
   {
      f=138000000 + channel*8000000;
      cCableTransponder *t = new cCableTransponder(channel, f, BANDWIDTH_8_MHZ, sRate, qam);
      v_tp_.push_back(t);
   }
  
}

void cTransponders::CalcTerrTpl()
{
   Clear();
   int f; 
   int channel=0;
   lockMs_ = 3000;
   

   //for (channel=5; channel <= 12; channel++) 
   for (channel=5; channel <= 12; channel++) 
   {
      f = 142500000 + channel*7000000;
      cTerrTransponder *t = new cTerrTransponder(channel, f, BANDWIDTH_7_MHZ);
      v_tp_.push_back(t);
   }

   // 474 000 kHz  bis 858 000 kHz
   for (channel=21; channel<= 69; channel++) 
   {
      f = 306000000 + channel*8000000;
      cTerrTransponder *t = new cTerrTransponder(channel, f, BANDWIDTH_8_MHZ);
      v_tp_.push_back(t);
   }
   
}

string cTransponders::SetPosition(string tplPath)
{
  if(cSource::IsSat(sourceCode_))
  { 
     string tmp = fileName_.substr(tplPath.find_last_of('/')+1);
     int index = tmp.find_last_of('.');
     tmp.erase(index);
     return tmp;
  }
  if(cSource::IsTerr(sourceCode_))
     return "DVB-T";

  if(cSource::IsCable(sourceCode_))
     return "DVB-C";

  return "";
}

string cTransponders::TplFileName(int satCodec)
{
  string tmp = cPlugin::ConfigDirectory();
     // TODO remove /plugins/ from tmp
  tmp += "/transponders/";
  char *buffer;
  asprintf(&buffer,"%s",*cSource::ToString(satCodec));
  tmp += buffer;
  tmp += ".tpl";
  //cerr << " ransponder list path: " << tmp << endl;
  return tmp;
}

void  cTransponders::Clear()
{
   for (vTpIter iter = v_tp_.begin(); iter != v_tp_.end(); ++iter)
       delete *iter;

    v_tp_.clear();
}
/*
Das Erste;BR:212500000:I0C34D12M16B7T8G4Y0:T:27500:513:514=deu:516:0:32:8468:12289:0
arte;BR:212500000:I0C34D12M16B7T8G4Y0:T:27500:33:34=deu,35=fra:36:0:2:8468:12289:0
Phoenix;BR:212500000:I0C34D12M16B7T8G4Y0:T:27500:49:50=deu:52:0:3:8468:12289:0
EinsPlus;BR:212500000:I0C34D12M16B7T8G4Y0:T:27500:97:98=deu:516:0:6:8468:12289:
*/
