/**
 *  GraphTFT plugin for the Video Disk Recorder 
 * 
 *  graphtft.c - A plugin for the Video Disk Recorder
 *
 *  (c) 2004 Lars Tegeler, Sascha Volkenandt  
 *
 * This code is distributed under the terms and conditions of the
 * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
 *
 * $Id: graphtft.c,v 1.12 2004/05/26 11:34:33 tegeler Exp $
 *
 **/

#include "display.h"
#include "setup.h"
#include "theme.h"
#include "i18n.h"
#include "osd.h"
#include "memcpy.h"
#include "getopt.h"
#include <vdr/plugin.h>
#include <vdr/config.h>

static const char *VERSION        = "0.0.8";
static const char *THEMEVERSION   = "0.1.0";
static const char *DESCRIPTION    = "Display Info on TFT";
//static const char *MAINMENUENTRY  = "";

void *(* fast_memcpy)(void *to, const void *from, size_t len);

class cPluginGraphTFT : public cPlugin {

// Add any member variables or functions you may need here.
private:
  cGraphTFTDisplay *_graphTFTdisplay;
  char *_cfgDir;
  char *_dev;

public:
  cPluginGraphTFT(void);
  virtual ~cPluginGraphTFT();
  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  NULL; 
  }
  virtual cOsdObject *MainMenuAction(void);
  virtual cMenuSetupPage *SetupMenu(void);
  virtual bool SetupParse(const char *Name, const char *Value);
  };

cPluginGraphTFT::cPluginGraphTFT(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!
  _graphTFTdisplay = NULL;
  _cfgDir = NULL;
  _dev = NULL;
}

cPluginGraphTFT::~cPluginGraphTFT()
{
  // Clean up after yourself!
  if (_graphTFTdisplay)
    delete _graphTFTdisplay;
  delete[] _cfgDir;
  delete[] _dev;

}

const char *cPluginGraphTFT::CommandLineHelp(void)
{
 // Return a string that describes all known command line options.
 return "   -d DEV,  --device=DEV   sets the output-device\n"
#ifdef HAVE_IMLIB
	"                           /dev/fb0 or vdr/1 \n"
#endif
#if HAVE_DFB
 	"                           directFB \n"
#endif
	"                           (default: autodetect)\n";
}

bool cPluginGraphTFT::ProcessArgs(int argc, char *argv[])
{
	// Implement command line argument processing here if applicable.
	static struct option long_options[] = {
		{ "device",      required_argument, NULL, 'd' },
		{ NULL }
    	};

    	int c;
	bool retValue = false;

    	// check the arguments for the plugin
	while ((c = getopt_long(argc, argv, "d:", long_options, NULL)) != -1) {
        	switch (c) {
			// the device argument
	    		case 'd':
				fprintf(stderr, "vdr: graphtft - arg: %s\n", optarg);
#ifdef HAVE_IMLIB
				if (strstr(optarg, "/dev/fb")){
					// found framebuffer
					_dev = strdup(optarg);
					retValue = true;
				}else if (strstr(optarg, "vdr/")){
					// found vdrdevice
					_dev = strdup(optarg);
					retValue = true;
				}
#endif
#if HAVE_DFB
				if (strstr(optarg, "directFB")){
					// found directFB
					_dev = strdup(optarg);		
					retValue = true;
				}
#endif
				if (!retValue){
					// dont know this device string
					fprintf(stderr, "vdr: graphtft - device unknowen: %s\n", optarg);
					return false;
				}
				break;
				
				// any other argument
	   		 default:
				fprintf(stderr, "vdr: graphtft - argument unknowen (char): %c\n", c);
				return false;
		}
    	}
    	return true;

}

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

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

#ifdef HAVE_FAST_MEMCPY
  probe_fast_memcpy(0);
#else
  fast_memcpy = memcpy;
#endif

	//local variables
	const char * str;
	char *buffer = NULL;
	int index = 0;

#ifdef HAVE_IMLIB
	if (!_dev)
	{
		for (int i = 0; i < cDevice::NumDevices(); i++) {
			cDevice *d = cDevice::GetDevice(i);
			if (d &&(!d->IsPrimaryDevice()) && d->HasDecoder()) {
				fprintf(stderr, "vdr: graphtft -  try device: vdr/%d !\n", i);
				asprintf(&_dev, "vdr/%d", i);
				break;
			}
		}
	}
#endif

#ifdef HAVE_DFB
	if (!_dev)
	{
		fprintf(stderr, "vdr: graphtft - try directFB device!\n");
		asprintf(&_dev,"directFB");
	}       
#endif

#ifdef HAVE_IMLIB
	if (!_dev)
	{
		fprintf(stderr, "vdr: graphtft - try framebuffer device!\n");
		asprintf(&_dev,"/dev/fb0");
	}
#endif
	// try to get the config dir
	str = ConfigDirectory();
	if (!str)
		return false;
	_cfgDir = strdup(str);
	GraphTFTSetup.PluginConfPath = strdup(str);
	
	//Find the themes in the config directory
	asprintf(&buffer, "find %s/graphTFT/themes -follow -type f -name '*.theme' | sort", _cfgDir);
	FILE *p = popen(buffer, "r");
	free(buffer);
	if (p) {
		char *s;
		cReadLine ReadLine;
		while ((s = ReadLine.Read(p)) != NULL && index < MAXTHEME ){
			//Try to load the themes
			GraphTFTTheme.Load(s);
			cGraphTFTThemeItem *item = GraphTFTTheme.Get(itemTheme);
			if (item != NULL)
			{
				// check if the theme fit to current version
				if ( strcmp( item->Version().c_str(), THEMEVERSION) == 0 ){

					// if the theme has a valid theme Item, add the theme to Themes Array 
					// FIX ME: we shloud use a list of theme objects to store the themes
					std::string name = item->Name();
					GraphTFTSetup.Themes[index] = strdup(name.c_str());
					GraphTFTSetup.ThemesPath[index] = strdup(s);
					index++;
				}else{
					fprintf(stderr, "vdr: graphtft - themeversion dosen't match\n");
				}
			}
		}
	}
	// Have we found themes?
	if ( index == 0 )
	{
		// Nop, we haven't -> error
		fprintf(stderr, "vdr: graphtft - start: None themes found!\n");
		return false;
	}else{
		// Yep, so the the theme stored in setup
		// FIX ME: with the list of theme object we should check names, not indexs
		GraphTFTSetup.ThemesFound = index;
		if ( index > GraphTFTSetup.Theme )
			GraphTFTTheme.Load(GraphTFTSetup.ThemesPath[GraphTFTSetup.Theme]);
		else
			// Found fewer themes then the setup value is set to
			// so lets take the first one
			GraphTFTTheme.Load(GraphTFTSetup.ThemesPath[0]);
	}
       
	// first register the translations
	RegisterI18n(Phrases);

	// create the display object
	_graphTFTdisplay = new cGraphTFTDisplay();

	// if creating was ok, try to init both and return true if all was ok
	if (_graphTFTdisplay){
		return _graphTFTdisplay->Init(_dev, _cfgDir);
	}

	return false;
}

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

cOsdObject *cPluginGraphTFT::MainMenuAction(void)
{
	return NULL;
}

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

bool cPluginGraphTFT::SetupParse(const char *Name, const char *Value)
{
  // Parse your own setup parameters and store their values.
  return GraphTFTSetup.SetupParse(Name, Value);
}

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