#include <string.h>
#include <vdr/tools.h>
#include <vdr/channels.h>
#include <vdr/plugin.h>
#include "autogroup.h"
#include "autosort_tools.h"
#include "autosort_menu.h"

//#define DEBUG_GROUP_PARSING


cAutoGroup::cAutoGroup(void)
{
  pIdx = 0;
  oIdx = 0;
//  name = strdup("");
//  startName = strdup("");
  name = NULL;
  startName = NULL; // valgrind
  
  hasNameList     = new cMultiList;
  notNameList     = new cMultiList;
  hasSourceList   = new cMultiList;
  hasProviderList = new cMultiList;
  notProviderList = new cMultiList;
  caValueList     = new cMultiList;
  notCaValueList  = new cMultiList;
  audioLangList   = new cMultiList;
  priority = 99;
  order = 500;
  fixedPos = -1;
  subSections = false;
  sort = false;
  keepHere = false;
  setCaFF = false;
  setCa0 = false;
  isSpecial = false;
  saveDelete = false;
  realDelete = false;
  iCanSee = 0;
  hasApid = 0;
  hasVpid = 0;
  hasTpid = 0;
  hasCa = 0;
  hasOpenCa = 0;
  hasClosedCa = 0;
  hasOpenProvider = 0;
  hasClosedProvider = 0;
  timeStampDays = 0;
}

cAutoGroup::~cAutoGroup()
{
//  dsyslog("cAutoGroup Destructor for %s", name);
  free(name);
  free(startName);
  hasNameList->Clear();     delete hasNameList;
  notNameList->Clear();     delete notNameList;
  hasSourceList->Clear();   delete hasSourceList;
  hasProviderList->Clear(); delete hasProviderList;
  notProviderList->Clear(); delete notProviderList;
  caValueList->Clear();     delete caValueList;
  notCaValueList->Clear();  delete notCaValueList;
  audioLangList->Clear();   delete audioLangList;
}

cAutoGroup *cAutoGroup::Copy(cAutoGroup *OldGroup)
{
  cAutoGroup *NewGroup = new cAutoGroup;
  name              = OldGroup->Name();
  priority          = OldGroup->Priority();
  order             = OldGroup->Order();
  fixedPos          = OldGroup->FixedPos();
  subSections       = OldGroup->SubSections();
  sort              = OldGroup->Sort();
  keepHere          = OldGroup->KeepHere();
  setCaFF           = OldGroup->SetCaFF();
  setCa0            = OldGroup->SetCa0();
  isSpecial         = OldGroup->IsSpecial();
  saveDelete        = OldGroup->SaveDelete();
  realDelete        = OldGroup->RealDelete();
  iCanSee           = OldGroup->ICanSee();
  hasApid           = OldGroup->HasApid();
  hasVpid           = OldGroup->HasVpid();
  hasTpid           = OldGroup->HasTpid();
  hasCa             = OldGroup->HasCa();
  hasOpenCa         = OldGroup->HasOpenCa();
  hasClosedCa       = OldGroup->HasClosedCa();
  hasOpenProvider   = OldGroup->HasOpenProvider();
  hasClosedProvider = OldGroup->HasClosedProvider();
  timeStampDays     = OldGroup->TimeStampDays();

  hasNameList     = OldGroup->HasNameList()->Copy();
  notNameList     = OldGroup->NotNameList()->Copy();
  hasSourceList   = OldGroup->HasSourceList()->Copy();
  hasProviderList = OldGroup->HasProviderList()->Copy();
  notProviderList = OldGroup->NotProviderList()->Copy();
  caValueList     = OldGroup->CaValueList()->Copy();
  notCaValueList  = OldGroup->NotCaValueList()->Copy();
  audioLangList   = OldGroup->AudioLangList()->Copy();
  return NewGroup;
}


int cAutoGroup::GetChIndex(void)
{
  cChannel *channel = Channels.Last();
  while (channel){
    if ((strcmp(channel->Name(),name) == 0) && channel->GroupSep()) return channel->Index();
    if (strcmp(channel->Name(),"Auto Sort") == 0) return 0;
    channel = Channels.Get(Channels.GetPrevGroup(channel->Index()));
    }  
  return 0;
}

void cAutoGroup::Print(void)
{
  dsyslog("AutoGroupPrint:");
  dsyslog("  Name:          %s",name);
  dsyslog("  Index:         %d",Index());
  dsyslog("  Priority:      %d",priority);
  dsyslog("  Priority Index:%d",pIdx);
  dsyslog("  Order:         %d",order);
  dsyslog("  Order Index:   %d",oIdx);
  if (fixedPos < 0) { 		dsyslog("  FixedPosition: None");}
    else {            		dsyslog("  FixedPosition: %d",fixedPos); }
  if (timeStampDays == 0) { 	dsyslog("  TimeStamp:     Dont't care about");}
    else {            		dsyslog("  TimeStamp:     %d days old",timeStampDays); }
  if (subSections) {  		dsyslog("  SubSections:   Yes"); }
    else {            		dsyslog("  SubSections:   No"); }
  if (sort) {         		dsyslog("  Sort:          Yes"); }
    else {            		dsyslog("  Sort:          No"); }
  if (keepHere) {     		dsyslog("  KeepHere:      Yes"); }
    else {            		dsyslog("  KeepHere:      No"); }
  if (setCaFF) {      		dsyslog("  SetCaFF:       Yes"); }
    else {            		dsyslog("  SetCaFF:       No"); }
  if (setCa0) {       		dsyslog("  SetCa0:        Yes"); }
    else {            		dsyslog("  SetCa0:        No"); }
  if (saveDelete) {       	dsyslog("  SaveDelete:        Yes"); }
    else {            		dsyslog("  SaveDelete:        No"); }
  if (realDelete) {       	dsyslog("  RealDelete:        Yes"); }
    else {            		dsyslog("  RealDelete:        No"); }
  if (hasApid  < 0) {     	dsyslog("  Apid:          Must NOT have"); }
  if (hasApid == 0) {     	dsyslog("  Apid:          Don't care about"); }
  if (hasApid  > 0) {     	dsyslog("  Apid:          Must have"); }
  if (hasVpid  < 0) {     	dsyslog("  Vpid:          Must NOT have"); }
  if (hasVpid == 0) {     	dsyslog("  Vpid:          Don't care about"); }
  if (hasVpid  > 0) {     	dsyslog("  Vpid:          Must have"); }
  if (hasTpid  < 0) {     	dsyslog("  Tpid:          Must NOT have"); }
  if (hasTpid == 0) {     	dsyslog("  Tpid:          Don't care about"); }
  if (hasTpid  > 0) {     	dsyslog("  Tpid:          Must have"); }
  if (iCanSee  < 0) {       	dsyslog("  ICanSee:       No"); }
  if (iCanSee == 0) {       	dsyslog("  ICanSee:       Don't care about"); }
  if (iCanSee  > 0) {       	dsyslog("  ICanSee:       Yes"); }
  if (hasCa  < 0) {       	dsyslog("  Ca:            Must NOT have"); }
  if (hasCa == 0) {       	dsyslog("  Ca:            Don't care about"); }
  if (hasCa  > 0) {       	dsyslog("  Ca:            Must have"); }
  if (hasOpenCa  < 0) {   	dsyslog("  OpenCa:        Must NOT have"); }
  if (hasOpenCa == 0) {   	dsyslog("  OpenCa:        Don't care about"); }
  if (hasOpenCa  > 0) {   	dsyslog("  OpenCa:        Must have"); }  
  if (hasClosedCa  < 0) { 	dsyslog("  ClosedCa:      Must NOT have"); }
  if (hasClosedCa == 0) { 	dsyslog("  ClosedCa:      Don't care about"); }
  if (hasClosedCa  > 0) { 	dsyslog("  ClosedCa:      Must have"); }
  if (hasOpenProvider  < 0) {   dsyslog("  OpenProvider:  Must NOT have"); }
  if (hasOpenProvider == 0) {   dsyslog("  OpenProvider:  Don't care about"); }
  if (hasOpenProvider  > 0) {   dsyslog("  OpenProvider:  Must have"); }  
  if (hasClosedProvider  < 0) { dsyslog("  ClosedProvider:Must NOT have"); }
  if (hasClosedProvider == 0) { dsyslog("  ClosedProvider:Don't care about"); }
  if (hasClosedProvider  > 0) { dsyslog("  ClosedProvider:Must have"); }
  if (!strcmp(startName,"")) { 	dsyslog("  StartName:     Don't care about");}
    else {                     	dsyslog("  StartName:     %s",startName); }
  for (cMultiOption *option = hasNameList->First(); option; option = hasNameList->Next(option)) {
                                dsyslog("  HasName        %s",option->Value());              } 
  for (cMultiOption *option = notNameList->First(); option; option = notNameList->Next(option)) {
                                dsyslog("  NotName        %s",option->Value());              } 
  for (cMultiOption *option = hasSourceList->First(); option; option = hasSourceList->Next(option)) {
                                dsyslog("  HasSource      %s",option->Value());              } 
  for (cMultiOption *option = hasProviderList->First(); option; option = hasProviderList->Next(option)) {
                                dsyslog("  HasProvider    %s",option->Value());              } 
  for (cMultiOption *option = notProviderList->First(); option; option = notProviderList->Next(option)) {
                                dsyslog("  NotProvider    %s",option->Value());              } 
  for (cMultiOption *option = caValueList->First(); option; option = caValueList->Next(option)) {
                                dsyslog("  CaValue        %s",option->Value());              } 
  for (cMultiOption *option = notCaValueList->First(); option; option = notCaValueList->Next(option)) {
                                dsyslog("  NotCaValue     %s",option->Value());              } 
  for (cMultiOption *option = audioLangList->First(); option; option = audioLangList->Next(option)) {
                                dsyslog("  AudioLang      %s",option->Value());              } 
}

//ToDo: Change this
//refer HISTORY 1.3.36
#define MAXPARSEBUFFER KILOBYTE(10)

bool cAutoGroup::Parse(const char *line)
{
  char *subline;
  subline = strdup(line);
  char *option = strtok(subline,":");
  bool nameFound = false;
  while (option != NULL)
  {
    if (!nameFound) { 
       name = option;
       nameFound = true;
       }
    else {
      ParseOption(option);
      }
    option = strtok(NULL,":");
  }

  // check for additional config files
  char *buf;
//  asprintf(&buf, "%s/%s/%s",cPlugin::ConfigDirectory(),"autosort",name );
  asprintf(&buf, "%s/%s/%s",ConfigDir,"autosort",name );


    if (access(buf, R_OK) == 0) {
      dsyslog ("loading %s", buf);
      FILE *f = fopen(buf, "r");
      if (f) {
	char buffer[MAXPARSEBUFFER];
        while (fgets(buffer, sizeof(buffer), f) > 0) {
           char *p = strchr(buffer, '#');
           if (p) continue;
	  stripspace(buffer);
          if (!isempty(buffer)) {
            option = strtok(buffer,":");
	    ParseOption(option);
            }
          }
        fclose(f);
        }
      }
  subline=NULL;
  free(subline);
  option=NULL;
  free(option);
  free(buf);


  CopyOpenGroups();
  DeleteDoubles();
#ifdef DEBUG_GROUP_PARSING
  Print();
#endif
  if (!strcasecmp(name,"Auto Sort") ||
      !strcasecmp(name,"Unsorted") ||
      !strcasecmp(name,"Dummy") ||
      !strcasecmp(name,"Dummy2") ||
      !strcasecmp(name,"New Channels")) {
	esyslog("AutoSort -ERROR-  Found unallowed AutoGroup name: '%s'",name);
	esyslog("       !!! Check your autosort.conf !!!");
        return false;
	}
  else if (priority < 0 || priority > 99  ||
           order    < 1 || order    > 999 ||
           fixedPos < -1 ) {
	     esyslog("AutoSort -ERROR-  Found wrong Priority, Order or FixedPos in AutoGroup '%s'",name);
	     esyslog("       !!! Check your autosort.conf !!!");
             return false;     
             }
  else if (setCaFF && setCa0) {
	esyslog("AutoSort -ERROR-  Found SetCaFF and SetCa0 in same AutoGroup '%s'",name);
	esyslog("       !!! Check your autosort.conf !!!");
        return false;
	}  
  else return true;



}

bool cAutoGroup::ParseOption(char *option)
{
//  int i = 0;
         if (!strcasecmp(option, "HasApid"))          hasApid =  1; 
    else if (!strcasecmp(option, "HasNoApid"))        hasApid = -1; 
    else if (!strcasecmp(option, "HasVpid"))          hasVpid =  1; 
    else if (!strcasecmp(option, "HasNoVpid"))        hasVpid = -1; 
    else if (!strcasecmp(option, "HasTpid"))          hasTpid =  1; 
    else if (!strcasecmp(option, "HasNoTpid"))        hasTpid = -1; 
    else if (!strcasecmp(option, "ICanSee"))          iCanSee =  1; 
    else if (!strcasecmp(option, "ICanNotSee"))       iCanSee = -1; 

    else if (!strcasecmp(option, "HasCa"))            hasCa =  1; 
    else if (!strcasecmp(option, "HasNoCa"))          hasCa = -1; 
    else if (!strcasecmp(option, "HasOpenCa"))        hasOpenCa =  1; 
    else if (!strcasecmp(option, "HasNoOpenCa"))      hasOpenCa = -1; 
    else if (!strcasecmp(option, "HasClosedCa"))      hasClosedCa =  1; 
    else if (!strcasecmp(option, "HasNoClosedCa"))    hasClosedCa = -1; 

    else if (!strcasecmp(option, "HasOpenProvider"))        hasOpenProvider =  1; 
    else if (!strcasecmp(option, "HasNoOpenProvider"))      hasOpenProvider = -1; 
    else if (!strcasecmp(option, "HasClosedProvider"))      hasClosedProvider =  1; 
    else if (!strcasecmp(option, "HasNoClosedProvider"))    hasClosedProvider = -1; 

    else if (!strcasecmp(option, "SubSections"))      subSections = true; 
    else if (!strcasecmp(option, "Sort"))             sort = true; 
    else if (!strcasecmp(option, "keepHere"))         keepHere = true; 
    else if (!strcasecmp(option, "SetCaFF"))          setCaFF = true; 
    else if (!strcasecmp(option, "SetCa0"))           setCa0 = true; 
    else if (!strcasecmp(option, "SaveDelete"))       saveDelete = true; 
    else if (!strcasecmp(option, "Delete"))           saveDelete = true; 
    else if (!strcasecmp(option, "RealDelete"))       realDelete = true; 
    else if (!strncasecmp(option, "Priority",8))     { strsep(&option,"="); priority = atoi(option); } 
    else if (!strncasecmp(option, "Order",5))        { strsep(&option,"="); order =    atoi(option); } 
    else if (!strncasecmp(option, "FixedPos",8))     { strsep(&option,"="); fixedPos = atoi(option); } 
    else if (!strncasecmp(option, "TimeStamp",9))    { strsep(&option,"="); timeStampDays = atoi(option); } 
    else if (!strncasecmp(option, "StartName",9))    { strsep(&option,"="); startName = option; } 
    else if (!strncasecmp(option, "HasName",7))      { strsep(&option,"="); hasNameList->AddValue(UpString(option)); }
    else if (!strncasecmp(option, "NotName",7))      { strsep(&option,"="); notNameList->AddValue(UpString(option)); }
    else if (!strncasecmp(option, "HasSource",9))    { strsep(&option,"="); hasSourceList->AddValue(UpString(option)); }
    else if (!strncasecmp(option, "HasProvider",11)) { strsep(&option,"="); hasProviderList->AddValue(UpString(option)); }
    else if (!strncasecmp(option, "NotProvider",11)) { strsep(&option,"="); notProviderList->AddValue(UpString(option)); }
    else if (!strncasecmp(option, "CaValue",7))      { strsep(&option,"="); caValueList->AddValue(UpString(option)); }
    else if (!strncasecmp(option, "NotCaValue",10))  { strsep(&option,"="); notCaValueList->AddValue(UpString(option)); }
    else if (!strncasecmp(option, "AudioLang",9))    { strsep(&option,"="); audioLangList->AddValue(UpString(option)); }

    else {
      esyslog("AutoSort -WARNING-: Found unknown option '%s' in AutoGroup '%s'", option, name);
      esyslog("       !!! Check your autosort.conf !!!");
      return false;
      }
    
  return true;
}

void cAutoGroup::CopyOpenGroups(void){
  if (hasOpenCa > 0) {
     dsyslog("AutoSort-Group '%s': Appending OpenCa to CaValue", name); 
     caValueList->AppendList(OpenGroups.OpenCa());     
     }
  if (hasOpenCa < 0) {
     dsyslog("AutoSort-Group '%s': Appending OpenCa to NotCaValue", name); 
     notCaValueList->AppendList(OpenGroups.OpenCa());     
     }
  if (hasClosedCa > 0) { 
     dsyslog("AutoSort-Group '%s': Appending ClosedCa to CaValue", name);
     caValueList->AppendList(OpenGroups.ClosedCa());     
     }
  if (hasClosedCa < 0) { 
     dsyslog("AutoSort-Group '%s': Appending ClosedCa to NotCaValue", name);
     notCaValueList->AppendList(OpenGroups.ClosedCa());     
     }
  if (hasOpenProvider > 0) { 
     dsyslog("AutoSort-Group '%s': Appending OpenProvider to HasProvider", name);
     hasProviderList->AppendList(OpenGroups.OpenProvider());
     }
  if (iCanSee > 0) { // badly tested, does it what we expect?
     dsyslog("AutoSort-Group '%s': Appending OpenProvider to HasProvider (via iCanSee)", name);
     hasProviderList->AppendList(OpenGroups.OpenProvider());
     dsyslog("AutoSort-Group '%s': Appending OpenCa to CaValue (via iCanSee)", name); 
     caValueList->AppendList(OpenGroups.OpenCa());     
     }

  if (hasOpenProvider < 0) { 
     dsyslog("AutoSort-Group '%s': Appending OpenProvider to NotProvider", name); 
     notProviderList->AppendList(OpenGroups.OpenProvider());     
     }
  if (hasClosedProvider > 0) { 
     dsyslog("AutoSort-Group '%s': Appending ClosedProvider to HasProvider", name);
     hasProviderList->AppendList(OpenGroups.ClosedProvider());     
     }
  if (hasClosedProvider < 0) { 
     dsyslog("AutoSort-Group '%s': Appending ClosedProvider to NotProvider", name); 
     notProviderList->AppendList(OpenGroups.ClosedProvider());     
     }
}


void cAutoGroup::DeleteDoubles(void)
{
  char *result = NULL;
  result = hasNameList->DeleteDoubles();
  if (result != NULL) isyslog("AutoSort-Group '%s': Deleted double HasName '%s'", name, result);
  result = notNameList->DeleteDoubles();
  if (result != NULL) isyslog("AutoSort-Group '%s': Deleted double NotName '%s'", name, result);
  result = hasSourceList->DeleteDoubles();
  if (result != NULL) isyslog("AutoSort-Group '%s': Deleted double HasSource '%s'", name, result);
  result = hasProviderList->DeleteDoubles();
  if (result != NULL) isyslog("AutoSort-Group '%s': Deleted double HasProvider '%s'", name, result);
  result = notProviderList->DeleteDoubles();
  if (result != NULL) isyslog("AutoSort-Group '%s': Deleted double NotProvider '%s'", name, result);
  result = caValueList->DeleteDoubles();
  if (result != NULL) isyslog("AutoSort-Group '%s': Deleted double CaValue '%s'", name, result);
  result = notCaValueList->DeleteDoubles();
  if (result != NULL) isyslog("AutoSort-Group '%s': Deleted double NotCaValue '%s'", name, result);
  result = audioLangList->DeleteDoubles();
  if (result != NULL) isyslog("AutoSort-Group '%s': Deleted double AudioLang '%s'", name, result);
  result = NULL;
  free(result);
}

//#undef DELETECA
void cAutoGroup::ModifyChannelToGroup (int ChIndex, bool Out)
{
  //ToDo: rewrite this to reduce #ifdefs
  cChannel *channel = Channels.Get(ChIndex);
  const int CaFF[] = {255,0};
#ifndef DELETECA
  const int Ca0[] = {0};
#endif
  if (!Out) { // channel will go into group
    if (saveDelete) {
      FILE *f;
//      char *fileName = strdup( AddDirectory(cPlugin::ConfigDirectory(), "../channels.deleted"));
      char *fileName = strdup( AddDirectory(ConfigDir, "../channels.deleted"));
      f = fopen(fileName , "a");
      if (!f) {
        LOG_ERROR_STR(fileName);
      } else {
        if (channel->Save( f )){
	  // Need global channel Loop Control
          //cChannel *prev = Channels.Prev(channel);	  
          //Channels.Del(channel);
	  //channel = prev;
          }
	}
      fclose(f);
      f = NULL;
      free(fileName);    
      }
    if (realDelete) {
      //Channels.Del(channel);
      }
    if (setCaFF) {
#ifdef DELETECA
      channel->DeleteCaIds();
#else      
      if ((channel->Ca(0) >= 0x0001) && (channel->Ca(0) <= 0x00FF)){
        isyslog("AutoSort: -WARNING- You need the 'deleteca'-patch for '%s'", channel->Name());
      } else {
        channel->SetCaIds(Ca0);      
        }
#endif      
      channel->SetCaIds(CaFF);
      }
    if (setCa0) {
#ifdef DELETECA
      channel->DeleteCaIds();
#else      
      if ((channel->Ca(0) >= 0x0001) && (channel->Ca(0) <= 0x00FF)){
        isyslog("AutoSort: -WARNING- You need the 'deleteca'-patch for '%s'", channel->Name());
      } else {
        channel->SetCaIds(Ca0);      
        }
#endif      
      }
  } else { // channel will go out of group
    if (setCaFF) {
#ifdef DELETECA
      channel->DeleteCaIds();
#else      
      if ((channel->Ca(0) >= 0x0001) && (channel->Ca(0) <= 0x00FF)){
        isyslog("AutoSort: -WARNING- You need the 'deleteca'-patch for '%s'", channel->Name());
      } else {
        channel->SetCaIds(Ca0);      
        }
#endif      
      }
    }
  channel =NULL;
  free(channel);
}


// --- ChannelFitsGroup ---------------------------------
//#define DEBUG_CFG 1

bool cAutoGroup::ChannelFitsGroup (int ChIndex)
{
  cChannel *channel = Channels.Get(ChIndex);
#ifdef DEBUG_CFG
  dsyslog(" --------------------------------- ");
  dsyslog("check if channel %s fits group %s", channel->Name(),name);
#endif
  int j = 0;
  bool fits = false;
// ------------------------------------------------------


  // --- ICanSee ---
  if (( iCanSee > 0) && (channel->Ca(0) != 0 )) {
    fits = false;
    if (hasProviderList->First()){
      for (cMultiOption *option = hasProviderList->First(); option; option = hasProviderList->Next(option)) {
        if (strstr(UpString(strdup(channel->Provider())),option->Value())) {
          fits = true;
          }
        }
      }
    if (caValueList->First()){
      char *caHex;  
      for (cMultiOption *option = caValueList->First(); option; option = caValueList->Next(option)) {
        j = 0;      
        while (channel->Ca(j) != 0) {
          caHex="";	
	  asprintf(&caHex, "%X", channel->Ca(j));	
          if (strstr(strdup(caHex),option->Value())) { // ToDo: change behavor
            fits = true;
            }	  
	  j++;
	  }
        }
      caHex=NULL;
      free(caHex);
      }
    if (!fits) { 
#ifdef DEBUG_CFG
      dsyslog("channel %s kicked out by 'ICanSee'", channel->Name());
#endif    
      channel=NULL;
      free(channel);
      return false; 
      }
    }

  // --- HasName ---
  if (hasNameList->First()){
    fits = false;
    for (cMultiOption *option = hasNameList->First(); option; option = hasNameList->Next(option)) {
      if (strstr(UpString(strdup(channel->Name())),option->Value())) {
        fits = true;
	}
      }
    if (!fits) {
#ifdef DEBUG_CFG
      dsyslog("channel %s kicked out by 'HasName'", channel->Name());
#endif    
      channel=NULL;
      free(channel);
      return false;
      }
    }

  // --- HasProvider --
  if (hasProviderList->First()){
    fits = false;
    for (cMultiOption *option = hasProviderList->First(); option; option = hasProviderList->Next(option)) {
      if (strstr(UpString(strdup(channel->Provider())),option->Value())) {
        fits = true;
	}
      }
    if (!fits) { 
#ifdef DEBUG_CFG
      dsyslog("channel %s kicked out by 'HasProvider'", channel->Name());
#endif    
      channel=NULL;
      free(channel);
      return false; 
      }
    }

  // --- StartName ---
//  if (strcmp(startName, "") != 0) {
  if (startName ) {
    if (strncasecmp(startName, channel->Name(), 1) != 0) { 
#ifdef DEBUG_CFG
      dsyslog("channel %s kicked out by 'StartName'", channel->Name());
#endif    
      channel=NULL;
      free(channel);
      return false; 
      }
    }

  // --- HasNoApid ---
  if (( hasApid < 0) && (channel->Apid(0) != 0 )) { 
#ifdef DEBUG_CFG
    dsyslog("channel %s kicked out by 'HasNoApid'", channel->Name());
#endif    
    channel=NULL;
    free(channel);
    return false; 
    }

  // --- TimeStamp ---
  if (timeStampDays > 0) {
    if (strstr(channel->ShortName(),"ASTS")){
      char *buf = strdup(channel->ShortName());
      strsep(&buf,"-");
      int stamp = atoi(buf);
      buf = NULL; // YY
      free(buf); // YY
      if ((time(NULL) - stamp) < ( timeStampDays * 86400 )) { 
#ifdef DEBUG_CFG
        dsyslog("channel %s kicked out by 'TimeStamp' (not old enought)", channel->Name());
#endif    
        channel=NULL;
        free(channel);
	return false; // not old enought
	}
    } else {
#ifdef DEBUG_CFG
      dsyslog("channel %s kicked out by 'TimeStamp' (no TimeStamp)", channel->Name());
#endif    
      channel=NULL;
      free(channel);
      return false; // no TimeStamp
      }
    }

  // --- HasVpid ---
  if (( hasVpid > 0) && (channel->Vpid()  == 0 )) {
#ifdef DEBUG_CFG
    dsyslog("channel %s kicked out by 'HasVpid'", channel->Name());
#endif    
    channel=NULL;
    free(channel);
    return false; 
    }

  // --- HasCa ---
  if (( hasCa   > 0) && (channel->Ca(0)   == 0 )) { 
#ifdef DEBUG_CFG
    dsyslog("channel %s kicked out by 'HasCa'", channel->Name());
#endif    
    channel=NULL;
    free(channel);
    return false; 
    }

  // --- HasNoCa ---
  if (( hasCa   < 0) && (channel->Ca(0)   != 0 )) { 
#ifdef DEBUG_CFG
    dsyslog("channel %s kicked out by 'HasNoCa'", channel->Name());
#endif    
    channel=NULL;
    free(channel);
    return false; 
    }

  // --- NotCaValue ---
  if (notCaValueList->First()){
    fits = false;
    char *caHex;  
    for (cMultiOption *option = notCaValueList->First(); option; option = notCaValueList->Next(option)) {
      j = 0;      
      while (channel->Ca(j) != 0) {
        caHex="";	
	asprintf(&caHex, "%X", channel->Ca(j));	
        if (strstr(strdup(caHex),option->Value())) {
          caHex=NULL;
          free(caHex);
#ifdef DEBUG_CFG
          dsyslog("channel %s kicked out by 'NotCaValue'", channel->Name());
#endif    
          channel=NULL;
          free(channel);
          return false;
          }	  
	j++;
	}
      }
    caHex=NULL;
    free(caHex);
    }

  // --- HasNoVpid ---
  if (( hasVpid < 0) && (channel->Vpid()  != 0 )) { 
#ifdef DEBUG_CFG
    dsyslog("channel %s kicked out by 'HasNoVpid'", channel->Name());
#endif    
    channel=NULL;
    free(channel);
    return false; 
    }

  // --- NotProvider ---
  if (notProviderList->First()){
    fits = false;
    for (cMultiOption *option = notProviderList->First(); option; option = notProviderList->Next(option)) {
      if (strstr(UpString(strdup(channel->Provider())),option->Value())) {
#ifdef DEBUG_CFG
        dsyslog("channel %s kicked out by 'NotProvider'", channel->Name());
#endif    
        channel=NULL;
        free(channel);
        return false;
	}
      }
    }

  // --- NotName ---
  if (notNameList->First()){
    fits = false;
    for (cMultiOption *option = notNameList->First(); option; option = notNameList->Next(option)) {
      if (strstr(UpString(strdup(channel->Name())),option->Value())) {
#ifdef DEBUG_CFG
        dsyslog("channel %s kicked out by 'NotName'", channel->Name());
#endif    
        channel=NULL;
        free(channel);
        return false;
	}
      }
    }

  // --- AudioLang ---
  if (audioLangList->First()){
    fits = false;
    for (cMultiOption *option = audioLangList->First(); option; option = audioLangList->Next(option)) {
      j = 0;
      while (strcmp(channel->Alang(j),"") != 0) {
        if (strstr(UpString(strdup(channel->Alang(j))),option->Value())) {
          fits = true;
          }
	j++;
	}
      }
    if (!fits) { 
#ifdef DEBUG_CFG
      dsyslog("channel %s kicked out by 'AudioLang'", channel->Name());
#endif    
      channel=NULL;
      free(channel);
      return false; 
      }
    }

  // --- CaValue ---
  if (caValueList->First()){
    fits = false;
    char *caHex;  
    for (cMultiOption *option = caValueList->First(); option; option = caValueList->Next(option)) {
      j = 0;      
      while (channel->Ca(j) != 0) {
        caHex="";	
	asprintf(&caHex, "%X", channel->Ca(j));	
        if (strstr(strdup(caHex),option->Value())) { // ToDo: change behavor
          fits = true;
          }	  
	j++;
	}
      }
    caHex=NULL;
    free(caHex);
    if (!fits) { 
#ifdef DEBUG_CFG
      dsyslog("channel %s kicked out by 'CaValue'", channel->Name());
#endif    
      channel=NULL;
      free(channel);
      return false; 
      }
    }

  // --- HasNoTpid ---
  if (( hasTpid < 0) && (channel->Tpid()  != 0 )) { 
#ifdef DEBUG_CFG
    dsyslog("channel %s kicked out by 'HasNoTpid'", channel->Name());
#endif    
    channel=NULL;
    free(channel);
    return false; 
    }

  // --- HasApid ---
  if (( hasApid > 0) && (channel->Apid(0) == 0 )) { 
#ifdef DEBUG_CFG
    dsyslog("channel %s kicked out by 'HasApid'", channel->Name());
#endif    
    channel=NULL;
    free(channel);
    return false; 
    }

  // --- HasTpid ---
  if (( hasTpid > 0) && (channel->Tpid()  == 0 )) { 
#ifdef DEBUG_CFG
    dsyslog("channel %s kicked out by 'HasTpid'", channel->Name());
#endif    
    channel=NULL;
    free(channel);
    return false; 
    }

  // --- HasSource ---
  if (hasSourceList->First()){
    fits = false;
    for (cMultiOption *option = hasSourceList->First(); option; option = hasSourceList->Next(option)) {
      if (channel->Source() == cSource::FromString(option->Value())) {
        fits = true;
	}
      }
    if (!fits) {
#ifdef DEBUG_CFG
      dsyslog("channel %s kicked out by 'HasSource'", channel->Name());
#endif    
      channel=NULL;
      free(channel);
      return false; 
      }
    }

// ----------------------------------------------------
#ifdef DEBUG_CFG
  dsyslog(" +++++++++++++++++++++++++++++++++ ");
  dsyslog("channel %s fits group %s", channel->Name(),name);
  dsyslog(" +++++++++++++++++++++++++++++++++ ");
#endif
  channel=NULL;
  free(channel);
  return true;
}
