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

#include <stdio.h>
#include <string.h>

#include <vdr/plugin.h>
#include <vdr/device.h>
#include <vdr/interface.h>
#include <vdr/skins.h>
#include <vdr/thread.h>
#include <vdr/tools.h>

#include "i18n.h"

static const char *VERSION        = "0.1.1";
static const char *DESCRIPTION    = "Snapshot";
static const char *MAINMENUENTRY  = "Take Snapshot";

// --------------- Status monitor -------------------

#include <vdr/status.h>

class cSnapshotStatusMonitor : public cStatus {

public:
    cSnapshotStatusMonitor() { m_Current[0] = 0; };
    const char *GetCurrentName(void) { return m_Current; }

protected:
    char m_Current[4096];

    virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber) {
      if(cDevice::PrimaryDevice() == Device && ChannelNumber > 0) {
        m_Current[0] = 0;
        if(Channels.GetByNumber(ChannelNumber)->Name()) {
          strcpy(m_Current, Channels.GetByNumber(ChannelNumber)->Name());
          if(strchr(m_Current, ';'))
            *strchr(m_Current, ';') = 0;
        }
      }
    }

#if VDRVERSNUM < 10338
    virtual void Replaying(const cControl *Control, const char *Name) {
      m_Current[0] = 0;
      if(Name) {
        strcpy(m_Current, Name);
      }
    }
#else
    virtual void Replaying(const cControl *Control, const char *Name, 
			   const char *FileName, bool On) {
      m_Current[0] = 0;
      if(On && Name) {
        strcpy(m_Current, Name);
      }
    }
#endif
};

// --------------- Setup menu -------------------
#include <vdr/menuitems.h>

class cPluginSnapshot;

class cMenuSetupSnapshot : public cMenuSetupPage {
private:
  cPluginSnapshot *m_Plugin;

  int   m_HideMainMenuEntry;
  int   m_Jpeg;
  int   m_Quality;
  int   m_SizeX;
  int   m_SizeY;
  char  m_DestDir[1024];

protected:
  virtual void Store(void);

public:
  cMenuSetupSnapshot(cPluginSnapshot *Plugin);
};

// --------------- Plugin -----------------------
class cSnapshotThread;

class cPluginSnapshot : public cPlugin {
private:

protected:
  bool  m_HideMainMenuEntry;
  bool  m_Jpeg;
  int   m_Quality;
  int   m_SizeX;
  int   m_SizeY;
  char *m_DestDir;

  void SaveSetup(void);
  bool m_HaveSetup;

  cSnapshotThread *m_SnapshotThread;

  cSnapshotStatusMonitor *m_StatusMonitor;

public:
  void TakeSnapshot(void);

public:
  cPluginSnapshot(void);
  virtual ~cPluginSnapshot();
  virtual const char *Version(void) { return VERSION; }
  virtual const char *Description(void) { return tr(DESCRIPTION); }
  virtual const char *CommandLineHelp(void);
  virtual bool ProcessArgs(int argc, char *argv[]);
  virtual bool Initialize(void);
  virtual bool Start(void);
  virtual void Housekeeping(void);
  virtual const char *MainMenuEntry(void) { return m_HideMainMenuEntry ? NULL : tr(MAINMENUENTRY); }
  virtual cOsdObject *MainMenuAction(void);
  virtual cMenuSetupPage *SetupMenu(void);
  virtual bool SetupParse(const char *Name, const char *Value);

  friend class cMenuSetupSnapshot;
};

class cSnapshotThread : public cThread {
protected:
  cPluginSnapshot *m_Plugin;

  virtual void Action(void) {
    usleep(250*1000);
    m_Plugin->TakeSnapshot();
  }

public:
  cSnapshotThread(cPluginSnapshot *Plugin) : cThread() {
    m_Plugin = Plugin;
  }
  void Stop(void) {Cancel(1);}
};

cPluginSnapshot::cPluginSnapshot(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!
  m_HideMainMenuEntry = false;
  m_Jpeg    = true;
  m_Quality = -1;
  m_DestDir = strdup("/video/snapshots/");
  m_SizeX = 720;
  m_SizeY = 576;

  m_HaveSetup = false;

  m_StatusMonitor = new cSnapshotStatusMonitor;
}

cPluginSnapshot::~cPluginSnapshot()
{
  if(m_SnapshotThread) {
    m_SnapshotThread->Stop();
    delete m_SnapshotThread;
  }
  delete m_StatusMonitor;
  if(m_DestDir)
    free(m_DestDir);
}

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

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

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

bool cPluginSnapshot::Start(void)
{
  // Start any background activities the plugin shall perform.

  SaveSetup();
  RegisterI18n(Phrases);

  return true;
}

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

#if VDRVERSNUM < 10307
  #define OSDMESSAGE(msg) do{Interface->Write(Interface->Width() / 2, 0, msg, clrRed);}while(0)
#else
  #define OSDMESSAGE(msg) do{Skins.Message(mtInfo,msg);}while(0)
#endif

cOsdObject *cPluginSnapshot::MainMenuAction(void)
{
  // Perform the action when selected from the main VDR menu.
  if(m_SnapshotThread) {
    m_SnapshotThread->Stop();
    delete m_SnapshotThread;
    m_SnapshotThread = NULL;
  }
  m_SnapshotThread = new cSnapshotThread(this);
  m_SnapshotThread->Start();

  return NULL;
}

void cPluginSnapshot::TakeSnapshot(void)
{
  if(cDevice::PrimaryDevice()) {
    time_t now = time(NULL);
    struct tm tm_r;
    struct tm *t = localtime_r(&now, &tm_r);
    char FileName[1024];

    sprintf(FileName, "%s/%s_%04d-%02d-%02d_%02d%02d%02d", 
	    m_DestDir, m_StatusMonitor->GetCurrentName(),
            t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 
	    t->tm_hour, t->tm_min, t->tm_sec);
    strcat(FileName, m_Jpeg ? ".jpeg" : ".pnm");

#if VDRVERSNUM < 10338
    if(cDevice::PrimaryDevice()->GrabImage(FileName, m_Jpeg, m_Quality, 
					   m_SizeX, m_SizeY))
#else
    if(cDevice::PrimaryDevice()->GrabImageFile(FileName, m_Jpeg, m_Quality, 
					       m_SizeX, m_SizeY))
#endif
      OSDMESSAGE(tr("Snapshot saved"));
    else
      OSDMESSAGE(tr("Error saving snapshot"));
  }
}

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

bool cPluginSnapshot::SetupParse(const char *Name, const char *Value)
{
  m_HaveSetup = true;

  // Parse your own setup parameters and store their values.
  if(!strcmp(Name,"HideMainMenuEntry")) { m_HideMainMenuEntry = atoi(Value) ? true : false; return true; }
  else if(!strcmp(Name,"Jpeg"))    { m_Jpeg    = atoi(Value) ? true : false; return true; }
  else if(!strcmp(Name,"Quality")) { m_Quality = atoi(Value); return true; }
  else if(!strcmp(Name,"SizeX"))   { m_SizeX   = atoi(Value); return true; }
  else if(!strcmp(Name,"SizeY"))   { m_SizeY   = atoi(Value); return true; }
  else if(!strcmp(Name,"DestDir")) {
    if(m_DestDir)
      free(m_DestDir);
    m_DestDir = strdup(Value);
    return true;
  }

  return false;
}

void cPluginSnapshot::SaveSetup(void)
{
  SetupStore("HideMainMenuEntry", m_HideMainMenuEntry);
  SetupStore("Jpeg", m_Jpeg);
  SetupStore("Quality", m_Quality);
  SetupStore("SizeX", m_SizeX);
  SetupStore("SizeY", m_SizeY);
  SetupStore("DestDir", m_DestDir);

  MakeDirs(m_DestDir, true);
}

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


// --------------- Setup menu -------------------

const char *sImageFormats[] =
  {"PNM", "JPEG", NULL};

static inline const char * int_to_str(int i)
{
  static char buf[64];
  sprintf(buf, "%d", i);
  return buf;
}

void cMenuSetupSnapshot::Store(void)
{
  m_Plugin->SetupParse("HideMainMenuEntry", int_to_str(m_HideMainMenuEntry ? 0 : 1));
  m_Plugin->SetupParse("Jpeg", int_to_str(m_Jpeg));
  m_Plugin->SetupParse("Quality", int_to_str(m_Quality));
  m_Plugin->SetupParse("SizeX", int_to_str(m_SizeX));
  m_Plugin->SetupParse("SizeY", int_to_str(m_SizeY));
  m_Plugin->SetupParse("DestDir", m_DestDir);
  m_Plugin->SaveSetup();
}

cMenuSetupSnapshot::cMenuSetupSnapshot(cPluginSnapshot *Plugin)
{
  m_Plugin = Plugin;

  m_HideMainMenuEntry = m_Plugin->m_HideMainMenuEntry ? 0 : 1;
  m_Jpeg    = m_Plugin->m_Jpeg ? 1 : 0;
  m_Quality = m_Plugin->m_Quality;
  m_SizeX   = m_Plugin->m_SizeX;
  m_SizeY   = m_Plugin->m_SizeY;
  strcpy(m_DestDir, m_Plugin->m_DestDir);

  Add(new cMenuEditBoolItem(tr("Show in main menu"),     
			    &m_HideMainMenuEntry));
  Add(new cMenuEditStrItem( tr("Save snapshots to"),        
			    m_DestDir, 255, FileNameChars));
  Add(new cMenuEditStraItem(tr("Image format"),             
			    &m_Jpeg,     2, sImageFormats));
  Add(new cMenuEditIntItem( tr("Jpeg compression quality"), 
			    &m_Quality, -1, 0xff));
  Add(new cMenuEditIntItem( tr("Image width"),              
			    &m_SizeX,    1, 2048));
  Add(new cMenuEditIntItem( tr("Image height"),             
			    &m_SizeY,    1, 2048));
}



