/*
 * statscript.c: A plugin for the Video Disk Recorder
 *
 * most parts of the code are taken from the default vdr status plugin written by Klaus Schmidinger.
 *
 * See the README file for copyright information and how to reach the author.
 *
 */

#include <vdr/plugin.h>
#include <vdr/status.h>
#include <vdr/tools.h>

#include <stdlib.h>
#include <stdarg.h>

static const char *VERSION        = "0.1.1";
static const char *DESCRIPTION    = "Status monitor script";
static const char *MAINMENUENTRY  = NULL;
static const char *PLUGINNAME     = "statinfo";

#define SETUP_CHANSWITCH  "ChannelSwitch"
#define SETUP_RECORDING   "Recording"
#define SETUP_REPLAY      "Replay"
#define SETUP_VOLUME      "Volume"
#define SETUP_OSDCLEAR    "OSD_Clear"
#define SETUP_OSDTITLE    "OSD_Title"
#define SETUP_OSDMESSAGE  "OSD_Message"
#define SETUP_OSDHELPKEYS "OSD_HelpKeys"
#define SETUP_OSDCURITEM  "OSD_CurrentItem"
#define SETUP_OSDTXTITEM  "OSD_TextItem"
#define SETUP_OSDCHANNEL  "OSD_Channel"
#define SETUP_OSDPROGRAM  "OSD_Program"
#define SETUP_DEBUG       "DebugInfo"

bool bChanSwitch  = true;
bool bRecording   = true;
bool bReplay      = false;
bool bVolume      = false;
bool bOsdclear    = false;
bool bOsdtitle    = false;
bool bOsdmessage  = false;
bool bOsdhelpkeys = false;
bool bOsdcuritem  = false;
bool bOsdtxtitem  = false;
bool bOsdchannel  = false;
bool bOsdprogram  = false;
bool bDebug       = false;
// ---

class cStatusInfo : public cStatus {
private:
   char *statCmd;
   int numRecs;
   int mVolume;
   void execCmd( char *format, ... );
protected:
   virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
   virtual void Recording(const cDevice *Device, const char *Name, const char *FileName, bool On);
   virtual void Replaying(const cControl *Control, const char *Name, const char *FileName, bool On);
   virtual void SetVolume(int Volume, bool Absolute);
   virtual void OsdClear(void);
   virtual void OsdTitle(const char *Title);
   virtual void OsdStatusMessage(const char *Message);
   virtual void OsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue);
   virtual void OsdCurrentItem(const char *Text);
   virtual void OsdTextItem(const char *Text, bool Scroll);
   virtual void OsdChannel(const char *Text);
   virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle);
public:
   cStatusInfo();
};

cStatusInfo::cStatusInfo()
{
   asprintf( &statCmd, "sh %s/%s.sh", ( const char * )AddDirectory( cPlugin::ConfigDirectory(), PLUGINNAME ), PLUGINNAME );
   numRecs = 0;
   mVolume = 0;
}

void cStatusInfo::ChannelSwitch(const cDevice *Device, int ChannelNumber)
{
   if( bChanSwitch && ChannelNumber && Device->IsPrimaryDevice() && ChannelNumber == cDevice::CurrentChannel() ) {
      execCmd( "CHAN %d &", ChannelNumber );
   }
}

void cStatusInfo::Recording(const cDevice *Device, const char *Name, const char *FileName, bool On)
{
   if( ! bRecording )
      return;

   if( On ) {
      numRecs++;
   }
   else {
      if( numRecs > 0 )
         numRecs--;
   }
   execCmd( "REC %d %d \"%s\" &", On, numRecs, *strescape( Name != NULL ? Name : "", "\"$" ) );
}

void cStatusInfo::Replaying(const cControl *Control, const char *Name, const char *FileName, bool On)
{
   if( bReplay )
      execCmd( "REPL %d \"%s\" &", On, *strescape( Name != NULL ? Name : "", "\"$" ) );
}

void cStatusInfo::SetVolume(int Volume, bool Absolute)
{
   if( ! bVolume )
      return;

   if( Absolute )
      mVolume = Volume;
   else
      mVolume += Volume;

   execCmd( "VOL %d %d %d &", mVolume, Absolute, Volume );
}

void cStatusInfo::OsdClear(void)
{
   if( bOsdclear )
      execCmd( "OSDCLR &" );
}

void cStatusInfo::OsdTitle(const char *Title)
{
   if( bOsdtitle )
      execCmd( "OSDTIT \"%s\" &", *strescape( Title != NULL ? Title : "", "\"$" ) );
}

void cStatusInfo::OsdStatusMessage(const char *Message)
{
   if( bOsdmessage )
      execCmd( "OSDMSG \"%s\" &", *strescape( Message != NULL ? Message : "", "\"$" ) );
}

void cStatusInfo::OsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue)
{
   if( bOsdhelpkeys )
      execCmd( "OSDHLP \"%s\" \"%s\" \"%s\" \"%s\" &", Red, Green, Yellow, Blue );
}

void cStatusInfo::OsdCurrentItem(const char *Text)
{
   if( bOsdcuritem )
      execCmd( "OSDCITM \"%s\" &", Text );
}

void cStatusInfo::OsdTextItem(const char *Text, bool Scroll)
{
   if( bOsdtxtitem )
      execCmd( "OSDTITM %d \"%s\" &", Scroll, Text );
}

void cStatusInfo::OsdChannel(const char *Text)
{
   if( bOsdchannel )
      execCmd( "OSDCHAN \"%s\" &", Text );
}

void cStatusInfo::OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle)
{
   struct tm tm_r;
   char t1[32];
   char t2[32];

   if( ! bOsdprogram )
      return;

   strftime( t1, sizeof( t1 ), "%R", localtime_r( &PresentTime, &tm_r ) );
   strftime( t2, sizeof( t2 ), "%R", localtime_r( &FollowingTime, &tm_r ) );

   execCmd( "OSDPROG \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" &", t1, PresentTitle, PresentSubtitle,
                                                                         t2, FollowingTitle, FollowingSubtitle );
}

void cStatusInfo::execCmd( char *format, ... ) {
   char * parms;
   char * command;
   va_list args;

   va_start( args, format );
   vasprintf( &parms, format, args );
   asprintf( &command, "%s %s", statCmd, parms );
   if( bDebug )
      isyslog( "Executing <%s>", command );
   system( command );
   free( command );
   free( parms );
   va_end( args );
}

///////////////////////////////////////////////////////////
// Class cMenuSetupStatInfo
class cMenuSetupStatInfo : public cMenuSetupPage
{
private:
   int mChanSwitch;
   int mRecording;
   int mReplay;
   int mVolume;
   int mOsdclear;
   int mOsdtitle;
   int mOsdmessage;
   int mOsdhelpkeys;
   int mOsdcuritem;
   int mOsdtxtitem;
   int mOsdchannel;
   int mOsdprogram;
   int mDebug;

protected:
   virtual void Store(void);

public:
   cMenuSetupStatInfo(void);
};

cMenuSetupStatInfo::cMenuSetupStatInfo(void) 
{
   mChanSwitch  = bChanSwitch;  
   mRecording   = bRecording;  
   mReplay      = bReplay;     
   mVolume      = bVolume;     
   mOsdclear    = bOsdclear;   
   mOsdtitle    = bOsdtitle;   
   mOsdmessage  = bOsdmessage; 
   mOsdhelpkeys = bOsdhelpkeys;
   mOsdcuritem  = bOsdcuritem; 
   mOsdtxtitem  = bOsdtxtitem; 
   mOsdchannel  = bOsdchannel; 
   mOsdprogram  = bOsdprogram; 
   mDebug       = bDebug;      

   Add(new cMenuEditBoolItem( tr(SETUP_CHANSWITCH ), &mChanSwitch  ));
   Add(new cMenuEditBoolItem( tr(SETUP_RECORDING  ), &mRecording   ));
   Add(new cMenuEditBoolItem( tr(SETUP_REPLAY     ), &mReplay      ));
   Add(new cMenuEditBoolItem( tr(SETUP_VOLUME     ), &mVolume      ));
   Add(new cMenuEditBoolItem( tr(SETUP_OSDCLEAR   ), &mOsdclear    ));
   Add(new cMenuEditBoolItem( tr(SETUP_OSDTITLE   ), &mOsdtitle    ));
   Add(new cMenuEditBoolItem( tr(SETUP_OSDMESSAGE ), &mOsdmessage  ));
   Add(new cMenuEditBoolItem( tr(SETUP_OSDHELPKEYS), &mOsdhelpkeys ));
   Add(new cMenuEditBoolItem( tr(SETUP_OSDCURITEM ), &mOsdcuritem  ));
   Add(new cMenuEditBoolItem( tr(SETUP_OSDTXTITEM ), &mOsdtxtitem  ));
   Add(new cMenuEditBoolItem( tr(SETUP_OSDCHANNEL ), &mOsdchannel  ));
   Add(new cMenuEditBoolItem( tr(SETUP_OSDPROGRAM ), &mOsdprogram  ));
   Add(new cMenuEditBoolItem( tr(SETUP_DEBUG      ), &mDebug       ));
}

void cMenuSetupStatInfo::Store(void)
{
   SetupStore( SETUP_CHANSWITCH , bChanSwitch  = mChanSwitch  );
   SetupStore( SETUP_RECORDING  , bRecording   = mRecording   );
   SetupStore( SETUP_REPLAY     , bReplay      = mReplay      );
   SetupStore( SETUP_VOLUME     , bVolume      = mVolume      );
   SetupStore( SETUP_OSDCLEAR   , bOsdclear    = mOsdclear    );
   SetupStore( SETUP_OSDTITLE   , bOsdtitle    = mOsdtitle    );
   SetupStore( SETUP_OSDMESSAGE , bOsdmessage  = mOsdmessage  );
   SetupStore( SETUP_OSDHELPKEYS, bOsdhelpkeys = mOsdhelpkeys );
   SetupStore( SETUP_OSDCURITEM , bOsdcuritem  = mOsdcuritem  );
   SetupStore( SETUP_OSDTXTITEM , bOsdtxtitem  = mOsdtxtitem  );
   SetupStore( SETUP_OSDCHANNEL , bOsdchannel  = mOsdchannel  );
   SetupStore( SETUP_OSDPROGRAM , bOsdprogram  = mOsdprogram  );
   SetupStore( SETUP_DEBUG      , bDebug       = mDebug       );
}


class cPluginStatInfo : public cPlugin {
private:
   // Add any member variables or functions you may need here.
   cStatusInfo *statusTest;
public:
   cPluginStatInfo(void);
   virtual ~cPluginStatInfo();
   virtual const char *Version(void){ return VERSION;}
   virtual const char *Description(void){ return DESCRIPTION;}
   virtual const char *CommandLineHelp(void);
   virtual bool ProcessArgs(int argc, char *argv[]);
   virtual bool Start(void);
   virtual void Housekeeping(void);
   virtual const char *MainMenuEntry(void){ return MAINMENUENTRY;}
   virtual cOsdObject *MainMenuAction(void);
   virtual cMenuSetupPage *SetupMenu(void);
   virtual bool SetupParse(const char *Name, const char *Value);
};

cPluginStatInfo::cPluginStatInfo(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!
   statusTest = NULL;
}

cPluginStatInfo::~cPluginStatInfo(){
   // Clean up after yourself!
   delete statusTest;
}

const char *cPluginStatInfo::CommandLineHelp(void){
   // Return a string that describes all known command line options.
   return NULL;
}

bool cPluginStatInfo::ProcessArgs(int argc, char *argv[]){
   // Implement command line argument processing here if applicable.
   return true;
}

bool cPluginStatInfo::Start(void){
   // Start any background activities the plugin shall perform.
   statusTest = new cStatusInfo;
   return true;
}

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

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

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

bool cPluginStatInfo::SetupParse(const char *Name, const char *Value)
{
   // Parse your own setup parameters and store their values.
   if( !strcasecmp(Name, SETUP_CHANSWITCH) )
      bChanSwitch = atoi(Value);
   else if( !strcasecmp(Name, SETUP_RECORDING) )
      bRecording = atoi(Value);
   else if( !strcasecmp(Name, SETUP_REPLAY) )
      bReplay = atoi(Value);
   else if( !strcasecmp(Name, SETUP_VOLUME) )
      bVolume = atoi(Value);
   else if( !strcasecmp(Name, SETUP_OSDCLEAR) )
      bOsdclear = atoi(Value);
   else if( !strcasecmp(Name, SETUP_OSDTITLE) )
      bOsdtitle = atoi(Value);
   else if( !strcasecmp(Name, SETUP_OSDMESSAGE) )
      bOsdmessage = atoi(Value);
   else if( !strcasecmp(Name, SETUP_OSDHELPKEYS) )
      bOsdhelpkeys = atoi(Value);
   else if( !strcasecmp(Name, SETUP_OSDCURITEM) )
      bOsdcuritem = atoi(Value);
   else if( !strcasecmp(Name, SETUP_OSDTXTITEM) )
      bOsdtxtitem = atoi(Value);
   else if( !strcasecmp(Name, SETUP_OSDCHANNEL) )
      bOsdchannel = (char)atoi(Value);
   else if( !strcasecmp(Name, SETUP_OSDPROGRAM) )
      bOsdprogram = atoi(Value);
   else if( !strcasecmp(Name, SETUP_DEBUG) )
      bDebug = (char)atoi(Value);
   else
      return false;

   return true;
}

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


