/*
 * See the README file for copyright information and how to reach the author.
 */

#include <stdarg.h>
#include <vdr/menu.h>
#include "mysetup.h"

typedef struct {
  int Width;
  int Align;
} RecListDefaultType;

RecListDefaultType recListDefaultValues[MAX_COLTYPES] = {
  { 0,0},
  { 5,0},
  { 8,0},
  { 5,0},
  {14,0},
  { 4,2},
  { 7,0},
  { 5,0},
#if (APIVERSNUM >= 20505)
  { 5,0},
  { 1,0}
#else
  { 5,0}
#endif
};


cNestedItemList RecordingDirCommands;

mySetup::mySetup()
{
  mysetup.HideMainMenuEntry = 0;
  mysetup.PatchNew = 1;
  mysetup.ReplaceOrgRecMenu = 0;

  for (int i = 0; i < MAX_RECLIST_COLUMNS; i++)
     mysetup.RecListColumn[0].Type = COLTYPE_NONE;

  mysetup.RecListColumn[0].Type = COLTYPE_DATE;
  STRN0CPY(mysetup.RecListColumn[0].Name, "");
  mysetup.RecListColumn[0].Width = recListDefaultValues[mysetup.RecListColumn[0].Type].Width;
  mysetup.RecListColumn[0].Align = recListDefaultValues[mysetup.RecListColumn[0].Type].Align;
  STRN0CPY(mysetup.RecListColumn[0].Op1, "");
  STRN0CPY(mysetup.RecListColumn[0].Op2, "");

  mysetup.RecListColumn[1].Type = COLTYPE_TIME;
  STRN0CPY(mysetup.RecListColumn[1].Name, "");
  mysetup.RecListColumn[1].Width = recListDefaultValues[mysetup.RecListColumn[1].Type].Width;
  mysetup.RecListColumn[1].Align = recListDefaultValues[mysetup.RecListColumn[1].Type].Align;
  STRN0CPY(mysetup.RecListColumn[1].Op1, "");
  STRN0CPY(mysetup.RecListColumn[1].Op2, "");

  mysetup.ShowNewRecs = 1;
  mysetup.RecsPerDir = 2;
  mysetup.RecRefreshRate = 5;
  mysetup.GoLastReplayed = 0;
  mysetup.ReturnToPlugin = 1;
  mysetup.ReturnToRec = 0;
  mysetup.UseVDRsRecInfoMenu = 0;
  mysetup.PatchFont = 1;
  mysetup.FileSystemFreeMB = 1;
  mysetup.SetRecordingCat = 1;
  mysetup.FileSystemFreeMB = 0;
  mysetup.UndeleteTimeOut = 10;
  mysetup.ButtonFirst = 0;
  mysetup.ErrorCount = 1;
}

mySetup mysetup;

bool mySetup::SetupParse(const char *Name, const char *Value)
{
  bool rc = true;
  if (!strcasecmp(Name, "IsOrgRecMenu"))
     return (mysetup.ReplaceOrgRecMenu == false); // vdr-replace patch
  if (!strncasecmp(Name, "RecListColumn.", 14)) {
     char *tmp = NULL;
     for (int i = 0; i < MAX_RECLIST_COLUMNS; i++) {
        if (asprintf(&tmp,"RecListColumn.%d", i) == -1) {
           rc = false;
           }
        else {
           if (!strcasecmp(Name, tmp)) {
              const char *m;
              // get 'Name' from config line
              m  = strstr(Value, "name=");
              if (m) {
                 char *tmp = strdup(m + 5);
                 if (strchr(tmp, ',')) *strchr(tmp, ',') = 0;
                    STRN0CPY(mysetup.RecListColumn[i].Name, tmp);
                 free(tmp);
                 }
              else {
                 mysetup.RecListColumn[i].Type = COLTYPE_NONE;
                 rc = false;
                 break;
                 }
              // get 'Type' from config line
              m  = strstr(Value, "type=");
              if (m) {
                 char *tmp = strdup(m + 5);
                 if (strchr(tmp, ',')) *strchr(tmp, ',') = 0;
                    mysetup.RecListColumn[i].Type = atoi(tmp);
                 free(tmp);
                 }
              else {
                 mysetup.RecListColumn[i].Type = COLTYPE_NONE;
                 rc = false;
                 break;
                 }
              // get 'Width' from config line
	      m  = strstr(Value, "width=");
              if (m) {
                 char *tmp = strdup(m + 6);
                 if (strchr(tmp, ',')) *strchr(tmp, ',') = 0;
                    mysetup.RecListColumn[i].Width = atoi(tmp);
                 free(tmp);
                 }
              else {
                 mysetup.RecListColumn[i].Type = COLTYPE_NONE;
                 rc = false;
                 break;
                 }
              // get 'Align' from config line
              m  = strstr(Value, "align=");
              if (m) {
                 char *tmp = strdup(m + 6);
                 if (strchr(tmp, ',')) *strchr(tmp, ',') = 0;
                 mysetup.RecListColumn[i].Align = atoi(tmp);
                 free(tmp);
                 }
              else {
                 mysetup.RecListColumn[i].Type = COLTYPE_NONE;
                 rc = false;
                 break;
                 }
              // get 'Op1' from config line
              m  = strstr(Value, "op1=");
              if (m) {
                 char *tmp = strdup(m + 4);
                 if (strchr(tmp, ',')) *strchr(tmp, ',') = 0;
                    STRN0CPY(mysetup.RecListColumn[i].Op1, tmp);
                 free(tmp);
                 }
              else {
                 mysetup.RecListColumn[i].Type = COLTYPE_NONE;
                 rc = false;
                 break;
                 }
              // get 'Op2' from config line
              m  = strstr(Value, "op2=");
              if (m) {
                 char *tmp = strdup(m + 4);
                 STRN0CPY(mysetup.RecListColumn[i].Op2, tmp);
                 free(tmp);
                 }
              else {
                 mysetup.RecListColumn[i].Type = COLTYPE_NONE;
                 rc = false;
                 break;
                 }
              break;
              }
           free(tmp);
           }
        }
     }
  else if (!strcasecmp(Name, "HideMainMenuEntry"))  mysetup.HideMainMenuEntry  = atoi(Value);
  else if (!strcasecmp(Name, "ReplaceOrgRecMenu"))  mysetup.ReplaceOrgRecMenu  = atoi(Value);
  else if (!strcasecmp(Name, "PatchNew"))           mysetup.PatchNew           = atoi(Value);
  else if (!strcasecmp(Name, "ShowNewRecs"))        mysetup.ShowNewRecs        = atoi(Value);
  else if (!strcasecmp(Name, "RecsPerDir"))         mysetup.RecsPerDir         = atoi(Value);
  else if (!strcasecmp(Name, "RecRefreshRate"))     mysetup.RecRefreshRate     = atoi(Value);
  else if (!strcasecmp(Name, "GoLastReplayed"))     mysetup.GoLastReplayed     = atoi(Value);
  else if (!strcasecmp(Name, "ReturnToPlugin"))     mysetup.ReturnToPlugin     = atoi(Value);
  else if (!strcasecmp(Name, "UseVDRsRecInfoMenu")) mysetup.UseVDRsRecInfoMenu = atoi(Value);
  else if (!strcasecmp(Name, "PatchFont"))          mysetup.PatchFont          = atoi(Value);
  else if (!strcasecmp(Name, "FileSystemFreeMB"))   mysetup.FileSystemFreeMB   = atoi(Value);
  else if (!strcasecmp(Name, "SetRecordingCat"))    mysetup.SetRecordingCat    = atoi(Value);
  else if (!strcasecmp(Name, "UndeleteTimeOut"))    mysetup.UndeleteTimeOut    = atoi(Value);
  else if (!strcasecmp(Name, "ButtonFirst"))        mysetup.ButtonFirst        = atoi(Value);
  else if (!strcasecmp(Name, "ErrorCount"))         mysetup.ErrorCount        = atoi(Value);
  else rc = false;
  return rc;
}

/******************** myMenuSetup ********************/
myMenuSetup::myMenuSetup()
{
  SetCols(45);
  hidemainmenuentry   = mysetup.HideMainMenuEntry;
  patchnew            = mysetup.PatchNew;
  replaceorgrecmenu   = mysetup.ReplaceOrgRecMenu;

  for (int i = 0; i < MAX_RECLIST_COLUMNS; i++) {
    reclistcolumn[i].Type         = mysetup.RecListColumn[i].Type;
    STRN0CPY(reclistcolumn[i].Name, mysetup.RecListColumn[i].Name);
    reclistcolumn[i].Width        = mysetup.RecListColumn[i].Width;
    reclistcolumn[i].Align        = mysetup.RecListColumn[i].Align;
    STRN0CPY(reclistcolumn[i].Op1 , mysetup.RecListColumn[i].Op1);
    STRN0CPY(reclistcolumn[i].Op2 , mysetup.RecListColumn[i].Op2);
  }

  shownewrecs         = mysetup.ShowNewRecs;
  recsperdir          = mysetup.RecsPerDir;
  recrefreshrate      = mysetup.RecRefreshRate;
  golastreplayed      = mysetup.GoLastReplayed;
  returntoplugin      = mysetup.ReturnToPlugin;
  usevdrsrecinfomenu  = mysetup.UseVDRsRecInfoMenu;
  patchfont           = mysetup.PatchFont;
  filesystemfreemb    = mysetup.FileSystemFreeMB;
  setrecordingcat     = mysetup.SetRecordingCat;
  undeletetimeout     = mysetup.UndeleteTimeOut;
  buttonfirst         = mysetup.ButtonFirst;
  errorcount          = mysetup.ErrorCount;
  fileSystemFreeMB[0] = tr("no");
  fileSystemFreeMB[1] = tr("original");
  fileSystemFreeMB[2] = tr("per file system");
  buttonFirst[0]      = tr("Button$UNDELETE");
  buttonFirst[1]      = tr("Button$Commands");
  Set();
}

void myMenuSetup::Set()
{
  int currentItem = Current();
  Clear();
  Add(new cMenuEditBoolItem(tr("Show nr. of new recordings of a directory"),   &shownewrecs));
  Add(new cMenuEditStraItem(tr("Maximum number of recordings per directory"),  &recsperdir, 5, RecsPerDir_texts));
  Add(SubMenuItem(tr("Items to show in recording list"),                       osUser1)); 
  Add(new cMenuEditBoolItem(tr("Show alternative to new marker"),              &patchnew));
  Add(new cMenuEditBoolItem(tr("Set menu category"),                           &setrecordingcat));
  Add(new cMenuEditStraItem(tr("Show free disk space"),                        &filesystemfreemb, 3, fileSystemFreeMB));
  Add(new cMenuEditIntItem(tr("Refreshrate of recordings list (s) (0 = off)"), &recrefreshrate, 0, 10));
  Add(new cMenuEditBoolItem(tr("Hide main menu entry"),                        &hidemainmenuentry));
#ifdef MAINMENUHOOKSVERSNUM
  Add(new cMenuEditBoolItem(tr("Replace original recordings menu"),            &replaceorgrecmenu));
#endif
  Add(new cMenuEditBoolItem(tr("Jump to last replayed recording"),             &golastreplayed));
  Add(new cMenuEditBoolItem(tr("Call plugin after playback"),                  &returntoplugin));
  Add(new cMenuEditBoolItem(tr("Use VDR's recording info menu"),               &usevdrsrecinfomenu));
  Add(new cMenuEditIntItem(tr("Red button UNDELETE timeout (s)"),              &undeletetimeout, 0, 10, trVDR("off")));
  if (undeletetimeout)
     Add(new cMenuEditStraItem(tr("Displayed first (UNDELETE or Commands)"),   &buttonfirst, 2, buttonFirst));
#if (APIVERSNUM >= 20505)
  Add(new cMenuEditIntItem(tr("Number of errors for error sign"),              &errorcount, 1, 100));
#endif

  SetCurrent(Get(currentItem));
  Display();
  SetHelp(NULL, NULL, NULL, NULL);
}

void myMenuSetup::Store()
{
  SetupStore("HideMainMenuEntry",  mysetup.HideMainMenuEntry  = hidemainmenuentry);
  SetupStore("PatchNew",           mysetup.PatchNew           = patchnew);
  SetupStore("ReplaceOrgRecMenu",  mysetup.ReplaceOrgRecMenu  = replaceorgrecmenu);
  char varname[16];
  char* tmp = NULL;
  for (int i = 0; i < MAX_RECLIST_COLUMNS; i++) {
     if (asprintf(&tmp, "type=%d,name=%s,width=%d,align=%d,op1=%s,op2=%s",
                      reclistcolumn[i].Type,
                      reclistcolumn[i].Name && (reclistcolumn[i].Type == COLTYPE_FILE || reclistcolumn[i].Type == COLTYPE_FILETHENCOMMAND) ? reclistcolumn[i].Name : "",
                      reclistcolumn[i].Width,
                      reclistcolumn[i].Align,
                      reclistcolumn[i].Op1 && (reclistcolumn[i].Type == COLTYPE_FILE || reclistcolumn[i].Type == COLTYPE_FILETHENCOMMAND) ? reclistcolumn[i].Op1 : "",
                      reclistcolumn[i].Op2 && reclistcolumn[i].Type == COLTYPE_FILETHENCOMMAND ? reclistcolumn[i].Op2 : "") != -1) {
        mysetup.RecListColumn[i].Type         = reclistcolumn[i].Type;
        STRN0CPY(mysetup.RecListColumn[i].Name, reclistcolumn[i].Name);
        mysetup.RecListColumn[i].Width        = reclistcolumn[i].Width;
        mysetup.RecListColumn[i].Align        = reclistcolumn[i].Align;
        STRN0CPY(mysetup.RecListColumn[i].Op1,  reclistcolumn[i].Op1);
        STRN0CPY(mysetup.RecListColumn[i].Op2,  reclistcolumn[i].Op2);

        snprintf(varname, 16, "RecListColumn.%d", i);
        SetupStore(varname, tmp);
        free(tmp);
        }
     }
  SetupStore("ShowNewRecs",        mysetup.ShowNewRecs        = shownewrecs);
  SetupStore("RecsPerDir",         mysetup.RecsPerDir         = recsperdir);
  SetupStore("RecRefreshRate",     mysetup.RecRefreshRate     = recrefreshrate);
  SetupStore("GoLastReplayed",     mysetup.GoLastReplayed     = golastreplayed);
  SetupStore("ReturnToPlugin",     mysetup.ReturnToPlugin     = returntoplugin);
  SetupStore("UseVDRsRecInfoMenu", mysetup.UseVDRsRecInfoMenu = usevdrsrecinfomenu);
  SetupStore("PatchFont",          mysetup.PatchFont          = patchfont);
  SetupStore("FileSystemFreeMB",   mysetup.FileSystemFreeMB   = filesystemfreemb);
  SetupStore("SetRecordingCat",    mysetup.SetRecordingCat    = setrecordingcat);
  SetupStore("UndeleteTimeOut",    mysetup.UndeleteTimeOut    = undeletetimeout);
  SetupStore("ButtonFirst",        mysetup.ButtonFirst        = buttonfirst);
  SetupStore("ErrorCount",         mysetup.ErrorCount         = errorcount);
}

eOSState myMenuSetup::ProcessKey(eKeys Key) {
  int oldSetRecordingCat = setrecordingcat;
  int oldundeletetimeout = undeletetimeout;
  eOSState state = cMenuSetupPage::ProcessKey(Key);
  if (Key != kNone && ((oldSetRecordingCat != setrecordingcat) || oldundeletetimeout != undeletetimeout)) {
     Set();
     }
  switch (state) {
     case osUser1:
        return AddSubMenu(new myMenuSetupColumns(&reclistcolumn[0]));
     case osUser9: Store(); return osBack;
     default: ;
     }
  return state;
}


/******************** myMenuSetupColumns ********************/
myMenuSetupColumns::myMenuSetupColumns(RecListColumnType *prlcs) : cOsdMenu(tr("Items to show in recording list"), 4) {
  preclistcolumns = prlcs;
  SetMenuCategory(mcPluginSetup);

  ColumnType_descriptions[0] = tr("--none--");
  ColumnType_descriptions[1] = tr("Blank");
  ColumnType_descriptions[2] = tr("Date of Recording");
  ColumnType_descriptions[3] = tr("Time of Recording");
  ColumnType_descriptions[4] = tr("Date and Time of Recording");
  ColumnType_descriptions[5] = tr("Length of Recording");
  ColumnType_descriptions[6] = tr("Rating of Recording");
  ColumnType_descriptions[7] = tr("Content of File");
  ColumnType_descriptions[8] = tr("Content of File, then Result of a Command");
#if (APIVERSNUM >= 20505)
  ColumnType_descriptions[9] = tr("Recording Error");
#endif
  AlignmentType_names[0]     = tr("left");
  AlignmentType_names[1]     = tr("center");
  AlignmentType_names[2]     = tr("right");
  Set();
}

void myMenuSetupColumns::Set() {
  SetCols(30);
  // build up menu entries
//  SetHelp(tr("Edit"), NULL, NULL, NULL);  //SetHelp(tr("Edit"), NULL, tr("Move Up"), tr("Move down"));
  // save current postion
  int current = Current();
  // clear entries, if any
  Clear();
  cOsdItem *sItem;
  char *itemStr;
  int ret;
  ret = asprintf(&itemStr, "%s\t%s", tr("Icon"), tr("(fixed to the first position)"));
  if (ret <= 0) {
     esyslog("Error allocating linebuffer for cOsdItem.");
     return;
     }
  sItem = new cOsdItem(itemStr);
  sItem->SetSelectable(false);
  Add(sItem);
  // build up setup menu
  for (int i = 0; i < MAX_RECLIST_COLUMNS; i++) {
     ret = asprintf(&itemStr, "%s %i", tr("Item"), i + 1);
     if (ret <= 0) {
        esyslog("Error allocating linebuffer for cOsdItem.");
        return;
        }
     Add(new cMenuEditStraItem(itemStr, &(preclistcolumns[i].Type), MAX_COLTYPES, ColumnType_descriptions));
     switch (preclistcolumns[i].Type) {
        case COLTYPE_NONE:
           break;
        case COLTYPE_BLANK:
           Add(new cMenuEditIntItem(IndentMenuItem(tr("Width")), &(preclistcolumns[i].Width), 0, 24));
           break;
        case COLTYPE_DATE:
           Add(new cMenuEditIntItem(IndentMenuItem(tr("Width")), &(preclistcolumns[i].Width), 8, 24));
           Add(new cMenuEditStraItem(IndentMenuItem(tr("Alignment")), &(preclistcolumns[i].Align), 3, AlignmentType_names));
           break;
        case COLTYPE_TIME:
           Add(new cMenuEditIntItem(IndentMenuItem(tr("Width")), &(preclistcolumns[i].Width), 5, 24));
           Add(new cMenuEditStraItem(IndentMenuItem(tr("Alignment")), &(preclistcolumns[i].Align), 3, AlignmentType_names));
           break;
        case COLTYPE_DATETIME:
           Add(new cMenuEditIntItem(IndentMenuItem(tr("Width")), &(preclistcolumns[i].Width), 14, 24));
           Add(new cMenuEditStraItem(IndentMenuItem(tr("Alignment")), &(preclistcolumns[i].Align), 3, AlignmentType_names));
           break;
        case COLTYPE_LENGTH:
           Add(new cMenuEditIntItem(IndentMenuItem(tr("Width")), &(preclistcolumns[i].Width), 3, 24));
           Add(new cMenuEditStraItem(IndentMenuItem(tr("Alignment")), &(preclistcolumns[i].Align), 3, AlignmentType_names));
           break;
        case COLTYPE_RATING:
           Add(new cMenuEditIntItem(IndentMenuItem(tr("Width")), &(preclistcolumns[i].Width), 5, 24));
           Add(new cMenuEditStraItem(IndentMenuItem(tr("Alignment")), &(preclistcolumns[i].Align), 3, AlignmentType_names));
           break;
#if (APIVERSNUM >= 20505)
        case COLTYPE_ERROR:
           Add(new cMenuEditIntItem(IndentMenuItem(tr("Width")), &(preclistcolumns[i].Width), 1, 24));
           Add(new cMenuEditStraItem(IndentMenuItem(tr("Alignment")), &(preclistcolumns[i].Align), 3, AlignmentType_names));
           break;
#endif
        case COLTYPE_FILE:
           Add(new cMenuEditStrItem(IndentMenuItem(tr("Name")), (preclistcolumns[i].Name), 64, tr(FileNameChars)));
           Add(new cMenuEditIntItem(IndentMenuItem(tr("Width")), &(preclistcolumns[i].Width), 1, 24));
           Add(new cMenuEditStraItem(IndentMenuItem(tr("Alignment")), &(preclistcolumns[i].Align), 3, AlignmentType_names));
           Add(new cMenuEditStrItem(IndentMenuItem(tr("Filename")), (preclistcolumns[i].Op1), 64, tr(FileNameChars)));
           break;
        case COLTYPE_FILETHENCOMMAND:
           Add(new cMenuEditStrItem(IndentMenuItem(tr("Name")), (preclistcolumns[i].Name), 64, tr(FileNameChars)));
           Add(new cMenuEditIntItem(IndentMenuItem(tr("Width")), &(preclistcolumns[i].Width), 1, 24));
           Add(new cMenuEditStraItem(IndentMenuItem(tr("Alignment")), &(preclistcolumns[i].Align), 3, AlignmentType_names));
           Add(new cMenuEditStrItem(IndentMenuItem(tr("Filename")), (preclistcolumns[i].Op1), 1024, tr(FileNameChars)));
           Add(new cMenuEditStrItem(IndentMenuItem(tr("Command")), (preclistcolumns[i].Op2), 1024, tr(FileNameChars)));
           break;
        }
     }
  ret = asprintf(&itemStr, "%s\t%s", tr("Name of the recording"), tr("(fixed to the last position)"));
  if (ret <= 0) {
     esyslog("Error allocating linebuffer for cOsdItem.");
     return;
     }
  sItem = new cOsdItem(itemStr);
  sItem->SetSelectable(false);
  Add(sItem);
  // restore current position
  SetCurrent(Get(current));
}

eOSState myMenuSetupColumns::ProcessKey(eKeys Key) {
  int iTemp_type [4], i;
  for (i = 0; i < MAX_RECLIST_COLUMNS; i++) {
     iTemp_type[i] = preclistcolumns[i].Type;
     }
  eOSState state = cOsdMenu::ProcessKey(Key);
  int iChanged = -1;
  for (i = 0; i < MAX_RECLIST_COLUMNS && iChanged == -1; i++) {
     if (iTemp_type[i] != preclistcolumns[i].Type) {
        iChanged = i;
        }
     }
  if (iChanged >= 0) {
     preclistcolumns[iChanged].Width = recListDefaultValues[preclistcolumns[iChanged].Type].Width;
     preclistcolumns[iChanged].Align = recListDefaultValues[preclistcolumns[iChanged].Type].Align;
     Set();
     Display();
     }
  if (state == osUnknown) {
     switch (Key) {
        case kOk: return osUser9;
        default:  break;
        }
     }
  return state;
}

int msprintf(char **strp, const char *fmt, ...) {
  va_list ap;
  va_start (ap, fmt);
  int res = vasprintf (strp, fmt, ap);
  va_end (ap);
  return res;
}

char* IndentMenuItem(const char* szString, int indentions) {
  char* szIndented = NULL;
  msprintf(&szIndented, "%*s", strlen(szString)+indentions*2, szString);
  return szIndented;
}
