/*
 * See the files COPYING and README for copyright information and how to reach
 * the author.
 *
 *  $Id: jobs.h,v 1.12 2006/04/24 19:43:37 lordjaxom Exp $
 */

#ifndef VDR_BURN_JOBS_H
#define VDR_BURN_JOBS_H

#include "common.h"
#include "skins.h"
#include "setup.h"
#include "chain-vdr.h"
#include "proctools/format.h"
#include "proctools/process.h"
#include <list>
#include <deque>
#include <string>
#include <numeric>
#include <vdr/videodir.h>

class cRecording;

namespace vdr_burn {

	class skin;
	class chain_vdr;

	namespace menu 
	{ 
		class track_editor; 
		class job_editor;
		class recording_edit_item;
	}

	// --- recording ----------------------------------------------------------

	class recording
	{
		friend class menu::recording_edit_item;

		friend class cBurnMenuBurn;
		friend class cBurnMenuEditRecordingItem;
		friend class cBurnMenuTracks;

	private:
		std::string     m_fileName;
		std::string     m_summary;
		std::string     m_datetime;
		path_pair       m_paths;
		char            m_name[JOBNAMELEN + 1];
		int             m_index;
		track_info_list m_videoTracks;
		track_info_list m_audioTracks;
		track_info_list m_usedAudioTracks;
		track_info_list m_unusedAudioTracks;

	protected:
		friend class menu::track_editor;
		track_info_list& get_video_tracks(void) { return m_videoTracks; }
		track_info_list& get_audio_tracks(void) { return m_audioTracks; }

		friend class menu::job_editor;
		int& get_edit_index(void) { return m_index; }
		
	public:
		recording(const cRecording *Recording);

		bool scan_tracks(void);
		void freeze(void);

		void set_paths(const path_pair& paths);
		void set_index(int index) { m_index = index; }

		const path_pair& get_paths(void) const { return m_paths; }
		const std::string& get_filename(void) const { return m_fileName; }
		const std::string& get_summary(void) const { return m_summary; }
		const std::string& get_datetime(void) const { return m_datetime; }
		const char* get_name(void) const { return m_name; }
		int get_index(void) const { return m_index; }
		const track_info_list& get_used_video_tracks(void) const;
		const track_info_list& get_used_audio_tracks(void) const;
		int64_t get_video_size(void) const;
		int64_t get_audio_size(void) const;
		int64_t get_size(void) const;

		std::string get_chapters(eChaptersMode ChaptersMode) const;
		std::string get_track_path(const track_info& track) const;
		std::string get_video_path(void) const;
		std::string get_requant_path(void) const;
		std::string get_audio_paths(void) const;
		std::string get_used_cids(void) const;
		std::string get_ignored_cids(void) const;
		std::string get_movie_path(void) const;
		std::string get_menu_background(int Page) const;
		std::string get_buttons_normal(void) const;
		std::string get_buttons_highlight(int Page) const;
		std::string get_menu_mpeg(int Page) const;
		std::string get_graft_point(void) const;

		friend bool operator==(const recording& lhs, const recording& rhs);
		friend bool operator!=(const recording& lhs, const recording& rhs);
		friend bool operator<(const recording& lhs, const recording& rhs);
	};

	inline 
	const track_info_list& recording::get_used_video_tracks(void) const
	{
		return m_videoTracks;
	}

	inline 
	const track_info_list& recording::get_used_audio_tracks(void) const
	{
		return m_usedAudioTracks;
	}

	inline 
	int64_t recording::get_size(void) const 
	{
		return get_video_size() + get_audio_size();
	}

	inline 
	std::string recording::get_track_path(const track_info& track) const
	{
		if (track.type == unknown || !track.used)
			return "";
		return proctools::format("{0}/{1}") % m_paths.temp % track.filename;
	}

	inline
	std::string recording::get_video_path(void) const
	{
		return get_track_path(m_videoTracks[0]);
	}
	
	inline
	std::string recording::get_requant_path(void) const
	{
		return proctools::format("{0}/requant.mpv") % m_paths.temp;
	}

	inline 
	std::string recording::get_movie_path(void) const
	{
		return proctools::format("{0}/movie.mpg") % m_paths.temp;
	}

	inline 
	std::string recording::get_menu_background(int page) const
	{
		return proctools::format("{0}/menu-bg-{1}.png") % m_paths.data % page;
	}

	inline 
	std::string recording::get_buttons_normal(void) const
	{
		return proctools::format("{0}/menu-buttons-ns.png") % m_paths.data;
	}

	inline 
	std::string recording::get_buttons_highlight(int page) const
	{
		return proctools::format("{0}/menu-buttons-h-{1}.png") 
			   % m_paths.data % page;
	}
		
	inline 
	std::string recording::get_menu_mpeg(int page) const
	{
		return proctools::format("{0}/menu-bg-{1}.mpg") % m_paths.data % page;
	}

	inline
	std::string recording::get_graft_point(void) const
	{
		return proctools::format("{0}={1}")
			   % m_fileName.substr(std::string(VideoDirectory).length())
			   % m_fileName;
	}
	typedef std::list<recording> recording_list;

	// --- job -----------------------------------------------------------

	class job
	{
		friend class cBurnMenuBurn;

	private:
		recording_list   m_recordings;
		path_pair        m_paths;
		char             m_title[JOBNAMELEN + 1];
		int              m_skinIndex;
		int              m_diskType;
		int              m_storeMode;
		int              m_chaptersMode;
		int              m_diskSize;
		int              m_customDiskSizeMB;
		chain_vdr       *m_process;
		bool             m_canceled;

	protected:
		friend class menu::job_editor;
		recording_list& get_edit_recordings(void) { return m_recordings; }

		template<typename Fn>
		int64_t accumulate_size(Fn func) const;

	public:
		job(void);
		virtual ~job();

		void freeze(void);

		void reset(void);
		void start(void);
		void stop(void);

		void append_recording(const cRecording* recording);
		void erase_recording(recording_list::iterator rec);
		
		//void Add(const cRecording *Recording);
		//void Del(recording_list::iterator rec);
		void set_paths(const path_pair& paths);
		void set_title(const char* title) { strncpy(m_title, title, JOBNAMELEN); }

		recording_list::const_iterator get_by_filename(const std::string& FileName);
		const recording_list& get_recordings(void) const;

		//recording *First(void) const { return cList<recording>::First(); }
		
		//recording *Next(recording *Recording) const;

		int get_progress(void) const;
		bool get_is_burning(int& progress) const;
		bool get_is_active(void);
		const path_pair& get_paths(void) const { return m_paths; }
		const char* get_title(void) const { return m_title; }
		disk_type::type get_disk_type(void) const;
		eStoreMode get_store_mode(void) const;
		eChaptersMode get_chapters_mode(void) const;
		disk_size::type get_disk_size(void) const;
		int get_disk_size_mb(void) const;
		bool get_is_canceled(void) const { return m_canceled; }
		proctools::process::status_value get_return_status(void) const;
		const skin& get_skin(void) const {return skin_list::get()[m_skinIndex];}
		int64_t get_video_size(void) const;
		int64_t get_audio_size(void) const;
		int64_t get_size(void) const;
		double get_size_mb(void) const;

		std::string get_iso_path(void) const;
		std::string get_log_path(void) const;
		std::string get_menu_background(int Page) const;
		std::string get_buttons_normal(void) const;
		std::string get_buttons_highlight(int Page) const;
		std::string get_menu_mpeg(int Page) const;
		std::string get_volume_id(void) const;
	};

	template<typename Fn>
	int64_t job::accumulate_size(Fn func) const
	{
		return proctools::sum(m_recordings.begin(), m_recordings.end(), 
							  int64_t(0),
							  std::mem_fun_ref( func ));
	}

	inline
	const recording_list& job::get_recordings(void) const
	{
		return m_recordings;
	}

	inline
	int job::get_progress(void) const
	{
		return m_process != 0 ? m_process->get_progress() : 0;
	}

	inline
	bool job::get_is_burning(int& progress) const
	{
		progress = 0;
		return m_process != 0 ? m_process->get_is_burning() : 0;
	}

	inline
	bool job::get_is_active(void)
	{
		return m_process != 0 ? m_process->get_is_active() : 0;
	}

	inline
	disk_type::type job::get_disk_type(void) const
	{
		return static_cast<disk_type::type>(m_diskType);
	}

	inline
	eStoreMode job::get_store_mode(void) const
	{
		return static_cast<eStoreMode>(m_storeMode);
	}

	inline
	eChaptersMode job::get_chapters_mode(void) const
	{
		return static_cast<eChaptersMode>(m_chaptersMode);
	}

	inline
	disk_size::type job::get_disk_size(void) const
	{
		return static_cast<disk_size::type>(m_diskSize);
	}

	inline
	proctools::process::status_value job::get_return_status(void) const
	{
		return m_process != 0
			   ? m_process->return_status() 
			   : proctools::process::none;
	}

	inline 
	int64_t job::get_video_size(void) const
	{
		return accumulate_size(&recording::get_video_size);
	}

	inline 
	int64_t job::get_audio_size(void) const
	{
		return accumulate_size(&recording::get_audio_size);
	}

	inline 
	int64_t job::get_size(void) const
	{
		return accumulate_size(&recording::get_size);
	} 
	
	inline
	double job::get_size_mb(void) const
	{ 
		return static_cast<double>(get_size()) / MEGABYTE(1); 
	}

	/*inline 
	bool job::Burning(int &Progress) const
	{
		return mProcess ? mProcess->Burning(Progress) : false;
	}*/
		
	/*inline recording *job::Next(recording *Recording) const
	{
		return cList<recording>::Next(Recording);
	}*/

	inline 
	std::string job::get_iso_path(void) const
	{
		return proctools::format("{0}/{1}.iso") 
			   % BurnParameters.IsoPath % escape_shellcmd(m_title);
	}

	inline 
	std::string job::get_log_path(void) const
	{
		return proctools::format("{0}/dvd.log") % m_paths.data;
	}

	inline 
	std::string job::get_menu_background(int page) const
	{
		return proctools::format("{0}/menu-bg-{1}.png") % m_paths.data % page;
	}

	inline 
	std::string job::get_buttons_normal(void) const
	{
		return proctools::format("{0}/menu-buttons-ns.png") % m_paths.data;
	}

	inline 
	std::string job::get_buttons_highlight(int page) const
	{
		return proctools::format("{0}/menu-buttons-h-{1}.png") 
			   % m_paths.data % page;
	}

	inline 
	std::string job::get_menu_mpeg(int page) const
	{
		return proctools::format("{0}/menu-bg-{1}.mpg") % m_paths.data % page;
	}

	inline
	std::string job::get_volume_id(void) const
	{
		return std::string( m_title ).substr(0, 32);
	}
	
	typedef std::deque<job*> job_queue;

}

#endif // VDR_BURN_JOBS_H
