/*
 * dvdconvert.c: A plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 */

#include <getopt.h>
#include <stdlib.h>
#include <vdr/interface.h>
#include <vdr/plugin.h>
#include "i18n.h"

#define MAX_ENTRIES 256
#define MAX_LISTITEMS 32
#define MAX_GROUPS  20

#define STATE_GROUPS 1000
#define STATE_SAVE    999
#define DEFAULT_CHARS "abcdefghijklmnopqrstuvwxyz0123456789-/_ABCDEFGHIJKLMNOPQRSTUVWXYZ"

static const char *VERSION        = "1.0.1";
static const char *DESCRIPTION    = "Plugin for dvdconvert with dvd2vdr dvd2dvd";
static const char *MAINMENUENTRY  = NULL;

static const char *CFG_FILE="dvdconvert.conf";
static const char *SCRIPT_FILE="dvdconvert.sh";

typedef struct _admin
{
   char *name;
   char *value;
   char type;
   int length;
   char *choices;
   char *scriptName;
   char *desc;
   char *sValue;
   int  iValue;
   int  iValMin;
   int  iValMax;
   int  group;
   const char * lItems[MAX_LISTITEMS];
   int numLItems;
} ADMIN_ENTRY;


class cMenuSetupAdmin : public cMenuSetupPage
{
private:
   ADMIN_ENTRY *admTable[ MAX_ENTRIES ];
   char configFile[254];
   char scriptFile[254];
   void FreeTable(int);
   void AddMenuEntry( ADMIN_ENTRY *admEntry );
   eOSState ProcessKey(eKeys Key);
   bool isSubmenu;
protected:
   virtual void Store(void);
public:
   cMenuSetupAdmin(const char *configFile, const char *scriptFile);
   cMenuSetupAdmin( ADMIN_ENTRY **admTable, int groupNum );
};


// --- cMenuSetupAdmin --------------------------------------------------------

cMenuSetupAdmin::cMenuSetupAdmin(const char *cfgFile, const char *scrFile)
{
   int i = 0;
   int actGroup = 0;
   int numGroup = 0;
   int j;
   char *p1, *p2;

   if( cfgFile == NULL )
      strcpy(configFile,AddDirectory( cPlugin::ConfigDirectory(), CFG_FILE ));
   else
      strcpy(configFile,cfgFile);

   if( scrFile == NULL )
      strcpy(scriptFile,AddDirectory( cPlugin::ConfigDirectory(), SCRIPT_FILE ));
   else
      strcpy(scriptFile,scrFile);

   isSubmenu = false;
//   printf( "CfgFile: %s\n", configFile );
//   printf( "ScrFile: %s\n", scriptFile );
   FILE *fhdl = fopen( configFile, "r" );
//   printf( "Open: %s\n", configFile );
   if( fhdl != NULL )
   {
      static char buffer[ 2048 ];

      SetSection( "Admin" );
      while( fgets( buffer, sizeof( buffer ), fhdl ) != NULL )
      {
         buffer[ strlen( buffer ) - 1 ] = '\0';
         admTable[i]=( ADMIN_ENTRY * )calloc( sizeof( ADMIN_ENTRY ), 1 );
         if( buffer[0] == '/' )
         {
            sscanf( buffer, "%a[^:]:%a[^:]:%a[^:]:%c:%d:%a[^:]:%a[^:]:",
                    &(admTable[i]->scriptName),
                    &(admTable[i]->name),
                    &(admTable[i]->value),
                    &(admTable[i]->type),
                    &(admTable[i]->length),
                    &(admTable[i]->choices),
                    &(admTable[i]->desc ) );

            admTable[i]->group = actGroup;

            switch( admTable[i]->type )
            {
               case 'A':
                  if( strlen( admTable[i]->choices ) < 2 )
                  {
                     free( admTable[i]->choices );
                     admTable[i]->choices = (char *)malloc( strlen( DEFAULT_CHARS ) + 1 );
                     strcpy( admTable[i]->choices, (char *)DEFAULT_CHARS );
                  }

                  admTable[i]->sValue = ( char * )calloc( admTable[i]->length + 2, 1 );
                  strcpy( admTable[i]->sValue, admTable[i]->value );

                  break;
               case 'I':
                  admTable[i]->iValue = atoi( admTable[i]->value );
                  p1 = strchr( admTable[i]->choices, ',' );
                  if( p1 != NULL )
                  {
                     *p1 = '\0';
                     p1++;
                     admTable[i]->iValMin = atoi(admTable[i]->choices);
                     admTable[i]->iValMax = atoi(p1);
                     p1--;
                     *p1 = ',';
                  }
                  else
                  {
                     admTable[i]->choices[0] = '\0';
                  }
                  break;
               case 'B':
                  p1 = strchr( admTable[i]->choices, ',' );
                  admTable[i]->iValue = atoi( admTable[i]->value );
                  if( p1 != NULL )
                  {
                     admTable[i]->lItems[0] = admTable[i]->choices;
                     *p1 = '\0';
                     p1++;
                     admTable[i]->lItems[1] = p1;
                  }
                  break;
               case 'L':
                  j = 0;
                  p1 = admTable[i]->choices;
                  p2 = strchr( p1, ',' );
                  while( p2 != NULL && j < MAX_LISTITEMS - 1 )
                  {
                     *p2 = '\0';
                     admTable[i]->lItems[j] = p1;
                     p1 = p2 + 1;
                     p2 = strchr( p1, ',' );
                     j++;
                  }
                  admTable[i]->lItems[j] = p1;
                  j++;
                  admTable[i]->numLItems = j;
                  admTable[i]->lItems[j] = NULL;
                  admTable[i]->iValue = atoi( admTable[i]->value );
                  break;
               default:
                  printf( "Illegal type <%c>\n", admTable[i]->type );
                  FreeTable( i );
                  admTable[i]->type = '\0';
                  admTable[i]->desc = (char *) malloc( strlen( buffer ) + 3 );
                  strcpy( admTable[i]->desc, "#!" );
                  strcat( admTable[i]->desc, buffer );
                  break;

            }
            if( actGroup == 0 && admTable[i]->type != '\0' )
            {
               AddMenuEntry( admTable[i] );
            }
         }
         else
         {
            admTable[i]->desc = (char *) malloc( strlen( buffer ) + 1 );
            strcpy( admTable[i]->desc, buffer );
            if( buffer[ 0 ] == ':' )
            {
               if( strlen( buffer ) > 1 && buffer[1] != ' ' )
               {
                  if( numGroup < MAX_GROUPS )
                  {
                     numGroup++;
                  }
                  actGroup = numGroup;
                  Add( new cOsdItem( tr( admTable[i]->desc + 1 ), (eOSState)(actGroup+STATE_GROUPS) ) );
               }
               else
               {
                  actGroup = 0;
               }
            }
            else
            {
               if( buffer[ 0 ] == '-' )
               {
                  admTable[i]->group = actGroup;
                  if( actGroup == 0 )
                  {
                     Add( new cOsdItem( admTable[i]->desc, (eOSState)(STATE_GROUPS) ) );
                  }

               }
            }
         }
         i++;

      };
      Add( new cOsdItem( "Start der Scripte", (eOSState)(STATE_SAVE) ) );
      admTable[i]=NULL;
      fclose( fhdl );
   }
}

cMenuSetupAdmin::cMenuSetupAdmin( ADMIN_ENTRY *admTable[], int groupNum )
{
   int i = 0;
   isSubmenu = true;

   for( i=0; i < MAX_ENTRIES && admTable[i] != NULL; i++ )
   {
      if( admTable[i]->group == groupNum )
      {
         AddMenuEntry( admTable[i] );
      }
   }
}


void cMenuSetupAdmin::Store(void)
{
   int i,j;
   FILE *fhdl = fopen( configFile, "w" );
   char val[ 64 ];
/*    printf( "Store called %d\n", isSubmenu );  */

// fprintf( fhdl, "# This file contains the tasks for the admin plugin\n" );
// fprintf( fhdl, "# Syntax:\n" );
// fprintf( fhdl, "# <script>:<name>:<value>:<type>:<length>:<choices>:<description>:\n" );

   for( i=0; i < MAX_ENTRIES && admTable[i] != NULL; i++ )
   {
      if( admTable[i]->type != '\0' )
      {
         switch( admTable[i]->type )
         {
            case 'A':
               strcpy( val, admTable[i]->sValue );
               break;
            case 'I':
               if( admTable[i]->length > 0 )
               {
                  sprintf( val, "%0*d", admTable[i]->length, admTable[i]->iValue );
               }
               else
               {
                  sprintf( val, "%d", admTable[i]->iValue );
               }
               break;
            case 'B':
               if( admTable[i]->choices != NULL )
               {
                  if( strlen( admTable[i]->choices ) > 0 )
                  {
                     admTable[i]->choices[ strlen( admTable[i]->choices ) ] = ',';
                  }
               }
               strcpy( val, itoa( admTable[i]->iValue ) );
               break;
            case 'L':
               for( j=1; admTable[i]->lItems[j] != NULL; j++  )
               {
                  char *p1 = ( char * )admTable[i]->lItems[j];
                  *(p1-1) = ',';
               }
               strcpy( val, itoa( admTable[i]->iValue ) );
               break;
            default:
               printf( "Illegal type <%c>\n", admTable[i]->type );
               break;

         }
         fprintf( fhdl, "%s:%s:%s:%c:%d:%s:%s:\n",
                        admTable[i]->scriptName,
                        admTable[i]->name,
                        val,
                        admTable[i]->type,
                        admTable[i]->length,
                        admTable[i]->choices,
                        admTable[i]->desc );
      }
      else
      {
         fprintf( fhdl, "%s\n", admTable[i]->desc );
      }

      FreeTable( i );
      free( admTable[ i ] );
   }
   fclose( fhdl );
   system( scriptFile );
}


void cMenuSetupAdmin::AddMenuEntry( ADMIN_ENTRY *admEntry )
{
   switch( admEntry->type )
   {
      case 'A':
         Add(new cMenuEditStrItem( admEntry->desc, admEntry->sValue,
                                   admEntry->length + 1, admEntry->choices ) );
         break;
      case 'I':
         if( admEntry->iValMin != admEntry->iValMax )
         {
            Add(new cMenuEditIntItem( admEntry->desc, &(admEntry->iValue),
                                      admEntry->iValMin, admEntry->iValMax ));
         }
         else
         {
            Add(new cMenuEditIntItem( admEntry->desc, &(admEntry->iValue)));
         }
         break;
      case 'B':
         if( admEntry->lItems[0] != NULL )
         {
            Add(new cMenuEditBoolItem( admEntry->desc, &(admEntry->iValue),
                                       admEntry->lItems[0], admEntry->lItems[1] ));
         }
         else
         {
            Add(new cMenuEditBoolItem( admEntry->desc, &(admEntry->iValue)));
         }
         break;
      case 'L':
         Add(new cMenuEditStraItem( admEntry->desc, &(admEntry->iValue), admEntry->numLItems, admEntry->lItems));
         break;
      default:
         Add( new cOsdItem( admEntry->desc, (eOSState)(STATE_GROUPS) ) );
   }
}

void cMenuSetupAdmin::FreeTable( int idx )
{
   if( admTable[idx]->name != NULL )
      free( admTable[idx]->name );

   if( admTable[idx]->value != NULL )
      free( admTable[idx]->value );

   if( admTable[idx]->choices != NULL )
      free( admTable[idx]->choices );

   if( admTable[idx]->scriptName != NULL )
      free( admTable[idx]->scriptName );

   if( admTable[idx]->desc != NULL )
      free( admTable[idx]->desc );
}

eOSState cMenuSetupAdmin::ProcessKey(eKeys Key)
{
  eOSState state;
/*   printf( "\nProcessKey: %d", Key );  */

  state = cOsdMenu::ProcessKey(Key);
/*   printf( "\n State: %d", state );  */
  if (Key == kOk && state != osContinue) {
     if( !isSubmenu )
     {
        if( state == STATE_SAVE )
        {
           Store();
           state = osBack;
        }
        else
        {
           if( state > STATE_GROUPS )
           {
              return AddSubMenu( new cMenuSetupAdmin( (ADMIN_ENTRY **)admTable, state - STATE_GROUPS ) );
           }
           state = osContinue;
        }
     }
     else
     {
        state = osBack;
     }
  }
  return state;
}



class cPluginAdmin : public cPlugin
{
private:
   // Add any member variables or functions you may need here.
   const char *configFile;
   const char *scriptFile;
public:
   cPluginAdmin(void);
   virtual ~cPluginAdmin();
   virtual const char *Version(void)
   {
      return VERSION;
   }
   virtual const char *CommandLineHelp(void);
   virtual bool ProcessArgs(int argc, char *argv[]);
   virtual bool Initialize(void);
   virtual void Housekeeping(void);
   virtual const char *Description(void) { return tr(DESCRIPTION); }
   virtual const char * MainMenuEntry()
   {
      return MAINMENUENTRY;
   }
   virtual cMenuSetupPage *SetupMenu(void);
};


// --- cPluginAdmin ----------------------------------------------------------

cPluginAdmin::cPluginAdmin(void)
{
   // Initialize any member variables here.
   // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
   // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
   configFile=NULL;
   scriptFile=NULL;
}

cPluginAdmin::~cPluginAdmin()
{
   // Clean up after yourself!
}

const char *cPluginAdmin::CommandLineHelp(void)
{
   // Return a string that describes all known command line options.
   static char *help_str=0;

   free( help_str );
   asprintf( &help_str, "  -c FILE,  --cfgFile=FILE  name of configuration file\n"
                        "            (default: %s)\n"
                        "  -x FILE,  --exeFile=FILE  name of script file\n"
                        "            (default: %s)\n",
             configFile, scriptFile );
   return help_str;
}

bool cPluginAdmin::ProcessArgs(int argc, char *argv[])
{
   static struct option long_options[] = {
      { "cfgfile", required_argument, NULL, 'c'},
      { "execfile", required_argument, NULL, 'x'},
      { NULL}};

   int c, option_index = 0;

   while( ( c = getopt_long( argc, argv, "c:", long_options, &option_index ) ) != -1 )
   {
      switch( c )
      {
         case 'c':  configFile=optarg; break;
         case 'x':  scriptFile=optarg; break;
         default:  return false;
      }
   }

   return true;
}

bool cPluginAdmin::Initialize(void)
{
   // Start any background activities the plugin shall perform.
   RegisterI18n(AdminPhrases);
   return true;
}

void cPluginAdmin::Housekeeping(void)
{
   // Perform any cleanup or other regular tasks.
}

// cOsdObject *cPluginAdmin::MainMenuAction(void)
// {
//   // Perform the action when selected from the main VDR menu.
//   return NULL;
// }

cMenuSetupPage *cPluginAdmin::SetupMenu(void)
{
   // Return a setup menu in case the plugin supports one.
   return new cMenuSetupAdmin(configFile,scriptFile);
}

VDRPLUGINCREATOR(cPluginAdmin); // Don't touch this!
