/*
 * mediad.c: A plugin for the Video Disk Recorder
 *
 * See the README file for copyright information and how to reach the author.
 *
 * author: Matthias Haas
 */

#include "mediad.h"
#include "i18n.h"
#include "setup.h"
#include "status.h"
#include "plugins.h"
#include "hal.h"
#include "selectdevicemenu.h"

#include <vdr/config.h>
#include <vdr/interface.h>
#include <vdr/plugin.h>
#include <vdr/menu.h>

#include <sys/wait.h>
#include <getopt.h>
#include <stdlib.h>
#include <vector>

extern const char *VideoDirectory;

static const char *VERSION        = "0.1.0";

class pluginMediaD : public cPlugin {
private:
  	char **Directories;
  	uint DirCount;
  	char *MountScript;
  	const char *tmpcdrom;

	cMediadStatus *status;
  	bool checkStart(mediaplugin &plugin, bool alwaysAsk = false);
	hal halBinding;
	deviceSources _devices;
public:
	  pluginMediaD(void);
	  virtual ~pluginMediaD();
	  virtual const char *Version(void) { return VERSION; }
	  virtual const char *Description(void) { return tr("autoplays identified media"); }
	  virtual const char *CommandLineHelp(void);
	  virtual bool ProcessArgs(int argc, char *argv[]);
	  virtual bool Start(void);
	  virtual void Stop(void);
	  virtual void Housekeeping(void);
	  virtual const char *MainMenuEntry(void) { return (MediadSetup.HideMenu ? NULL : tr("Play media")); }
	  virtual cOsdObject *MainMenuAction(void);
	  virtual cMenuSetupPage *SetupMenu(void);
	  virtual bool SetupParse(const char *Name, const char *Value);
};

pluginMediaD::pluginMediaD(void)
{
	DirCount = 0;
	Directories = NULL;
	MountScript = NULL;
 	tmpcdrom = NULL;
	status = NULL;
}

pluginMediaD::~pluginMediaD()
{
	char path[1024];
	if(tmpcdrom) {
		sprintf(path,"%s/cdrom/%s",tmpcdrom,VDRSUBDIR);
    		unlink(path);
    		sprintf(path,"%s/cdrom",tmpcdrom);
    		rmdir(path);
    		rmdir(tmpcdrom);
 	 }

	free(MountScript);
	delete[] Directories;
 	halBinding.Stop();
	if(status)
		delete status;
}

const char *pluginMediaD::CommandLineHelp(void)
{
	return "  -m MountScript, --mount=MountScript    mount.sh script\n";
}

bool pluginMediaD::ProcessArgs(int argc, char *argv[])
{
  	static struct option long_options[] = {
		{ "mount",       required_argument, NULL, 'm' },
       		{ NULL }
     	};

  	int c;
  	while ((c = getopt_long(argc, argv, "m:c:", long_options, NULL)) != -1) {
		switch (c) {
		case 'm': 
			device::setMountScript(optarg);
			MountScript = strdup(optarg);
			break;

		default:  
			return false;
		}
	}
  	return true;
}

bool pluginMediaD::Start(void) {
#if VDRVERSNUM < 10507
	 RegisterI18n(MyPluginPhrases);
#endif

	if (MountScript == NULL)  
	{
		device::setMountScript("pmount.sh");
		MountScript = strdup("pmount.sh");
	}
 		// add all known plugins
	status = new cMediadStatus;
	mediaplugin::setStatus(status);
	// TODO: make it configurable add devices
	_devices.Load(AddDirectory(ConfigDirectory(),"mediad.conf"));
 	if(_devices.Count()<1) {
 	  esyslog("ERROR: you should have defined at least one source in mediad.conf");
 	  fprintf(stderr,"No source(s) defined in mediad.conf\n");
 	  return false;
	}
	halBinding.setDevices(&_devices);
	halBinding.setMountScript(MountScript);

	// delete ripit.process 
	rmdir("/tmp/ripit.process");
	mediaplugin::setMountCmd(MountScript);

	halBinding.Start();

	return true;
}

void pluginMediaD::Stop(void)
{
}

void pluginMediaD::Housekeeping(void) {
}

cOsdObject *pluginMediaD::MainMenuAction(void) {
	bool matchedAnything = false;
	device *pCurDevice;
 	struct stat buf;

	fprintf(stderr, "mediad: MainMenuAction\n");
	if(hal::triggered)
	{
		pCurDevice = halBinding.getDevice();
		hal::triggered = false;
	} else if(selectDeviceMenu::triggered){
		pCurDevice = selectDeviceMenu::getDevice();
		selectDeviceMenu::triggered = false;
	} else {
		return new selectDeviceMenu(_devices);
	}
	if(!pCurDevice) {
		fprintf(stderr, "mediad: currently no device selected.\n");
	}
	mediaplugin::setCurrentDevice(pCurDevice);
	ripit ripit_plugin;
	ripit_plugin.searchPattern();
	mp3 mp3_plugin;
	mp3_plugin.searchPattern();
	cdda cdda_plugin;
	cdda_plugin.searchPattern();
 	if(stat("/tmp/ripit.process", &buf) == 0 && ( ripit_plugin.matches() || mp3_plugin.matches() || cdda_plugin.matches() )) {
		DPRINT("mediad: ripit process already started for audio cd\n");
		return NULL;
	}

	Skins.Message(mtStatus, tr("Identifying Disc"));
	int nrMatches = 0;

	// reset the state of all detection plugins
	mediaplugin* pPlugin = MediadSetup.mediaplugins.First();
	while(pPlugin) {
		pPlugin->reset();
		pPlugin = MediadSetup.mediaplugins.Next(pPlugin);
	}
	pCurDevice->mount();
	// now we know where it is really mounted
	mediaplugin::setCurrentDevice(pCurDevice);

	mediaplugin *lastMatched = MediadSetup.mediaplugins.First();
	pPlugin = MediadSetup.mediaplugins.First();
	while(pPlugin) 
	{
		fprintf(stderr, "mediad: current plugin %s\n", pPlugin->getName());
		if(pPlugin->checkPluginAvailable()) 
		{
			pPlugin->searchPattern();
			if(pPlugin->matches()) {
				fprintf(stderr, "  found\n");
				lastMatched = pPlugin;
				matchedAnything = true;
				nrMatches++;
			}
		}
		pPlugin = MediadSetup.mediaplugins.Next(pPlugin);
	}

	switch(nrMatches) {
		case 0:
		{
			break;
		}
		case 1:
		{
			if(checkStart(*lastMatched)) {
				Skins.Message(mtStatus, NULL);
				Skins.Flush();
				return lastMatched->execute();
			}
			break;
		}
		default:
		{
			pPlugin = MediadSetup.mediaplugins.First();
			while(pPlugin) 
			{
				if(pPlugin->matches() &&
				    checkStart((*pPlugin), true)) {
					Skins.Message(mtStatus, NULL);
					Skins.Flush();
					return pPlugin->execute();
				}
				pPlugin = MediadSetup.mediaplugins.Next(pPlugin);
			}
		}
	}

	pCurDevice->umount();

	if(!matchedAnything)
		Skins.Message(mtError, tr("Couldn't identify disc!"));
	
	return NULL;
}

cMenuSetupPage *pluginMediaD::SetupMenu(void) {
  	return new cMediadMenuSetupPage;
}

bool pluginMediaD::SetupParse(const char *Name, const char *Value) {
  	return MediadSetup.SetupParse(Name, Value);
}

bool pluginMediaD::checkStart(mediaplugin &plugin, bool alwaysAsk) {
	if(!plugin.isAutoStart() || alwaysAsk) {
		char* msg;
		asprintf(&msg, "%s %s?", tr("Start of"), tr(plugin.getDescription()));
		DPRINT("Asking %s\n", msg);
 		if(Interface->Confirm(msg)) {
			free(msg);
			return true;
		}
		return false;
		free(msg);
	} 
	return true;
}

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