/////////////////////////////////////////////////////////////////////////////
// Name:        Pgc.h
// Purpose:     The class to store a PGC
// Author:      Alex Thuering
// Created:	    29.01.2003
// RCS-ID:      $Id: Pgc.h,v 1.12 2012/10/30 19:23:11 ntalex Exp $
// Copyright:   (c) Alex Thuering
// Licence:     GPL
/////////////////////////////////////////////////////////////////////////////

#ifndef PGC_H
#define PGC_H

#include "TextSub.h"
#include "Slideshow.h"
#include "mediatrc.h"
#include <wxSVG/mediadec_ffmpeg.h>
#include <wx/hashset.h>

class wxSvgXmlNode;
class wxSvgXmlDocument;
class DVD;
class Menu;
class Cache;
class PgcArray;

WX_DECLARE_HASH_SET(wxString, wxStringHash, wxStringEqual, StringSet);

/** The cell. It defines a marker point in a title. */
class Cell {
public:
	/** Constructor */
	Cell();
	/** Constructor */
	Cell(long start, bool chapter = true);
	
	/** Returns the start time */
	long GetStart() const { return m_start; }
	/** Returns the start time as string */
	wxString GetStartStr() const;
	/** Sets the start time */
	void SetStart(long start) { m_start = start; }
	/** Sets the start time */
	void SetStart(const wxString& startStr);
	
	/** Returns the end time */
	long GetEnd() const { return m_end; }
	/** Returns the end time as string */
	wxString GetEndStr() const;
	/** Sets the end time */
	void SetEnd(long end) { m_end = end; }
	/** Sets the end time */
	void SetEnd(const wxString& endStr);
	
	/** Returns true if cell is a chapter point */
	bool IsChapter() const { return m_chapter; }
	/** Sets cell as chapter point */
	void SetChapter(bool chapter) { m_chapter = chapter; }
	
	/** Returns true if cell is a program point */
	bool IsProgram() const { return m_program; }
	/** Sets cell as program point */
	void SetProgram(bool program) { m_program = program; }
	
	/** Returns the pause */
	int GetPause() const { return m_pause; }
	/** Sets the pause */
	void SetPause(int pause) { m_pause = pause; }
	
	/** Returns VM commands that will be executed when the cell plays. */
	wxString GetCommands() const { return m_commands; }
	/** Sets the VM commands that will be executed when the cell plays. */
	void SetCommands(const wxString& commands) { m_commands = commands; }
		
	wxSvgXmlNode* GetXML(DVDFileType type);
	bool PutXML(wxSvgXmlNode* node);
	
private:
	long m_start;
	long m_end;
	bool m_chapter;
	bool m_program;
	int m_pause;
	wxString m_commands;
};

class Stream {
public:
	Stream(StreamType type, wxString codecName);
	
	StreamType GetType() { return m_type; }
	void SetType(StreamType type) { m_type = type; }
	
	wxString GetSourceCodecName() { return m_sourceCodecName; }
	void SetSourceCodecName(wxString sourceCodecName) { m_sourceCodecName = sourceCodecName; }
	
	wxSize GetSourceVideoSize() { return m_sourceVideoSize; }
	void SetSourceVideoSize(wxSize sourceVideoSize) { m_sourceVideoSize = sourceVideoSize; }
	
	float GetSourceAspectRatio() { return m_sourceAspectRatio; }
	void SetSourceAspectRatio(float sourceAspectRatio) { m_sourceAspectRatio = sourceAspectRatio; }
	
	float GetSourceFps() { return m_sourceFps; }
	void SetSourceFps(float sourceFps) { m_sourceFps = sourceFps; }
		
	VideoFormat GetSourceVideoFormat();
	AudioFormat GetSourceAudioFormat();
	
	int GetSourceBitrate() { return m_sourceBitrate; }
	void SetSourceBitrate(int sourceBitrate) { m_sourceBitrate = sourceBitrate; }
	
	int GetSourceChannelNumber() { return m_sourceChannelNumber; }
	void SetSourceChannelNumber(int sourceChannelNumber) { m_sourceChannelNumber = sourceChannelNumber; }
	
	int GetSourceSampleRate() { return m_sourceSampleRate; }
	void SetSourceSampleRate(int sourceSampleRate) { m_sourceSampleRate = sourceSampleRate; }
	
	/** @return the stream format string */
	wxString GetSourceFormat();
	
	/** Returns destination audio, video or subtitle format */
	int GetDestinationFormat() { return m_destinationFormat; }
	/** Sets destination audio, video or subtitle format */
	void SetDestinationFormat(int destinationFormat) { m_destinationFormat = destinationFormat; }
	
	/** Returns destination video format */
	VideoFormat GetVideoFormat() { return (VideoFormat) m_destinationFormat; }
	/** Sets destination video format */
	void SetVideoFormat(VideoFormat videoFormat) { m_destinationFormat = videoFormat; }
	
	/** Returns destination audio format */
	AudioFormat GetAudioFormat() { return (AudioFormat) m_destinationFormat; }
	/** Sets destination audio format */
	void SetAudioFormat(AudioFormat audioFormat) { m_destinationFormat = audioFormat; }
	
	/** Returns destination subtitle format */
	SubtitleFormat GetSubtitleFormat() { return (SubtitleFormat) m_destinationFormat; }
	/** Sets destination subtitle format */
	void SetSubtitleFormat(SubtitleFormat subtitleFormat) { m_destinationFormat = subtitleFormat; }
	
	/** Returns destination audio volume (256 = normal) */
	int GetAudioVolume() { return m_audioVolume; }
	/** Sets destination audio volume (256 = normal) */
	void SetAudioVolume(int audioVolume) { m_audioVolume = audioVolume; }
	
	/** Returns destination audio channel number */
	int GetChannelNumber() const {
		return m_channelNumber;
	}
	
	/** Sets destination audio channel number */
	void SetChannelNumber(int channelNumber) {
		m_channelNumber = channelNumber;
	}
	
	/** Returns ts offset */
	long GetTsOffset() { return m_tsOffset; }
	/** Sets ts offset */
	void SetTsOffset(long tsOffset) { m_tsOffset = tsOffset; }
	
private:
	StreamType m_type; // audio/video/subtitle
	wxString m_sourceCodecName; // source codec name
	int m_sourceBitrate; // source bitrate
	int m_sourceChannelNumber; // number of audio channels
	int m_sourceSampleRate; // sample rate of audio
	wxSize m_sourceVideoSize; // frame size of source video
	float m_sourceAspectRatio; // aspect ratio of source video
	float m_sourceFps; // FPS of source video
	int m_destinationFormat; // destination audio, video or subtitle format
	int m_audioVolume; // destination audio volume
	int m_channelNumber; // destination audio channel number
	long m_tsOffset; // input ts offset
};

WX_DEFINE_ARRAY(Stream*, StreamArray);

class Vob {
public:
	Vob();
	Vob(const wxString& filename);
	Vob(Menu* menu);
	Vob(Slideshow* slideshow);
	Vob(const Vob& vob);
	~Vob();
	
	/** Sets name of video file for this vob*/
	bool SetFilename(const wxString& value);
	/** Returns name of video file */
	wxString GetFilename() { return m_filename; }
	/** Returns name of file to display */
	wxString GetFilenameDisplay();
	
	/** Returns true if there are audio streams in input file(s) */
	bool HasAudio();
	/** Returns count of audio streams */
	unsigned int GetAudioStreamCount();
	
    /** Returns array with audio tracks */
	const wxArrayString& GetAudioFilenames() { return m_audioFilenames; }
	/** Adds the given audio file to the vob */
	bool AddAudioFile(wxString filename);
	/** Removes audio file with given index from the vob */
	void RemoveAudioFile(int index);
	
    /** Returns array with subtitle tracks */
    TextSubArray& GetSubtitles() { return m_subtitles; }
	/** Returns count of subtitle streams */
	unsigned int GetSubtitleStreamsCount();
	
    /** Sets file name of tempory vob file */
	void SetTmpFilename(const wxString& value) { m_tmpFilename = value; }
    /** Returns file name of tempory vob file */
	const wxString& GetTmpFilename() { return m_tmpFilename; }
	
    /** Sets chapter list */
	void SetChapters(const wxString& value);
    /** Returns chapter list */
	wxString GetChapters();
	
    /** Sets pause */
	void SetPause(int value) { m_pause = value; }
    /** Returns pause */
	int GetPause() { return m_pause; }
	
	/** Sets start time (sec) */
	void SetStartTime(double value) { m_startTime = value; }
	/** Returns start time (sec) */
	double GetStartTime() { return m_startTime; }
	
	/** Sets recording time (sec) */
	void SetRecordingTime(double value) { m_recordingTime = value; }
	/** Returns recording time (sec) */
	double GetRecordingTime() { return m_recordingTime; }
	
    /** Returns cells */
	vector<Cell*>& GetCells() { return m_cells; }
	
	/** Returns true if aspect ratio must be retained */
	bool GetKeepAspectRatio() { return m_keepAspectRatio; }
	/** Sets if aspect ratio must be retained */
	void SetKeepAspectRatio(bool keepAspectRatio) { m_keepAspectRatio = keepAspectRatio; }
	
	/** Returns pad values: left, right, top, bottom */
	vector<int>& GetPad() { return m_pad; }
	/** Updates pad value to keep aspect ratio*/
	void UpdatePad(AspectRatio aspectRatio);
	/** Calculates pad value to keep aspect ratio*/
	bool CalcPad(int& padx, int& pady, VideoFormat videoFormat, AspectRatio aspectRatio, const vector<int>& crop);
	/** Returns crop values: left, right, top, bottom */
	vector<int>& GetCrop() { return m_crop; }
	
	/** Returns encode interlaced flag */
	bool GetInterlaced() { return m_interlaced; }
	/** Sets encode interlaced flag */
	void SetInterlaced(bool interlaced) { m_interlaced = interlaced; }
	
	/** Returns first field (interlacing) flag */
	FirstField GetFirstField() { return m_firstField; }
	/** Sets first field (interlacing) flag */
	void SetFirstField(FirstField firstField) { m_firstField = firstField; }
	
    /** Sets fadeIn */
	void SetFadeIn(int value) { m_fadeIn = value; }
    /** Returns fadeIn */
	int GetFadeIn() { return m_fadeIn; }
	
    /** Sets fadeOut */
	void SetFadeOut(int value) { m_fadeOut = value; }
    /** Returns fadeOut */
	int GetFadeOut() { return m_fadeOut; }
	
    /** Sets video filters */
	void SetVideoFilters(const wxString& value) { m_videoFilters = value; }
    /** Returns video filters */
	const wxString& GetVideoFilters() { return m_videoFilters; }
    /** Returns all video filters (incl. crop, pad, fade-in and fade-out) */
	wxString GetAllVideoFilters();
	
	void SetMenu(Menu* menu) { m_menu = menu; }
	Menu* GetMenu() { return m_menu; }
	
    void SetSlideshow(Slideshow* slideshow) { m_slideshow = slideshow; }
	Slideshow* GetSlideshow() { return m_slideshow; }
	
	/** Returns duration of video (sec) */
	inline double GetDuration() { return m_duration; }
    /** Returns array with stream parameters */
    StreamArray& GetStreams() { return m_streams; }
    /** Returns video stream parameters */
    Stream* GetVideoStream();
    /** Returns video stream index */
    int GetVideoStreamIndex();
	
    /** Returns true if the source video file must not be remultiplexed/transcoded */
   	inline bool GetDoNotTranscode() { return m_doNotTranscode; }
  	/** Sets if the source video file must not be remultiplexed/transcoded */
   	inline void SetDoNotTranscode(bool doNotTranscode) { m_doNotTranscode = doNotTranscode; }
	
	wxSvgXmlNode* GetXML(DVDFileType type, DVD* dvd);
	bool PutXML(wxSvgXmlNode* node, DVD* dvd, int tsi, int pgci, bool menu);
	
	/**
	 * Returns size in KB
     * @return Size of VOB file in KB
     */
	int GetSize(DVD* dvd);
	
	/**
	 * Returns size after transcoding in KB
     * @return Size of VOB file in KB
     */
	int GetTranscodedSize(DVD* dvd);
	
	/**
	 * Returns size in KB required for generation
	 * @return Size in KB
	 */
	int GetRequiredSize(DVD* dvd, Cache* cache);
	
	static Vob* CreateEmptyVob(VideoFormat videoFormat, AudioFormat audioFormat);
	
private:
	wxString m_filename;
	wxArrayString m_audioFilenames;
    TextSubArray m_subtitles;
	wxString m_tmpFilename;
	
	int m_pause;
	vector<Cell*> m_cells;
	
	Menu* m_menu;
    Slideshow* m_slideshow;
	
	double m_duration;
	double m_startTime;
	double m_recordingTime;
	StreamArray m_streams;
	bool m_doNotTranscode;
	bool m_interlaced;
	FirstField m_firstField;
	bool m_keepAspectRatio;
	vector<int> m_pad;
	vector<int> m_crop;
	int m_fadeIn;
	int m_fadeOut;
	wxString m_videoFilters;
	void Init(Menu* menu = NULL, Slideshow* slideshow = NULL);
	static unsigned int GetFileSize(const wxString& filename);
};

WX_DEFINE_ARRAY(Vob*, VobArray);

class Pgc {
public:
	Pgc() { }
	~Pgc() { WX_CLEAR_ARRAY(m_vobs) }
	
	wxString GetEntriesAsString();
	StringSet& GetEntries() { return m_entries; }
	void SetEntries(const StringSet& entries) { m_entries = entries; }
	void RemoveEntries(const StringSet& entries);
	
	void SetPreCommands(wxString value) { m_pre = value; }
	wxString GetPreCommands() { return m_pre; }
	void SetPostCommands(wxString value) { m_post = value; }
	wxString GetPostCommands() { return m_post; }
	void SetPalette(wxString value) { m_palette = value; }
	wxString GetPalette() { return m_palette; }
	
	VobArray& GetVobs() { return m_vobs; }
	
	Menu* GetMenu();
    Slideshow* GetSlideshow();
    
    /** Returns count of chapters in the title */
    unsigned int GetChapterCount(int lastVobi = -1);
	/** Returns URI of video frame */
	wxString GetVideoFrameUri(int chapter, long position = -1, bool fileNameOnly = false);
	
	wxSvgXmlNode* GetXML(DVDFileType type, DVD* dvd, PgcArray& pgcs, wxString nextTitle);
	bool PutXML(wxSvgXmlNode* node, DVD* dvd, int tsi, int pgci, bool menu);
	
private:
	VobArray m_vobs;
	StringSet m_entries;
	wxString m_pre, m_post, m_palette;
};

WX_DEFINE_ARRAY(Pgc*, PgcArrayBase);

#endif // PGC_H
