#include "plugins.h"
#include <vdr/recording.h>

extern const char *VideoDirectory;
extern cRecordings Recordings;

vdrrecording::vdrrecording() : 
	mediaplugin("vdr_rec") 
{
	addPattern(pattern(State, "001.vdr", tr("VDR Recording")));
	addPattern(pattern(Find, "001.vdr", tr("VDR Recording")));
}

bool vdrrecording::checkPluginAvailable(bool ignoreActivation)
{
	// always return true as it is a fix part of vdr
	return true;
}

bool vdrrecording::checkPluginAvailable(const cPlugin* plugin) 
{
	return mediaplugin::checkPluginAvailable(plugin);
}

mediaplugin* vdrrecording::clone()
{
	return new vdrrecording(*this);
}

cOsdObject * vdrrecording::startPlugin() 
{
	const char *oldvideodir = VideoDirectory;
	char* path;

	if (_needsUmount) {
		_st_curDevice->umount();
	}
	if (_needsDirectory) {
		if (_st_tmpCdrom == NULL) {
			_st_tmpCdrom = tmpnam(NULL);
			mkdir(_st_tmpCdrom,0777);
			asprintf(&path, "%s/cdrom", _st_tmpCdrom);
			mkdir(path, 0777);
			free(path);
			asprintf(&path, "%s/cdrom/%s", _st_tmpCdrom, VDRSUBDIR);
			symlink(_st_curDirectory, path);
			free(path);
		}
		VideoDirectory = _st_tmpCdrom;
	} else
		VideoDirectory = _st_curDirectory;

	DPRINT("open recmenu in %s\n", VideoDirectory);

	_st_status->setCurrentDevice(_st_curDevice);

	Recordings.Load();
	cPlugin *p = cPluginManager::GetPlugin("extrecmenu");
	if(p) {
		DPRINT("using extrecmenu\n");
		cOsdObject *osd = NULL;
		osd = p->MainMenuAction();
		VideoDirectory = oldvideodir;
		_st_status->LinkedRecording(true);
		return osd;
	} 
	cOsdMenu *menu = new cMenuRecordings();
	VideoDirectory = oldvideodir;
	_st_status->LinkedRecording(true);

	return menu;
}

dmharchivedvd::dmharchivedvd() : 
	mediaplugin("dmh_archive") 
{
	setSearchMode(And);
	addPattern(pattern(State, "video_ts", tr("DMH DVD")));
	addPattern(pattern(Find, "dvd.vdr", tr("DMH DVD")));
}

bool dmharchivedvd::checkPluginAvailable(bool ignoreActivation)
{
	// always return true as it is a fix part of vdr
	return true;
}

bool dmharchivedvd::checkPluginAvailable(const cPlugin* plugin) 
{
	//return mediaplugin::checkPluginAvailable(plugin);
	return false;
}

mediaplugin* dmharchivedvd::clone()
{
	return new dmharchivedvd(*this);
}

cOsdObject * dmharchivedvd::startPlugin() 
{
	const char *oldvideodir = VideoDirectory;
	char* titlePath = NULL;
	char* episodePath = NULL;
	struct stat buf;

	DPRINT("checking for dmh-archive-dvd\n");

	// TODO: OK
	//if (_st_tmpCdrom == NULL) {
	char *video_ts_dir;
	if (_needsUmount) {
		_st_curDevice->umount();
	}
	// TODO OK?
	//if(_st_tmpCdrom)
	//	free(_st_tmpCdrom);
	_st_tmpCdrom = tmpnam(NULL);
	mkdir(_st_tmpCdrom,0777);
	asprintf(&video_ts_dir, "%s/video_ts",_st_curDirectory);
	if(stat(video_ts_dir, &buf) != 0) {
			DPRINT("did not find %s\n", video_ts_dir);
		asprintf(&video_ts_dir, "%s/VIDEO_TS",_st_curDirectory);
		if(stat(video_ts_dir, &buf) != 0) {
			DPRINT("did not find %s\n", video_ts_dir);
			Skins.Message(mtError, tr("Wrong dmh-archive-dvd structure!"));
			free(video_ts_dir);
			return NULL;
		}
	}
	for(int track = 0; track <= 99; track++) {
		char *info_vdr;
		asprintf(&info_vdr, "%s/info_%.2d.vdr",video_ts_dir, track);
		if(stat(info_vdr, &buf) == 0) {
			char *index_vdr;
			char path_buf[BUF_SIZ];
			FILE* finfo;
			cReadLine ReadLine;
			char* bufinfo = NULL;
			char* title = NULL;
			char* episode = NULL;
			// create title dir
			if ((finfo = fopen(info_vdr, "r")) != (FILE *)NULL) {
				while((	bufinfo = ReadLine.Read(finfo))) {
					if(bufinfo[0] == 'T')
					break;
				}
				fclose(finfo);
			}
			if(bufinfo)
				asprintf(&title, "%s", bufinfo + 2);
			else
				asprintf(&title, "cdrom");
			if(titlePath)
			{
				free(titlePath);
				titlePath = NULL;
			}
			asprintf(&titlePath, "%s/%s", _st_tmpCdrom, title);
			mkdir(titlePath, 0777);
			// check whether there is an episode name
			if ((finfo = fopen(info_vdr, "r")) != (FILE *)NULL) {
				while((	bufinfo = ReadLine.Read(finfo))) {
					if(bufinfo[0] == 'S')
					break;
				}
				fclose(finfo);
			}
			if(bufinfo)
				asprintf(&episode, "%s", bufinfo + 2);
			else
				asprintf(&episode, "track%d",track);
			if(episodePath)
			{
				free(episodePath);
				episodePath = NULL;
			}
			asprintf(&episodePath, "%s/%s", titlePath, episode);
			DPRINT("Episode path %s\n", episodePath);
			mkdir(episodePath, 0777);

			asprintf(&index_vdr, "%s/index_%.2d.vdr",video_ts_dir,track);
			if(episodePath)
				asprintf(&index_vdr, "%s/index_%.2d.vdr",video_ts_dir,track);
			if(episodePath)
			{
				free(episodePath);
				episodePath = NULL;
			}
			asprintf(&episodePath, "%s/%s/%s/%s%.2d.rec", _st_tmpCdrom, title, episode, VDRSUBDIRARCH, track);
			mkdir(episodePath, 0777);
			sprintf(path_buf, "%s/%s/%s/%s%.2d.rec/index.vdr", _st_tmpCdrom, title, episode, VDRSUBDIRARCH, track);
			symlink(index_vdr, path_buf);
			sprintf(path_buf, "%s/%s/%s/%s%.2d.rec/info.vdr", _st_tmpCdrom, title, episode, VDRSUBDIRARCH, track);
			symlink(info_vdr, path_buf);
			for(int n = 0; n <= MAXFILESPERRECORDING; n++) {
				char vob[BUF_SIZ];
				sprintf(vob, "%s/VTS_%02d_%d.VOB", video_ts_dir, track, n);
				DPRINT("VOB %s\n", vob);
				sprintf(path_buf, "%s/%s/%s/%s%.2d.rec/%03d.vdr", _st_tmpCdrom, title, episode, VDRSUBDIRARCH, track, n);
				if(stat(vob, &buf) != 0) {
					sprintf(vob, "%s/vts_%02d_%d.vob", video_ts_dir, track, n);
					if(stat(vob, &buf) != 0) 
						break;
				}
				symlink(vob, path_buf);
			}
			free(index_vdr);
			free(title);
			free(episode);
		}
		free(info_vdr);
	}
	free(video_ts_dir);
	if(titlePath)
	{
		free(titlePath);
		titlePath = NULL;
	}
	if(episodePath)
	{
		free(episodePath);
		episodePath = NULL;
	}
	//}
	VideoDirectory = _st_tmpCdrom;
	DPRINT("open recmenu in %s\n", VideoDirectory);

	_st_status->setCurrentDevice(_st_curDevice);

	Recordings.Load();
	cPlugin *p = cPluginManager::GetPlugin("extrecmenu");
	if(checkPluginAvailable(p)) {
		DPRINT("using extrecmenu\n");
		cOsdObject *osd = NULL;
		osd = p->MainMenuAction();
		VideoDirectory = oldvideodir;
		_st_status->LinkedRecording(true);
		return osd;
	} 
	cOsdMenu *menu = new cMenuRecordings();
	VideoDirectory = oldvideodir;
	_st_status->LinkedRecording(true);

	return menu;
}

vcd::vcd() : 
	mediaplugin("vcd")
{
	_needsUmount = true;
	addPattern(pattern(MediaType, svcd, tr("SVCD")));
}

mediaplugin* vcd::clone()
{
	return new vcd(*this);
}

cOsdObject * vcd::startPlugin() 
{
	cPlugin *p = cPluginManager::GetPlugin(getName());
	cOsdObject *osd = NULL;
	if (checkPluginAvailable(p)) {
		osd = p->MainMenuAction();

		const char *last = _st_status->Current();

		osd->ProcessKey(kDown);
		if (_st_status->Current() != last) {
			// VCD has more than one track, so leave the menu open
			osd->ProcessKey(kUp);
		} else {
			// Autostart CD and destroy menu
			osd->ProcessKey(kOk);

			delete osd;
			osd = NULL;
		}
	}
	return osd;
}

mplayer::mplayer() : 
	mediaplugin("mplayer") 
{
	addPattern( pattern(Find, "*.avi", tr("AVI movie disc")));
	addPattern( pattern(Find, "*.avi-????", tr("AVI movie disc")));
	addPattern( pattern(Find, "*.mpg", tr("MPG movie disc")));
	addPattern( pattern(Find, "*.mpeg", tr("MPG movie disc")));
}

mediaplugin* mplayer::clone()
{
	return new mplayer(*this);
}

cOsdObject * mplayer::startPlugin() 
{
	DPRINT("Looking for mplayer plugin\n");
	cPlugin *p = cPluginManager::GetPlugin(getName());
	cOsdObject *osd = NULL;
	if (checkPluginAvailable(p)) {
		DPRINT("Found mplayer plugin\n");
		osd = p->MainMenuAction();
		// Switch to "source" mode
		osd->ProcessKey(kYellow);
		// Move to first entry
		const char *actual = _st_status->Current();
		osd->ProcessKey(kUp);
		while (actual != _st_status->Current()) {
			osd->ProcessKey(kUp);
			actual = _st_status->Current();
		}
		// Search for /cdrom-entry
		bool mplayersource = true;
		while (strstr(actual, _st_curDirectory) == NULL) {
			osd->ProcessKey(kDown);
			if (actual == _st_status->Current()) {
				mplayersource = false;
				break;
			} else {
				actual = _st_status->Current();
			}
		}
		if (mplayersource) {
			osd->ProcessKey(kOk);

			const char *last = _st_status->Current();
			osd->ProcessKey(kDown);
			if (_st_status->Current() != last) {
				DPRINT("Multiple avi files\n");
				// CD has more than one avi-file, so leave the menu open
				osd->ProcessKey(kUp);
			} else {
				DPRINT("Only a single avi file\n");
				// eutostart CD and destroy menu
				// TODO warum do nix gehen?
				osd->ProcessKey(kRed);
			}
		} else {
			delete osd;
			osd = NULL;
			Skins.Message(mtError, tr("Drive not present in mplayersources.conf!"));
		}
	}
	return osd;
}

music::music() : 
	mediaplugin("music") 
{
	addPattern( pattern(Find, "*.mp3", tr("MP3 player")));
	addPattern( pattern(Find, "*.ogg", tr("OGGVorbis player")));
	addPattern( pattern(Find, "*.wav", tr("Audio CD")));
}

music::~music()
{
}

mediaplugin* music::clone()
{
	return new music(*this);
}

cOsdObject* music::startPlugin() 
{
	DPRINT("Looking for music plugin\n");
	cPlugin *p = cPluginManager::GetPlugin(getName());
	cOsdObject *osd = NULL;
	if (checkPluginAvailable(p)) {
		DPRINT("Found music plugin\n");
		osd = p->MainMenuAction();

		const char *wanted = I18nTranslate("MP3", getName());

		// Switch to Browse Mode if not already done...
		if (strncmp(_st_status->Title(), wanted, strlen(wanted)) != 0)
			osd->ProcessKey(kBack);

		// Now switch into "source" mode
		osd->ProcessKey(kGreen);

		const char *last = NULL;
		const char *first = NULL;
		bool found = false;
		while (last != _st_status->Current() && first != _st_status->Current()) {
                        DPRINT("dir: %s (%s)\n", _st_status->Current(), last ? last : "NULL");
                        char *_st_curSubDir = strdup(_st_curDirectory);
                        char *_st_curSubDirLast = _st_curSubDir + strlen(_st_curSubDir) - 1;
                        while (_st_curSubDirLast >= _st_curSubDir) {
                                DPRINT("trying: %s (%s)\n", _st_curSubDir, _st_curDirectory);
                                if ((strcmp(_st_status->Current() + strlen(_st_status->Current()) 
                                                - strlen(_st_curSubDir), _st_curSubDir) == 0) 
                                                && ((* (_st_status->Current() + strlen(_st_status->Current()) 
                                                - strlen(_st_curSubDir) - 1)) != ' ')) {
                                        DPRINT("play it!!\n");
        
                                        osd->ProcessKey(kRed);    // Select it
                                        osd->ProcessKey(kYellow); // Change to browse mode again
        
                                        osd->ProcessKey(kYellow); // Instant Playback
                                        
                                        found = true;
                                        break;
                                }
                                do {
                                        (* _st_curSubDirLast) = 0;
                                        _st_curSubDirLast--;
                                        if ((_st_curSubDirLast >= _st_curSubDir) && (* _st_curSubDirLast) == '/') {
                                                if (_st_curSubDirLast > _st_curSubDir) {
                                                        (* _st_curSubDirLast) = 0;
                                                        _st_curSubDirLast--;
                                                }
                                                break;
                                        }
                                } while (_st_curSubDirLast > _st_curSubDir);
			}
			free(_st_curSubDir);
			if (found) {
                                break;
                        }

			last = _st_status->Current();
                        if (first == NULL) {
                            first = _st_status->Current();
                        }
			osd->ProcessKey(kDown);
		}

		/*delete osd;
		osd = NULL;
		*/
		if (! found)
			Skins.Message(mtError, tr("Drive not present in musicsources.conf!"));
	}
	return osd;
}

mp3::mp3() : 
	mediaplugin("mp3") 
{
	addPattern( pattern(Find, "*.mp3", tr("MP3 player")));
	addPattern( pattern(Find, "*.ogg", tr("OGGVorbis player")));
	addPattern( pattern(Find, "*.wav", tr("Audio CD")));
}

mp3::~mp3()
{
}

mediaplugin* mp3::clone()
{
	return new mp3(*this);
}

cOsdObject* mp3::startPlugin() 
{
	DPRINT("Looking for mp3 plugin\n");
	cPlugin *p = cPluginManager::GetPlugin(getName());
	cOsdObject *osd = NULL;
	if (checkPluginAvailable(p)) {
		DPRINT("Found mp3 plugin\n");
		osd = p->MainMenuAction();

		const char *wanted = I18nTranslate("MP3", getName());

		// Switch to Browse Mode if not already done...
		if (strncmp(_st_status->Title(), wanted, strlen(wanted)) != 0)
			osd->ProcessKey(kBack);

		// Now switch into "source" mode
		osd->ProcessKey(kGreen);

		const char *last = NULL;
		const char *first = NULL;
		bool found = false;
		while (last != _st_status->Current() && first != _st_status->Current()) {
                        DPRINT("dir: %s (%s)\n", _st_status->Current(), last ? last : "NULL");
                        char *_st_curSubDir = strdup(_st_curDirectory);
                        char *_st_curSubDirLast = _st_curSubDir + strlen(_st_curSubDir) - 1;
                        while (_st_curSubDirLast >= _st_curSubDir) {
                                DPRINT("trying: %s (%s)\n", _st_curSubDir, _st_curDirectory);
                                if ((strcmp(_st_status->Current() + strlen(_st_status->Current()) 
                                                - strlen(_st_curSubDir), _st_curSubDir) == 0) 
                                                && ((* (_st_status->Current() + strlen(_st_status->Current()) 
                                                - strlen(_st_curSubDir) - 1)) != ' ')) {
                                        DPRINT("play it!!\n");
        
                                        osd->ProcessKey(kRed);    // Select it
                                        osd->ProcessKey(kYellow); // Change to browse mode again
        
                                        osd->ProcessKey(kYellow); // Instant Playback
                                        
                                        found = true;
                                        break;
                                }
                                do {
                                        (* _st_curSubDirLast) = 0;
                                        _st_curSubDirLast--;
                                        if ((_st_curSubDirLast >= _st_curSubDir) && (* _st_curSubDirLast) == '/') {
                                                if (_st_curSubDirLast > _st_curSubDir) {
                                                        (* _st_curSubDirLast) = 0;
                                                        _st_curSubDirLast--;
                                                }
                                                break;
                                        }
                                } while (_st_curSubDirLast > _st_curSubDir);
			}
			free(_st_curSubDir);
			if (found) {
                                break;
                        }

			last = _st_status->Current();
                        if (first == NULL) {
                            first = _st_status->Current();
                        }
			osd->ProcessKey(kDown);
		}

		/*delete osd;
		osd = NULL;
		*/
		if (! found)
			Skins.Message(mtError, tr("Drive not present in mp3sources.conf!"));
	}
	return osd;
}

ripit::ripit() : 
	mediaplugin("ripit")
{
	_needsUmount = true;
	addPattern( pattern(Find, "*.wav", tr("Audio CD for ripping")));
}

mediaplugin* ripit::clone()
{
	return new ripit(*this);
}

cOsdObject * ripit::startPlugin() 
{
	cPlugin *p = cPluginManager::GetPlugin(getName());
	cOsdObject *osd = NULL;
	if (checkPluginAvailable(p)) {
		osd = p->MainMenuAction();
		osd->ProcessKey(kRed);
	}
	return osd;
}

dvd::dvd() : 
	mediaplugin("dvd")
{
	_needsUmount = true;
	addPattern(pattern(State, "video_ts", tr("Video DVD")));
}

mediaplugin* dvd::clone()
{
	return new dvd(*this);
}

photocd::photocd() : 
	mediaplugin("pcd")
{
	_needsUmount = true;
	addPattern(pattern(State, "photo_cd", tr("Photo CD")));
}

mediaplugin* photocd::clone()
{
	return new photocd(*this);
}

cdda::cdda() :
   mediaplugin("cdda")
{
  _needsUmount = true;
  addPattern( pattern(MediaType, audio, tr("Audio CD Player")));
}

mediaplugin* cdda::clone()
{
	return new cdda(*this);
}

burn::burn() :
   mediaplugin("burn")
{
  _needsUmount = true;
  addPattern( pattern(MediaType, blank, tr("DVD creation")));
}

mediaplugin* burn::clone()
{
	return new burn(*this);
}

image::image() : 
	mediaplugin("image") 
{
	addPattern( pattern(Find, "*.jpg", "JPEG"));
	addPattern( pattern(Find, "*.jpeg", "JPEG"));
	addPattern( pattern(Find, "*.png", "PNG"));
	addPattern( pattern(Find, "*.tiff", "TIFF"));
	addPattern( pattern(Find, "*.bmp", "BITMAP"));
}

image::~image()
{
}

mediaplugin* image::clone()
{
	return new image(*this);
}

cOsdObject* image::startPlugin() 
{
	DPRINT("Looking for image plugin\n");
	cPlugin *p = cPluginManager::GetPlugin(getName());
	cOsdObject *osd = NULL;
	if (checkPluginAvailable(p)) {
		DPRINT("Found image plugin\n");
		osd = p->MainMenuAction();

		const char *wanted = I18nTranslate("Image source", getName());

		// Switch to Browse Mode if not already done...
		if (strncmp(_st_status->Title(), wanted, strlen(wanted)) != 0)
			osd->ProcessKey(kYellow);

		const char *last = NULL;
		const char *first = NULL;
		bool found = false;
		while (last != _st_status->Current() && first != _st_status->Current()) {
                        DPRINT("dir: %s (%s)\n", _st_status->Current(), last ? last : "NULL");
                        char *_st_curSubDir = strdup(_st_curDirectory);
                        char *_st_curSubDirLast = _st_curSubDir + strlen(_st_curSubDir) - 1;
                        while (_st_curSubDirLast >= _st_curSubDir) {
                                DPRINT("trying: %s (%s)\n", _st_curSubDir, _st_curDirectory);
                                if ((strcmp(_st_status->Current() + strlen(_st_status->Current()) 
                                                - strlen(_st_curSubDir), _st_curSubDir) == 0) 
                                                && ((* (_st_status->Current() + strlen(_st_status->Current()) 
                                                - strlen(_st_curSubDir) - 1)) != ' ')) {
                                        DPRINT("play it!!\n");
        
                                        osd->ProcessKey(kRed);    // Select it
                                        osd->ProcessKey(kRed); // Change to browse mode again
        
                                        found = true;
                                        break;
                                }
                                do {
                                        (* _st_curSubDirLast) = 0;
                                        _st_curSubDirLast--;
                                        if ((_st_curSubDirLast >= _st_curSubDir) && (* _st_curSubDirLast) == '/') {
                                                if (_st_curSubDirLast > _st_curSubDir) {
                                                        (* _st_curSubDirLast) = 0;
                                                        _st_curSubDirLast--;
                                                }
                                                break;
                                        }
                                } while (_st_curSubDirLast > _st_curSubDir);
			}
			free(_st_curSubDir);
			if (found) {
                                break;
                        }

			last = _st_status->Current();
                        if (first == NULL) {
                            first = _st_status->Current();
                        }
			osd->ProcessKey(kDown);
		}

		/*delete osd;
		osd = NULL;
		*/
		if (! found)
			Skins.Message(mtError, tr("Drive not present in imagesources.conf!"));
	}
	return osd;
}


