/*
 * admin.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 1024
#define MAX_LISTITEMS 32
#define MAX_GROUPS  20

#define STATE_GROUPS     1000
#define STATE_SAVEEXIT    999
#define STATE_SAVEBACK    998
#define DEFAULT_CHARS "abcdefghijklmnopqrstuvwxyz0123456789-_ABCDEFGHIJKLMNOPQRSTUVWXYZ"

#define SETUP_MAINMENUENTRY       "MenuEntry"

static const char *VERSION        = "0.5.0";
static const char *DESCRIPTION    = "Administrative tasks";
static const char *MAINMENUENTRY  = "Administrative tasks";

int mainMenuEntry = 0;
#define CFG_FILE "admin.conf"
#define START_SCRIPT "/admin.sh -start"
#define INIT_SCRIPT "/admin.sh -init"
#define SAVE_SCRIPT "/admin.sh -save"

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];
   void FreeTable(int);
   void AddMenuEntry( ADMIN_ENTRY *admEntry );
   eOSState ProcessKey(eKeys Key);
   bool isSubmenu;
   bool usePageUpDn;
protected:
   virtual void Store(void);
public:
   cMenuSetupAdmin(void);
   cMenuSetupAdmin( ADMIN_ENTRY **admTable, int groupNum );
};


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

cMenuSetupAdmin::cMenuSetupAdmin(void)
{
   int i = 0;
   int actGroup = 0;
   int numGroup = 0;
   int j;
   char *p1, *p2;
   char buffer[512];
      
   usePageUpDn = false;
     
   strcpy(configFile,AddDirectory( cPlugin::ConfigDirectory(), "admin/" ));
   strcat(configFile,CFG_FILE);
   strcpy(buffer,AddDirectory( cPlugin::ConfigDirectory(), "admin" ));
      
   strcat(buffer, START_SCRIPT);
   isyslog( "Executing <%s>", buffer );
   system( buffer );

   SetHasHotkeys();
   isSubmenu = false;
   isyslog( "CfgFile: %s", configFile );

   FILE *fhdl = fopen( configFile, "r" );
   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( hk( 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 + 1, osUnknown, false ) );
               }
            }
         }
         i++;
      }
      Add( new cOsdItem( hk(tr( "Safe and terminate" )), (eOSState)(STATE_SAVEBACK) ) );
      Add( new cOsdItem( hk(tr( "Safe and restart VDR" )), (eOSState)(STATE_SAVEEXIT) ) );
      Add( new cOsdItem( "", osUnknown, false ) );
      Add( new cMenuEditBoolItem( tr("Menu entry"), (int *)&mainMenuEntry ) );
      admTable[i]=NULL;
      fclose( fhdl );
   }
   else {
      isyslog( "Error opening <%s>\n", configFile );
      Add( new cOsdItem( tr( "Config file not found" ), osUnknown, false ) );
   }
}

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

   usePageUpDn = true;
   while( i < MAX_ENTRIES && admTable[i] != NULL && admTable[i]->group != groupNum ) {
      if( admTable[i]->desc && *(admTable[i]->desc) == ':' )
         title = admTable[i]->desc;
         
      i++;         
   }
   
   while( i < MAX_ENTRIES && admTable[i] != NULL && admTable[i]->group == groupNum )
   {
      AddMenuEntry( admTable[i] );
      if( admTable[i]->type == 'A' )
         usePageUpDn = false;

      cnt++;
      i++;
   }
   if ( cnt > 50 && usePageUpDn )
      SetHelp( "", tr("PageUp"), tr("PageDown"), "" );
   else
      usePageUpDn = false;
   
   SetTitle( title + 1 );
}


void cMenuSetupAdmin::Store(void)
{
   int i,j;
   FILE *fhdl = fopen( configFile, "w" );
   char buffer[ 512 ];

/*    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" );

   SetupStore(SETUP_MAINMENUENTRY, mainMenuEntry);
   Setup.Save();

   for( i=0; i < MAX_ENTRIES && admTable[i] != NULL; i++ )
   {
      if( admTable[i]->type != '\0' )
      {
         switch( admTable[i]->type )
         {
            case 'A':
               strcpy( buffer, admTable[i]->sValue );
               break;
            case 'I':
               sprintf( buffer, "%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( buffer, 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( buffer, 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,
                        buffer,
                        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 );

   strcpy(buffer,AddDirectory( cPlugin::ConfigDirectory(), "admin" ));
   strcat(buffer, SAVE_SCRIPT);
   isyslog( "Executing <%s>", buffer );
   system( buffer );
}


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 + 1, osUnknown, false ) );
   }
}

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

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

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_SAVEBACK || state == STATE_SAVEEXIT )
        {
           Store();
           if( state == STATE_SAVEEXIT )
              exit( 0 );
           state = osBack;
        }
        else
        {
           if( state > STATE_GROUPS )
              return AddSubMenu( new cMenuSetupAdmin( (ADMIN_ENTRY **)admTable, state - STATE_GROUPS ) );

           state = osContinue;
        }
     }
     else
        state = osBack;
  }
  else {
     if ( usePageUpDn )
     {
        switch(Key) {
           case kGreen: PageUp();
              break;
           case kYellow: PageDown();
              break;
           default:
              break;
        }
     }
  }
  return state;
}



class cPluginAdmin : public cPlugin
{
public:
   cPluginAdmin(void);
   virtual ~cPluginAdmin();
   virtual const char *Version(void) { return VERSION; }
   virtual bool Initialize(void);
   virtual void Housekeeping(void);
   virtual const char *Description(void) { return tr(DESCRIPTION); }
   virtual const char * MainMenuEntry(void) { return mainMenuEntry ? tr(MAINMENUENTRY) : NULL; }
   virtual cOsdObject *MainMenuAction(void);
   virtual cMenuSetupPage *SetupMenu(void);
   virtual bool SetupParse(const char *Name, const char *Value);
};


// --- 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!
}

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


bool cPluginAdmin::Initialize(void)
{
   // Start any background activities the plugin shall perform.
   RegisterI18n(AdminPhrases);
   char buffer[512];

   strcpy(buffer,AddDirectory( cPlugin::ConfigDirectory(), "admin" ));
   strcat(buffer, INIT_SCRIPT);
   isyslog( "Executing <%s>", buffer );
   system( buffer );
   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 new cMenuSetupAdmin();
}

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

bool cPluginAdmin::SetupParse(const char *Name, const char *Value)
{
   // Parse your own setup parameters and store their values.
   if( !strcasecmp(Name, SETUP_MAINMENUENTRY) )
      mainMenuEntry = atoi(Value);
   else
      return false;

   return true;
}

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