/*
 * config.h: Configuration file handling
 *
 * See the main source file 'vdr.c' for copyright information and
 * how to reach the author.
 *
 * $Id: config.h 1.310.1.1 2008/04/13 11:09:42 kls Exp $
 */

#ifndef __CONFIG_H
#define __CONFIG_H

#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "i18n.h"
#include "font.h"
#include "tools.h"

// VDR's own version number:

#define VDRVERSION  "1.6.0-1"
#define VDRVERSNUM   10600  // Version * 10000 + Major * 100 + Minor

// The plugin API's version number:

#define APIVERSION  "1.6.0"
#define APIVERSNUM   10600  // Version * 10000 + Major * 100 + Minor

// When loading plugins, VDR searches them by their APIVERSION, which
// may be smaller than VDRVERSION in case there have been no changes to
// VDR header files since the last APIVERSION. This allows compiled
// plugins to work with newer versions of the core VDR as long as no
// VDR header files have changed.

#define VDREXTENSIONS 59

#ifdef USE_JUMPPLAY
#define JUMPPLAYVERSNUM 9
#endif /* JUMPPLAY */

#ifdef USE_LIEMIKUUTIO
#define LIEMIKUUTIO  120
#define MAXMAINMENUTITLE 4
#define MaxTitleName 64
#endif /* LIEMIKUUTIO */

#ifdef USE_CMDSUBMENU
#define CMDSUBMENUVERSNUM 7
#endif /* CMDSUBMENU */

#ifdef USE_MAINMENUHOOKS
#define MAINMENUHOOKSVERSNUM 1.0
#endif /* MAINMENUHOOKS */

#ifdef USE_PINPLUGIN
#define PIN_PLUGIN_PATCH 120
#endif /* PINPLUGIN */

#ifdef USE_IPTV
#define PLUGINPARAMPATCHVERSNUM 1
#endif /* IPTV */

#define MAXPRIORITY 99
#define MAXLIFETIME 99

#ifdef USE_DVLVIDPREFER
#define DVLVIDPREFER_MAX 12
#endif /* DVLVIDPREFER */

#define MINOSDWIDTH  480
#define MAXOSDWIDTH  672
#define MINOSDHEIGHT 324
#define MAXOSDHEIGHT 567

#ifdef USE_SOURCECAPS
#define MAXDEVICES         16 // the maximum number of devices in the system
#define MAXSOURCECAPS     128 // the maximum number of different sources per device
#endif /* SOURCECAPS */

#ifdef USE_LNBSHARE
#ifndef MAXDEVICES
#define MAXDEVICES         16 // the maximum number of devices in the system
#endif
#endif /* LNBSHARE */

#define MaxFileName 256
#define MaxSkinName 16
#define MaxThemeName 16

#ifdef USE_CMDSUBMENU
class cCommands;
#endif /* CMDSUBMENU */

class cCommand : public cListObject {
private:
  char *title;
  char *command;
  bool confirm;
#ifdef USE_CMDSUBMENU
  int nIndent;
  cCommands *childs;
#endif /* CMDSUBMENU */
  static char *result;
public:
  cCommand(void);
  virtual ~cCommand();
  bool Parse(const char *s);
  const char *Title(void) { return title; }
  bool Confirm(void) { return confirm; }
  const char *Execute(const char *Parameters = NULL);
#ifdef USE_CMDSUBMENU
  int getIndent(void) { return nIndent; }
  void setIndent(int nNewIndent) { nIndent = nNewIndent; }
  cCommands *getChilds(void) { return childs; }
  int getChildCount(void);
  bool hasChilds(void) { return getChildCount() > 0; }
  void addChild(cCommand *newChild);
#endif /* CMDSUBMENU */
  };

typedef uint32_t in_addr_t; //XXX from /usr/include/netinet/in.h (apparently this is not defined on systems with glibc < 2.2)

class cSVDRPhost : public cListObject {
private:
  struct in_addr addr;
  in_addr_t mask;
public:
  cSVDRPhost(void);
  bool Parse(const char *s);
  bool Accepts(in_addr_t Address);
  };

template<class T> class cConfig : public cList<T> {
private:
  char *fileName;
  bool allowComments;
  void Clear(void)
  {
    free(fileName);
    fileName = NULL;
    cList<T>::Clear();
  }
public:
  cConfig(void) { fileName = NULL; }
  virtual ~cConfig() { free(fileName); }
#ifdef USE_CMDSUBMENU
  virtual void AddConfig(T *Object) { cList<T>::Add(Object); }
#endif /* CMDSUBMENU */
  const char *FileName(void) { return fileName; }
  bool Load(const char *FileName = NULL, bool AllowComments = false, bool MustExist = false)
  {
    cConfig<T>::Clear();
    if (FileName) {
       free(fileName);
       fileName = strdup(FileName);
       allowComments = AllowComments;
       }
    bool result = !MustExist;
    if (fileName && access(fileName, F_OK) == 0) {
       isyslog("loading %s", fileName);
       FILE *f = fopen(fileName, "r");
       if (f) {
          char *s;
          int line = 0;
          cReadLine ReadLine;
          result = true;
          while ((s = ReadLine.Read(f)) != NULL) {
                line++;
                if (allowComments) {
                   char *p = strchr(s, '#');
                   if (p)
                      *p = 0;
                   }
                stripspace(s);
                if (!isempty(s)) {
                   T *l = new T;
                   if (l->Parse(s))
#ifdef USE_CMDSUBMENU
                      AddConfig(l);
#else
                      Add(l);
#endif /* CMDSUBMENU */
                   else {
                      esyslog("ERROR: error in %s, line %d", fileName, line);
                      delete l;
                      result = false;
                      break;
                      }
                   }
                }
          fclose(f);
          }
       else {
          LOG_ERROR_STR(fileName);
          result = false;
          }
       }
    if (!result)
       fprintf(stderr, "vdr: error while reading '%s'\n", fileName);
    return result;
  }
  bool Save(void)
  {
    bool result = true;
    T *l = (T *)this->First();
    cSafeFile f(fileName);
    if (f.Open()) {
       while (l) {
             if (!l->Save(f)) {
                result = false;
                break;
                }
             l = (T *)l->Next();
             }
       if (!f.Close())
          result = false;
       }
    else
       result = false;
    return result;
  }
  };

#ifdef USE_CMDSUBMENU
class cCommands : public cConfig<cCommand> {
public:
  virtual void AddConfig(cCommand *Object);
  };
#else
class cCommands : public cConfig<cCommand> {};
#endif /* CMDSUBMENU */

class cSVDRPhosts : public cConfig<cSVDRPhost> {
public:
  bool Acceptable(in_addr_t Address);
  };

extern cCommands Commands;
extern cCommands RecordingCommands;
#ifdef USE_TIMERCMD
extern cCommands TimerCommands;
#endif /* TIMERCMD */
extern cSVDRPhosts SVDRPhosts;

class cSetupLine : public cListObject {
private:
  char *plugin;
  char *name;
  char *value;
public:
  cSetupLine(void);
  cSetupLine(const char *Name, const char *Value, const char *Plugin = NULL);
  virtual ~cSetupLine();
  virtual int Compare(const cListObject &ListObject) const;
  const char *Plugin(void) { return plugin; }
  const char *Name(void) { return name; }
  const char *Value(void) { return value; }
  bool Parse(char *s);
  bool Save(FILE *f);
  };

class cSetup : public cConfig<cSetupLine> {
  friend class cPlugin; // needs to be able to call Store()
private:
  void StoreLanguages(const char *Name, int *Values);
  bool ParseLanguages(const char *Value, int *Values);
  bool Parse(const char *Name, const char *Value);
#ifdef USE_SOURCECAPS
  void StoreSourceCaps(const char *Name);
  bool ParseSourceCaps(const char *Value);
#endif /* SOURCECAPS */
  cSetupLine *Get(const char *Name, const char *Plugin = NULL);
  void Store(const char *Name, const char *Value, const char *Plugin = NULL, bool AllowMultiple = false);
  void Store(const char *Name, int Value, const char *Plugin = NULL);
public:
  // Also adjust cMenuSetup (menu.c) when adding parameters here!
  int __BeginData__;
  char OSDLanguage[I18N_MAX_LOCALE_LEN];
  char OSDSkin[MaxSkinName];
  char OSDTheme[MaxThemeName];
#ifdef USE_WAREAGLEICON
  int WarEagleIcons;
#endif /* WAREAGLEICON */
#ifdef USE_VALIDINPUT
  int ShowValidInput;
#endif /* VALIDINPUT */
  int PrimaryDVB;
  int ShowInfoOnChSwitch;
  int TimeoutRequChInfo;
  int MenuScrollPage;
  int MenuScrollWrap;
  int MenuKeyCloses;
  int MarkInstantRecord;
  char NameInstantRecord[MaxFileName];
  int InstantRecordTime;
  int LnbSLOF;
  int LnbFrequLo;
  int LnbFrequHi;
  int DiSEqC;
  int SetSystemTime;
  int TimeSource;
  int TimeTransponder;
  int MarginStart, MarginStop;
  int AudioLanguages[I18N_MAX_LANGUAGES + 1];
  int DisplaySubtitles;
  int SubtitleLanguages[I18N_MAX_LANGUAGES + 1];
  int SubtitleOffset;
  int SubtitleFgTransparency, SubtitleBgTransparency;
  int EPGLanguages[I18N_MAX_LANGUAGES + 1];
  int EPGScanTimeout;
  int EPGBugfixLevel;
  int EPGLinger;
  int SVDRPTimeout;
  int ZapTimeout;
  int ChannelEntryTimeout;
  int PrimaryLimit;
  int DefaultPriority, DefaultLifetime;
  int PausePriority, PauseLifetime;
  int UseSubtitle;
  int UseVps;
  int VpsMargin;
  int RecordingDirs;
  int VideoDisplayFormat;
  int VideoFormat;
  int UpdateChannels;
  int UseDolbyDigital;
#ifdef USE_DOLBYINREC
  int UseDolbyInRecordings;
#endif /* DOLBYINREC */
#ifdef USE_DVBSETUP
  int DolbyTransferFix;
  int NoQamOnDecoder;
  int TurnOffPrimary;
#endif /* DVBSETUP */
#ifdef USE_SYNCEARLY
  int UseSyncEarlyPatch;
#endif /* SYNCEARLY */
  int ChannelInfoPos;
  int ChannelInfoTime;
  int OSDLeft, OSDTop, OSDWidth, OSDHeight;
  int OSDMessageTime;
  int UseSmallFont;
  int AntiAlias;
  char FontOsd[MAXFONTNAME];
  char FontSml[MAXFONTNAME];
  char FontFix[MAXFONTNAME];
  int FontOsdSize;
  int FontSmlSize;
  int FontFixSize;
  int MaxVideoFileSize;
#ifdef USE_HARDLINKCUTTER
  int MaxRecordingSize;
#endif /* HARDLINKCUTTER */
  int SplitEditedFiles;
#ifdef USE_HARDLINKCUTTER
  int HardLinkCutter;
#endif /* HARDLINKCUTTER */
#ifdef USE_DELTIMESHIFTREC
  int DelTimeshiftRec;
#endif /* DELTIMESHIFTREC */
  int MinEventTimeout, MinUserInactivity;
  time_t NextWakeupTime;
  int MultiSpeedMode;
  int ShowReplayMode;
#ifdef USE_DDEPGENTRY
  int DoubleEpgTimeDelta;
  int DoubleEpgAction;
  int MixEpgAction;
  int DisableVPS;
#endif /* DDEPGENTRY */
  int ResumeID;
#ifdef USE_JUMPPLAY
  int JumpPlay;
  int PlayJump;
  int PauseLastMark;
  int ReloadMarks;
#endif /* JUMPPLAY */
#ifdef USE_SOURCECAPS
  int SourceCaps[MAXDEVICES][MAXSOURCECAPS];
  bool SourceCapsSet;
#endif /* SOURCECAPS */
  int CurrentChannel;
  int CurrentVolume;
  int CurrentDolby;
  int InitialChannel;
  int InitialVolume;
#ifdef USE_VOLCTRL
  int LRVolumeControl;
  int LRChannelGroups;
  int LRForwardRewind;
#endif /* VOLCTRL */
  int EmergencyExit;
#ifdef USE_NOEPG
  int noEPGMode;
#endif /* NOEPG */
#ifdef USE_LIRCSETTINGS
  int LircRepeatDelay;
  int LircRepeatFreq;
  int LircRepeatTimeout;
#endif /* LIRCSETTINGS */
#ifdef USE_LIEMIKUUTIO
  int ShowRecDate, ShowRecTime, ShowRecLength, ShowProgressBar, MenuCmdPosition;
  int MainMenuTitle;
  char CustomMainMenuTitle[MaxTitleName];
  int ShowTimerStop;
  int JumpSeconds;
  int JumpSecondsSlow;
#endif /* LIEMIKUUTIO */
#ifdef USE_SORTRECORDS
  int RecordingsSortMode;
  int RecordingsSortDirsFirst;
#endif /* SORTRECORDS */
#ifdef USE_CUTTERQUEUE
  int CutterAutoDelete;
#endif /* CUTTERQUEUE */
#ifdef USE_LIVEBUFFER
  int LiveBuffer;
  int KeepPaused;
  int LiveBufferSize;
  int InRAM;
  int MemBufSize;
  int ExtendBuffer;
#endif /* LIVEBUFFER */
#ifdef USE_DVDARCHIVE
  int DvdDisplayMode;
  int DvdDisplayZeros;
  int DvdTrayMode;
  int DvdSpeedLimit;
#endif /* DVDARCHIVE */
#ifdef USE_LNBSHARE
  int VerboseLNBlog;
  int CardUsesLNBnr[MAXDEVICES];
#endif /* LNBSHARE */
#ifdef USE_DVLVIDPREFER
  int UseVidPrefer;  // 0 = VDR's default, 1 = use
  int nVidPrefer;
  int VidPreferPrio[DVLVIDPREFER_MAX];
  int VidPreferSize[DVLVIDPREFER_MAX];
#endif /* DVLVIDPREFER */
#ifdef USE_DVLFRIENDLYFNAMES
  int UseFriendlyFNames;
#endif /* DVLFRIENDLYFNAMES */
  int __EndData__;
#ifdef USE_NOEPG
  char *noEPGList; // pointer not to be flat-copied
#endif /* NOEPG */
  cSetup(void);
#ifdef USE_NOEPG
  ~cSetup();
#endif /* NOEPG */
  cSetup& operator= (const cSetup &s);
  bool Load(const char *FileName);
  bool Save(void);
  };

extern cSetup Setup;

#endif //__CONFIG_H
