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

#include <vdr/plugin.h>
#include <vdr/status.h>
#include <vdr/config.h>
#include <vdr/interface.h>
#include "getopt.h"
#include "radiotransfer.h"
#include "i18n.h"
//file exists 
#include <sys/stat.h>

static const char *VERSION        = "0.0.8c";
static const char *DESCRIPTION    = "Radio Background-Image/RDS-Text";
static const char *MAINMENUENTRY  = "Show RDS-Radiotext";

//Setup-Params
int S_Activate = false;
int S_RtFunc = 1;
int S_RtOsdTitle = 1;
int S_RtOsdTags = 2;
int S_RtOsdPos = 1;
int S_RtOsdRows = 3;
int S_RtOsdLoop = 0;
int S_RtOsdTO = 60;
int S_RtBgCol = 0;
int S_RtBgTra = 0xA0;
int S_RtFgCol = 1;
int S_RtDispl = 1;
#if VDRVERSNUM < 10332
int S_RtUserkey = 9;
#endif
int S_HMEntry = false;
eKeys RT_Userkey;
uint32_t rt_color[9];
int S_Verbose = 1;
//Radiotext
char RT_Text[5][RT_MEL];
char RTP_Artist[RT_MEL], RTP_Title[RT_MEL];
int RT_Info, RT_Index;
int RT_PTY;
struct tm *RTP_TitStart;
bool RT_OsdTO = false, RT_OsdOpen = false;
//RadioCheck
const cChannel *chan;
bool IsRadio;

struct RadioTextService_v1_0 {
  int rds_info;		// 0= no / 1= Text / 2= Text + RTplus-Tags (Item,Artist)
  int rds_pty;		// 0-31
  char *rds_text;
  char *rds_title;
  char *rds_artist;
  struct tm *title_start;
};


// --- cRadioCheck -------------------------------------------------------

class cRadioCheck: public cThread {
private:
    bool m_Active;
    static cRadioCheck *RadioCheck;
protected:
    virtual void Action(void);
    void Stop(void);
public:
    cRadioCheck(void);
    virtual ~cRadioCheck();
    static void Init(void);
    static void Exit(void);
};

cRadioCheck *cRadioCheck::RadioCheck = NULL;

cRadioCheck::cRadioCheck(void)
: cThread("radiocheck")
{
    m_Active = IsRadio = false;
}

cRadioCheck::~cRadioCheck() {
    if (m_Active) 
	Stop();
}

void cRadioCheck::Init(void) {
    if (RadioCheck == NULL) {
	RadioCheck = new cRadioCheck;
	RadioCheck->Start();
    }
}

void cRadioCheck::Exit(void) {
    if (RadioCheck != NULL) {
	RadioCheck->Stop();
	DELETENULL(RadioCheck);
    }
}

void cRadioCheck::Stop(void) {
    m_Active = false;
    Cancel(3);
}

void cRadioCheck::Action(void) 
{
    m_Active = true;
    if (S_Verbose >= 2)
        printf("vdr-radio: background-checking starts\n");

    while (m_Active) {
	cCondWait::SleepMs(5000);
	if (IsRadio && chan != NULL && chan->Vpid()) {
	    if (S_Verbose >= 2)
    		printf("vdr-radio: channnel '%s' got Vpid = %d\n", chan->Name(), chan->Vpid());
	    IsRadio = false;
	    Channels.SwitchTo(cDevice::CurrentChannel());
	    //cDevice::PrimaryDevice()->SwitchChannel(chan, true);
	    }
	}

    if (S_Verbose >= 2)
        printf("vdr-radio: background-checking ends\n");
}


// --- cMenuSetupRadio -------------------------------------------------------

class cMenuSetupRadio : public cMenuSetupPage {
private:
  int newS_Activate;
  int newS_RtFunc;
  int newS_RtOsdTitle;
  int newS_RtOsdTags;
  int newS_RtOsdPos;
  int newS_RtOsdRows;
  int newS_RtOsdLoop;
  int newS_RtOsdTO;
  int newS_RtBgCol;
  int newS_RtBgTra;
  int newS_RtFgCol;
  int newS_RtDispl;
#if VDRVERSNUM < 10332
  int newS_RtUserkey;
#endif
  int newS_HMEntry;
  const char *T_RtFunc[3];
  const char *T_RtOsdTags[3];
  const char *T_RtOsdPos[2];
  const char *T_RtOsdLoop[2];
  const char *T_RtBgColor[9];
  const char *T_RtFgColor[9];
  const char *T_RtDisplay[3];
protected:
  virtual void Store(void);
public:
  cMenuSetupRadio(void);
  };

cMenuSetupRadio::cMenuSetupRadio(void)
{
  T_RtFunc[0] = tr("Off");
  T_RtFunc[1] = tr("only Text");
  T_RtFunc[2] = tr("Text+TagInfo");
  T_RtOsdTags[0] = tr("Off");
  T_RtOsdTags[1] = tr("only, if some");
  T_RtOsdTags[2] = tr("always");
  T_RtOsdPos[0] = tr("Top");
  T_RtOsdPos[1] = tr("Bottom");
  T_RtOsdLoop[0] = tr("latest at Top");
  T_RtOsdLoop[1] = tr("latest at Bottom");
  T_RtBgColor[0] = T_RtFgColor[0] = tr ("Black");
  T_RtBgColor[1] = T_RtFgColor[1] = tr ("White");
  T_RtBgColor[2] = T_RtFgColor[2] = tr ("Red");
  T_RtBgColor[3] = T_RtFgColor[3] = tr ("Green");
  T_RtBgColor[4] = T_RtFgColor[4] = tr ("Yellow");
  T_RtBgColor[5] = T_RtFgColor[5] = tr ("Magenta");
  T_RtBgColor[6] = T_RtFgColor[6] = tr ("Blue");
  T_RtBgColor[7] = T_RtFgColor[7] = tr ("Cyan");
  T_RtBgColor[8] = T_RtFgColor[8] = tr ("Transparent");
  T_RtDisplay[0] = tr("Off");
  T_RtDisplay[1] = tr("about MainMenu");
#if VDRVERSNUM < 10332
  T_RtDisplay[2] = tr("Auto with UserMacrokey");
#else
  T_RtDisplay[2] = tr("Automatic");
#endif

  newS_Activate = S_Activate;
  newS_RtFunc = S_RtFunc;
  newS_RtOsdTitle = S_RtOsdTitle;
  newS_RtOsdTags = S_RtOsdTags;
  newS_RtOsdPos = S_RtOsdPos;
  newS_RtOsdRows = S_RtOsdRows;
  newS_RtOsdLoop = S_RtOsdLoop;
  newS_RtOsdTO = S_RtOsdTO;
  newS_RtBgCol = S_RtBgCol;
  newS_RtBgTra = S_RtBgTra;
  newS_RtFgCol = S_RtFgCol;
  newS_RtDispl = (S_RtDispl > 2 ? 2 : S_RtDispl);
#if VDRVERSNUM < 10332
  newS_RtUserkey = S_RtUserkey;
#endif
  newS_HMEntry = S_HMEntry;
  
  Add(new cMenuEditBoolItem( tr("Activate"),      	 		&newS_Activate));
  Add(new cMenuEditStraItem( tr("RDSText Function"),     		&newS_RtFunc, 3, T_RtFunc));
  Add(new cMenuEditStraItem( tr("RDSText OSD-Position"),  		&newS_RtOsdPos, 2, T_RtOsdPos));
  Add(new cMenuEditBoolItem( tr("RDSText OSD-Titlerow"),		&newS_RtOsdTitle));
  Add(new cMenuEditIntItem(  tr("RDSText OSD-Rows (1-5)"),		&newS_RtOsdRows, 1, 5));
  Add(new cMenuEditStraItem( tr("RDSText OSD-Scrollmode"),     		&newS_RtOsdLoop, 2, T_RtOsdLoop));
  Add(new cMenuEditStraItem( tr("RDSText OSD-Taginfo"),     		&newS_RtOsdTags, 3, T_RtOsdTags));
  Add(new cMenuEditStraItem( tr("RDSText OSD-Backgr.Color"), 		&newS_RtBgCol, 9, T_RtBgColor));
  Add(new cMenuEditIntItem(  tr("RDSText OSD-Backgr.Transp."), 		&newS_RtBgTra, 1, 255));
  Add(new cMenuEditStraItem( tr("RDSText OSD-Foregr.Color"), 		&newS_RtFgCol, 8, T_RtFgColor));
  Add(new cMenuEditIntItem(  tr("RDSText OSD-Timeout (0-1440 min)"),	&newS_RtOsdTO, 0, 1440));
  Add(new cMenuEditStraItem( tr("RDSText Display"), 	 		&newS_RtDispl, 3, T_RtDisplay));
#if VDRVERSNUM < 10332
  Add(new cMenuEditIntItem(  tr("RDSText UserMacroKey No"), 		&newS_RtUserkey, 1, 9));
#endif
  Add(new cMenuEditBoolItem( tr("Hide MainMenuEntry"),   		&newS_HMEntry));
}

void cMenuSetupRadio::Store(void)
{
  SetupStore("Activate", 	  	S_Activate = newS_Activate);
  SetupStore("RDSText-Function",     	S_RtFunc = newS_RtFunc);
  SetupStore("RDSText-OsdTitle",        S_RtOsdTitle = newS_RtOsdTitle);
  SetupStore("RDSText-OsdTags",         S_RtOsdTags = newS_RtOsdTags);
  SetupStore("RDSText-OsdPosition",  	S_RtOsdPos = newS_RtOsdPos);
  SetupStore("RDSText-OsdRows",      	S_RtOsdRows = newS_RtOsdRows);
  SetupStore("RDSText-OsdLooping",     	S_RtOsdLoop = newS_RtOsdLoop);
  SetupStore("RDSText-OsdBackgrColor",  S_RtBgCol = newS_RtBgCol);
  SetupStore("RDSText-OsdBackgrTrans",  S_RtBgTra = newS_RtBgTra);
  SetupStore("RDSText-OsdForegrColor",  S_RtFgCol = newS_RtFgCol);
  SetupStore("RDSText-OsdTimeout",  	S_RtOsdTO = newS_RtOsdTO);
  SetupStore("RDSText-Display",      	S_RtDispl = newS_RtDispl);
#if VDRVERSNUM < 10332
  SetupStore("RDSText-UserKey",      	S_RtUserkey = newS_RtUserkey);
  switch (S_RtUserkey) {
    case 1: RT_Userkey = kUser1; break;
    case 2: RT_Userkey = kUser2; break;
    case 3: RT_Userkey = kUser3; break;
    case 4: RT_Userkey = kUser4; break;
    case 5: RT_Userkey = kUser5; break;
    case 6: RT_Userkey = kUser6; break;
    case 7: RT_Userkey = kUser7; break;
    case 8: RT_Userkey = kUser8; break;
    case 9: RT_Userkey = kUser9; break;
    }
#endif
  SetupStore("HideMenuEntry",        	S_HMEntry = newS_HMEntry);
}


// --- cPluginRadio -------------------------------------------------------

class cPluginRadio : public cPlugin, cStatus {
private:
  // Add any member variables or functions you may need here.
  const char *ConfigDir;
  bool ConfigDirParam;
  bool channelOsd;
public:
  cPluginRadio(void);
  virtual ~cPluginRadio();
  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 Stop(void);
  virtual void Housekeeping(void);
  virtual const char *MainMenuEntry(void) { return (S_Activate==0 || S_RtFunc==0 || S_RtDispl==0 || S_HMEntry ? NULL : tr(MAINMENUENTRY)); }
  virtual cOsdObject *MainMenuAction(void);
  virtual cMenuSetupPage *SetupMenu(void);
  virtual bool SetupParse(const char *Name, const char *Value);
  virtual bool Service(const char *Id, void *Data);
  virtual const char **SVDRPHelpPages(void);
  virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
protected:
  virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
  bool file_exists(const char * filename);
  //
  virtual void OsdClear(void) { channelOsd = false; }
  virtual void OsdChannel(const char *Text) { channelOsd = true; }
  virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle) { channelOsd = true; }
};

cPluginRadio::cPluginRadio(void)
{
  // Initialize any member variables here.
  // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
  // VDR OBJECTS TO EXIST OR PROADUCE ANY OUTPUT!

    ConfigDirParam = false;
    channelOsd = false;
    
    rt_color[0] = 0xFF000000;	//Black
    rt_color[1] = 0xFFFCFCFC;	//White
    rt_color[2] = 0xFFFC1414;	//Red
    rt_color[3] = 0xFF24FC24;	//Green
    rt_color[4] = 0xFFFCC024;	//Yellow
    rt_color[5] = 0xFFB000FC;	//Magenta
    rt_color[6] = 0xFF0000FC;	//Cyan
    rt_color[7] = 0xFF00FCFC;	//Blue
    rt_color[8] = 0x00000000;	//Transparent
}

cPluginRadio::~cPluginRadio()
{
  // Clean up after yourself!
  if (ConfigDir) delete(ConfigDir);
  cRadioCheck::Exit();
}


const char *cPluginRadio::CommandLineHelp(void)
{
  // Return a string that describes all known command line options.
 return "  -f dir,   --files=dir      use dir as image directory (default: <vdrconfig>/plugins/radio)\n"
        "  -v level, --verbose=level  set verbose level (default = 1, 0 = Off, 1 = RDS-Text+Tags,    \n"
	"                                                2 = +RDS-Telegram/Debug, 3 = +RawData 0xfd  \n";
}

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

	static struct option long_options[] = {
		{ "files",      required_argument, NULL, 'f' },
		{ "verbose",    required_argument, NULL, 'v' },
		{ NULL }
	};
    
	int c;
	while ((c = getopt_long(argc, argv, "f:v:", long_options, NULL)) != -1) {
		switch (c) {
			case 'f':
				printf("vdr-radio: arg files = %s\n", optarg);
				ConfigDir = strdup(optarg);
				ConfigDirParam = true;
				break;
			case 'v':
				printf("vdr-radio: arg verbose = %s\n", optarg);
				if (isnumber(optarg))
				    S_Verbose = atoi(optarg);
				break;
			default:
				printf("vdr-radio: arg char = %c\n", c);
				return false;
			}
	}
	return true;
}

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

bool cPluginRadio::Start(void)
{
  // Start any background activities the plugin shall perform.
  RegisterI18n(Phrases);
  printf("vdr-radio: Radio-Plugin Backgr.Image/RDS-Text starts...\n");

  if (!ConfigDirParam) 
    ConfigDir = strdup(ConfigDirectory(Name()));
  cRadioCheck::Init();    

  return true;
}

void cPluginRadio::Stop(void)
{
  cRadioCheck::Exit();
}

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

cOsdObject *cPluginRadio::MainMenuAction(void)
{
  // Perform the action when selected from the main VDR menu.
  if (S_Activate > 0 && cRadioTransferControl::ReceiverDevice() != NULL && S_RtFunc > 0 && S_RtDispl > 0) {
    cRadioTextOsd *rtosd = new cRadioTextOsd();
    return rtosd;
    }
  else
    return NULL;
}

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

bool cPluginRadio::SetupParse(const char *Name, const char *Value)
{
  // Parse your own setup parameters and store their values.
  if 	  (!strcasecmp(Name, "Activate"))             	S_Activate = atoi(Value);
  else if (!strcasecmp(Name, "RDSText-Function"))     	S_RtFunc = atoi(Value);
  else if (!strcasecmp(Name, "RDSText-OsdTitle"))       S_RtOsdTitle = atoi(Value);
  else if (!strcasecmp(Name, "RDSText-OsdTags"))        S_RtOsdTags = atoi(Value);
  else if (!strcasecmp(Name, "RDSText-OsdPosition"))  	S_RtOsdPos = atoi(Value);
  else if (!strcasecmp(Name, "RDSText-OsdRows")) {
       S_RtOsdRows = atoi(Value);
       if (S_RtOsdRows > 5)  S_RtOsdRows = 5;
       }
  else if (!strcasecmp(Name, "RDSText-OsdLooping"))  	S_RtOsdLoop = atoi(Value);
  else if (!strcasecmp(Name, "RDSText-OsdBackgrColor")) S_RtBgCol = atoi(Value);
  else if (!strcasecmp(Name, "RDSText-OsdBackgrTrans")) S_RtBgTra = atoi(Value);
  else if (!strcasecmp(Name, "RDSText-OsdForegrColor")) S_RtFgCol = atoi(Value);
  else if (!strcasecmp(Name, "RDSText-OsdTimeout")) {
       S_RtOsdTO = atoi(Value);
       if (S_RtOsdTO > 1440)  S_RtOsdRows = 1440;
       }
  else if (!strcasecmp(Name, "RDSText-Display"))      	S_RtDispl = atoi(Value);
#if VDRVERSNUM < 10332
  else if (!strcasecmp(Name, "RDSText-UserKey")) {
    S_RtUserkey = atoi(Value);
    switch (S_RtUserkey) {
        case 1: RT_Userkey = kUser1; break;
        case 2: RT_Userkey = kUser2; break;
        case 3: RT_Userkey = kUser3; break;
        case 4: RT_Userkey = kUser4; break;
        case 5: RT_Userkey = kUser5; break;
        case 6: RT_Userkey = kUser6; break;
        case 7: RT_Userkey = kUser7; break;
        case 8: RT_Userkey = kUser8; break;
        case 9: RT_Userkey = kUser9; break;
        }
    }
#endif
  else if (!strcasecmp(Name, "HideMenuEntry"))        	S_HMEntry = atoi(Value);
  else
     return false;
  return true;
}

bool cPluginRadio::Service(const char *Id, void *Data)
{
  if (strcmp(Id,"RadioTextService-v1.0") == 0 && S_Activate > 0 && S_RtFunc >= 1) {
     if (Data) {
        RadioTextService_v1_0 *data = (RadioTextService_v1_0*)Data;
	data->rds_pty = RT_PTY;
	data->rds_info = (RT_Info < 0) ? 0 : RT_Info;
	int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1;
        data->rds_text = RT_Text[ind];
        data->rds_title = RTP_Title;
        data->rds_artist = RTP_Artist;
	data->title_start = RTP_TitStart;
        }
     return true;
     }

  return false;
}

const char **cPluginRadio::SVDRPHelpPages(void)
{
  static const char *HelpPages[] = {
    "RTINFO\n"
    "  Print the radiotext information.",
    "RTCLOSE\n"
    "  Close the radiotext-osd,\n"
    "  Reopen can only be done over menu or channelswitch.",
    NULL
    };
  return HelpPages;
}

cString cPluginRadio::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
{
  if (strcasecmp(Command, "RTINFO") == 0) {
     // we use the default reply code here
     if (RT_Info == 2) {
	int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1;
	return cString::sprintf(" Radiotext: %s\n RT-Title : %s\n RT-Artist: %s\n", RT_Text[ind], RTP_Title, RTP_Artist);
	}
     else if (RT_Info == 1) {
	int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1;
	return cString::sprintf(" Radiotext: %s\n", 	RT_Text[ind]);
	}
     else
        return cString::sprintf(" Radiotext not available (yet)\n");
     }
  else if (strcasecmp(Command, "RTCLOSE") == 0) {
     // we use the default reply code here
     if (RT_OsdTO)
        return cString::sprintf("RT-OSD already closed");
     else {
        RT_OsdTO = true;
        return cString::sprintf("RT-OSD will be closed now");
        }
     }
  return NULL;
}

void cPluginRadio::ChannelSwitch(const cDevice *Device, int ChannelNumber)
{
	IsRadio = false;
	char *image;

	if (S_Activate == false) return;

        if (cDevice::CurrentChannel() == ChannelNumber) {
	    chan = ChannelNumber ? Channels.GetByNumber(ChannelNumber) : NULL;

	    if (chan != NULL && chan->Vpid() == 0) {
		asprintf(&image, "%s/%s.mpg", ConfigDir, chan->Name());
		if (!file_exists( image )) {
		    if (S_Verbose >= 2)
		        printf("vdr-radio: background image not found: %s (Channelname: %s)\n", image, chan->Name());
		    dsyslog("vdr-radio: background image not found: %s (Channelname: %s)\n", image, chan->Name());
		    free(image);
		    asprintf(&image, "%s/radio.mpg", ConfigDir);
		    if (!file_exists(image)) {
			dsyslog("vdr-radio: background image not found: %s (Channelname: %s)\n", image, chan->Name());
			if (S_Verbose >= 2)
			    printf("vdr-radio: background image not found: %s (Channelname: %s)\n", image, chan->Name());
			}
		    }
		if (S_Verbose >= 2)
		    printf("vdr-radio: apid = %d   Channelname: %s Use image : %s\n", chan->Apid(0), chan->Name(), image);
		cControl::Launch(new cRadioTransferControl(cDevice::ActualDevice(), 0, chan->Apids(), chan->Dpids(), chan->Spids(), image));
		//Radiotext Auto-Display
		if (S_RtFunc >= 1 && S_RtDispl >= 2 && (!Skins.IsOpen() && !cOsd::IsOpen() || RT_OsdOpen || channelOsd)) {
		    S_RtDispl = 3;
#if VDRVERSNUM < 10332
		    cRemote::Put(RT_Userkey);
#else
		    cRemote::CallPlugin("radio");
#endif
		    }
		free(image);
		IsRadio = true;
		}

	    }
}

bool cPluginRadio::file_exists(const char * filename) {
        struct stat file_stat;
        return ((stat(filename, &file_stat) == 0) ? true:false);
}

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