/*
 * autotimeredit: A plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id: ddictionary.c 1.7 2005/10/19 23:22:17 hflor Exp $
 */

#include "ddictionary.h"
#include "autotimeredit.h"
#include "autotimers.h"
#include <vdr/timers.h>
#include <vdr/recording.h>

// -- cDefaultDictionary -----------------------------------------------------------------

cDefaultDictionary::cDefaultDictionary(const char *Dictionary, int Source, int Blacklist, int Includesub)
{
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionary::cDefaultDictionary Dictionary=%s Source=0x%02X Blacklist=%s", plugin_name, Dictionary, Source, Blacklist ? Includesub ? "sub" : "yes" : "no");
#endif
  if (strlen(Dictionary))
    strn0cpy(dictionary, Dictionary, sizeof(dictionary));
  else
    dictionary[0] = 0;
  source = Source;
  blacklist = Blacklist;
  includesub = Includesub;
}

cDefaultDictionary::cDefaultDictionary(cDefaultDictionary *Copy)
{
  if (Copy) {
#ifdef ATE_Debug2
    dsyslog("%s: cDefaultDictionary::cDefaultDictionary Copy Dictionary=%s Source=0x%02X Blacklist=%s", plugin_name, Copy->dictionary, Copy->source, Copy->blacklist ? Copy->includesub ? "sub" : "yes" : "no");
#endif
    strcpy(dictionary, Copy->dictionary);
    source = Copy->source;
    blacklist = Copy->blacklist;
    includesub = Copy->includesub;
  }
}

cDefaultDictionary::cDefaultDictionary(void)
{
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionary::cDefaultDictionary", plugin_name);
#endif
  dictionary[0] = 0;
  source = Source_none;
  blacklist = false;
  includesub = false;
}

cDefaultDictionary::~cDefaultDictionary(void)
{
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionary::~cDefaultDictionary dictionary=%s source=0x%02X blacklist=%s", plugin_name, dictionary, source, blacklist ? "yes" : "no");
#endif
  // Clean up
}

cDefaultDictionary& cDefaultDictionary::operator= (const cDefaultDictionary &DefaultDictionary)
{
  memcpy(this, &DefaultDictionary, sizeof(*this));
  return *this;
}

#if VDRVERSNUM >= 10315
int cDefaultDictionary::Compare(const cListObject &ListObject) const
{
  cDefaultDictionary *DD = (cDefaultDictionary *)&ListObject;
  int cmp = strcasecmp(dictionary, DD->dictionary);
  if (cmp == 0)
    return blacklist == DD->blacklist ? 0 : blacklist < DD->blacklist ? -1 : 1;
  else
    return cmp;
}  
#else
bool cDefaultDictionary::operator< (const cListObject &ListObject)
{
  cDefaultDictionary *DD = (cDefaultDictionary *)&ListObject;
  int cmp = strcasecmp(dictionary, DD->dictionary);
  if (cmp == 0)
    return blacklist > DD->blacklist;
  else
    return cmp < 0;
}
#endif


void cDefaultDictionary::SetValues(const char *Dictionary, int Source, int Blacklist, int Includesub)
{
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionary::SetValues Dictionary=%s Source=0x%02X Blacklist=%s", plugin_name, Dictionary, Source, Blacklist ? Includesub ? "sub" : "yes" : "no");
#endif
  if (strlen(Dictionary))
    strn0cpy(dictionary, Dictionary, sizeof(dictionary));
  else
    dictionary[0] = 0;
  source = Source;
  blacklist = Blacklist;
  includesub = Includesub;
}

void cDefaultDictionary::OnOff(void)
{
  if (blacklist)
    if (includesub)
      blacklist = false;
    else
      includesub = true;
  else  {
    blacklist = true;
    includesub = false;
  }
}

// -- cDefaultDictionarys ----------------------------------------------------------------

cDefaultDictionarys DefaultDictionarys;
cDefaultDictionarys CommandlineDefaultDictionarys;
cDefaultDictionarys SetupDefaultDictionarys;

void cDefaultDictionarys::DelDictionarys(eSource Source)
{
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionarys::DelDictionarys Source=0x%02X", plugin_name, Source);
#endif
  cDefaultDictionary *DD = First();
  while (DD) {
    if (DD->isSource(Source)) {
      if (DD->isOnlySource(Source)) {
        cDefaultDictionary *DDd = DD;
        DD = Next(DD);
        Del(DDd);
      } else {
        DD->DelSource(Source);
        DD = Next(DD);
      }
    } else
      DD = Next(DD);
  }
}

void cDefaultDictionarys::AddDictionarysFromAutoTimers(void)
{
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionarys::AddDictionarysFromAutoTimers", plugin_name);
#endif
  DelDictionarys(Source_AutoTimers);
  if (use_defaultdictionary.u & Source_AutoTimers) {
    cAutoTimer *autotimer = AutoTimers.First();
    while (autotimer) {
      if (strlen(autotimer->Folder()))
        DefaultDictionarys.Add(new cDefaultDictionary(autotimer->Folder(), Source_AutoTimers));
      autotimer = AutoTimers.Next(autotimer);
    }
  }
}

void cDefaultDictionarys::AddDictionarysFromTimers(void)
{
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionarys::AddDictionarysFromTimers", plugin_name);
#endif
  DelDictionarys(Source_Timers);
  if (use_defaultdictionary.u & Source_Timers) {
    cTimer *timer = Timers.First();
    while (timer) {
      const char *file = timer->File();
      const char *last = strrchr(file, '~');
      char dictionary[MaxFileName];
      if (last) {
        strn0cpy(dictionary, file, size_t(last - file) < sizeof(dictionary) ? last - file + 1 : sizeof(dictionary));
        DefaultDictionarys.Add(new cDefaultDictionary(dictionary, Source_Timers));
      }
      timer = Timers.Next(timer);
    }
  }
}

void cDefaultDictionarys::AddDictionarysFromRecords(void)
{
  static time_t lastsearch = 0;
  static int m_use_defaultdictionary = 0;
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionarys::AddDictionarysFromRecords 0x%02X lastsearch=%d now=%d (diff=%d) time=%d v1=%d v2=%d", plugin_name, use_defaultdictionary.u, int(lastsearch), int(time(NULL)), int(time(NULL) - lastsearch), updatetimerecords.u, m_use_defaultdictionary, (use_defaultdictionary.u & (Source_Commandline | Source_Setup)));
#endif
  if (use_defaultdictionary.u & Source_Records) {
    if (lastsearch == 0 || updatetimerecords.u == 0 || m_use_defaultdictionary != (use_defaultdictionary.u & (Source_Commandline | Source_Setup)) || updatetimerecords.u > 0 && (updatetimerecords.u * 3600 < int(time(NULL) - lastsearch)) || CountSource(Source_Records) == 0) {
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionarys::AddDictionarysFromRecords run update", plugin_name);
#endif
      m_use_defaultdictionary = (use_defaultdictionary.u & (Source_Commandline | Source_Setup));
      DelDictionarys(Source_Records);
      cRecordings Recordings;
      char dictionary[MaxFileName];
      char dictionarylast[MaxFileName];
      dictionarylast[0] = 0;
      if (Recordings.Load()) {
        cRecording *recording = Recordings.First();
        while (recording) {
          const char *name = recording->Name();
          const char *last = strrchr(name, '~');
          if (last) {
            strn0cpy(dictionary, name, size_t(last - name) < sizeof(dictionary) ? last - name + 1 : sizeof(dictionary));
            if (strcasecmp(dictionary, dictionarylast)) {
              DefaultDictionarys.Add(new cDefaultDictionary(dictionary, Source_Records));
              strcpy(dictionarylast, dictionary);
            }
          }
          recording = Recordings.Next(recording);
        }
        lastsearch = time(NULL);
      }
    }
  } else
    DelDictionarys(Source_Records);
}

void cDefaultDictionarys::AddDictionarysFromCommandline(void)
{
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionarys::AddDictionarysFromCommandline", plugin_name);
#endif
  DelDictionarys(Source_Commandline);
  if (use_defaultdictionary.u & Source_Commandline) {
    cDefaultDictionary *defaultdictionary = CommandlineDefaultDictionarys.First();
    while (defaultdictionary) {
      DefaultDictionarys.Add(new cDefaultDictionary(defaultdictionary));
      defaultdictionary = CommandlineDefaultDictionarys.Next(defaultdictionary);
    }
  }
}

void cDefaultDictionarys::AddDictionarysFromSetup(void)
{
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionarys::AddDictionarysFromSetup", plugin_name);
#endif
  DelDictionarys(Source_Setup);
  if (use_defaultdictionary.u & Source_Setup) {
    cDefaultDictionary *defaultdictionary = SetupDefaultDictionarys.First();
    while (defaultdictionary) {
      DefaultDictionarys.Add(new cDefaultDictionary(defaultdictionary));
      defaultdictionary = SetupDefaultDictionarys.Next(defaultdictionary);
    }
  }
}

void cDefaultDictionarys::FillDefaultDictionary(void)
{
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionarys::FillDefaultDictionary", plugin_name);
#endif
  static char *Empty = "";
  CountDefaultDictionarys = 0;
  SelDefaultDictionary[0] = Empty;
  cDefaultDictionary *DD = First();
  while (DD && CountDefaultDictionarys < (MaxDefaultDictionary - 1)) {
    if (!DD->Blacklist())
      SelDefaultDictionary[++CountDefaultDictionarys] = DD->Dictionary();
    DD = Next(DD);
  }
  CountDefaultDictionarys++;
}

int cDefaultDictionarys::CountSource(eSource Test)
{
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionarys::CountSource Test=0x%02X", plugin_name, Test);
#endif
  int i = 0;
  cDefaultDictionary *DD = First();
  while (DD) {
    if (DD->isSource(Test))
      i++;
    DD = Next(DD);
  }
  return i;
}

void cDefaultDictionarys::MergeDictionary(void)
{
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionarys::MergeDictionary Count()=%d", plugin_name, Count());
#endif
  cDefaultDictionary *DD1;
  cDefaultDictionary *DD2;
  bool identic;
  int i = Count();
  if (i == 1) {
    DD1 = Get(0);
    if (DD1->Source() == Source_none)
      Del(DD1);
  }
  if (i < 2)
    return;
  Sort();
  for (i = 1; i < Count();) {
    DD2 = Get(i);
    if (DD2->Source() == Source_none) {
      Del(DD2);
    } else {
      DD1 = Get(i -1);
      if (DD1->Includesub())
        identic = !strncasecmp(DD1->Dictionary(), DD2->Dictionary(), strlen(DD1->Dictionary()));
      else
        identic = !strcasecmp(DD1->Dictionary(), DD2->Dictionary());
      if (identic) {
        if (DD1->Blacklist() == DD2->Blacklist())
          DD1->AddSource(DD2->Source());
        Del(DD2);
      } else
        i++;
    }
  }
  if (Count() > 0) {
    DD1 = Get(0);
    if (DD1->Source() == Source_none)
      Del(DD1);
  }
}

void cDefaultDictionarys::AddMergeFill(void)
{
  AddDictionarysFromAutoTimers();
  AddDictionarysFromTimers();
  AddDictionarysFromRecords();
  AddDictionarysFromCommandline();
  AddDictionarysFromSetup();
  MergeDictionary();
  FillDefaultDictionary();
}

int cDefaultDictionarys::SearchDictionary(const char *Search)
{
#ifdef ATE_Debug2
  dsyslog("%s: cDefaultDictionarys::SearchDictionary Search=%s CountDefaultDictionarys=%d", plugin_name, Search, CountDefaultDictionarys);
#endif
  int i = CountDefaultDictionarys;
  while (--i) {
    if (!strncasecmp(SelDefaultDictionary[i], Search, strlen(SelDefaultDictionary[i]))) {
      return i;
    }
  }
  return 0;
}
