/*****************************************************************************
 *
 *  encoder.h -- Audio/Video encoder.
 *
 *  Copyright (C) 2010 Starbuck <starbuck@labdv.com>
 *  All rights reserved.
 *
 *  This file is part of the Encoder module of the DVDx 4 application.
 *
 *  GNU Lesser General Public License Usage
 *  This file may be used under the terms of the GNU Lesser General
 *  Public License version 2.1 as published by the Free Software
 *  Foundation and appearing in the file LICENSE.LGPL included in the
 *  packaging of this file.  Please review the following information to
 *  ensure the GNU Lesser General Public License version 2.1 requirements
 *  will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 *
 *  GNU General Public License Usage
 *  Alternatively, this file may be used under the terms of the GNU
 *  General Public License version 3.0 as published by the Free Software
 *  Foundation and appearing in the file LICENSE.GPL included in the
 *  packaging of this file.  Please review the following information to
 *  ensure the GNU General Public License version 3.0 requirements will be
 *  met: http://www.gnu.org/copyleft/gpl.html.
 *
 *****************************************************************************/

#ifndef ENCODER_H
#define ENCODER_H

// should be for libdvd.lib
#ifdef WIN32
#include "config.h"
#include "dvdnav/dvdnav.h"
#endif

#include "../main/macrosdev.h"
#include "../video/video_struct.h"
#include "../video/video_constants.h"
#include "interfacemencoder.h"
#include "interfaceffmpeg.h"
#include <QSettings>
#include <QString>
#include <QStringList>
#include <QTextEdit>
#include <QObject>

class Encoder : public QObject
{
	Q_OBJECT

public:
	struct Latency
	{
		int start;
		int finished;
		int kill;

		Latency()
		{
			start = DefaultLatencyStart;
			finished = DefaultLatencyFinished;
			kill = DefaultLatencyKill;
		}
	};

public:
	Encoder(QTextEdit *stdIn, QTextEdit *stdOut, QTextEdit *stdErr,
		QTextEdit *defLog, const int verbose);
	//~Encoder();

	bool activateInterface(const int, const QString &);
	void initialize();
	void setLatency(const int, const int, const int, const int);
	void writeSettings();  // must be called before deleting Encoder instance

	bool isReady();
	bool isInterfaceReady(const int);
	bool isSupportedMuxer(const int, const QString &);
	bool isSupportedVideo(const int, const QString &, const QString &);
	bool isSupportedAudio(const int, const QString &, const QString &);
	bool isSupportedSubtitle(const int, const QString &, const QString &);

	void readInterfaceLatency(const int, int *, int *, int *);

	void recommendedMuxerCodecs( const QString &, QString *, QString *, QString * );
	void recommendedMuxerVideoCodecs( const QString &,  const QString &, QString *, QString * );

	QStringList getMuxerSynonyms(const QString &);
	QStringList getVideoSynonyms(const QString &);
	QStringList getAudioSynonyms(const QString &);
	QStringList getSubtitleSynonyms(const QString &);

	int selectConvenientEngine();
	
	void cliChooseCmdEncode(int *, QString *, QStringList *, const QString &, int=0, int=0, int=0, bool=false);

	void cliCorrectAspectRatio(const int, QString *, QStringList *, const QString &, const QString &, double);
	void cliExtractAudioFromAvi(const int, QString *, QStringList *, const QString &, const QString &);

	bool cliCmdSplitFile(int *engine, QString *cmd, QStringList *args, QString *error,
		const QString &inputFileName, const qint64 inputFileSize, 
		const int partNumber, const qint64 partSize);
		
	void cliCmdTargetVcd(const int, QString *, QStringList *,
		const QString &, const QString &, const QString &);
	void cliCmdTargetSvcd(const int, QString *, QStringList *,
		const QString &, const QString &, const QString &);
	void cliCmdTargetXvid(const int, QString *, QStringList *,
		encoder_settings_t::input_t *);

	bool isCmdEncodeValid(const int, QString *, QStringList *, QString *, QString *, QString *, QString *, const int);

	QStringList profileCommandLine(const int, const encoder_profile_t *);
	QString profileDescription(const encoder_profile_t *);

	bool parseCommandCheck(const int,  QByteArray *, QByteArray *);
	
	static bool parseEngineProgress(int, QString *, QString *, int *, double *, int *, int *, double *, int *);

	bool audioAndVideoSelected();

	QString muxerName(const QString &);
	QString videoName(const QString &);
	QString audioName(const QString &);
	QString subtitleName(const QString &);

	QString muxerShortName(const QString &);
	QString videoShortName(const QString &);
	QString audioShortName(const QString &);
	QString subtitleShortName(const QString &);

	QString muxerLongName(const QString &);

	void setBinPath(const int, const QString &);

	void setInputPath(const QString &, const int);
	void setEncoderSelection(const QList<int> &, const QList<int> &, const QList<int> &);
	void updateInputTracks(video_t, bool, audio_t, bool, subtitle_t, bool);
	void setOutputMuxer(const QString &);
	QString setOutputFile(const QString &, const QString &);
	void setVerbosity(const int);
	void setSaveSettingsOnClose(const bool);

	// Common interface settings (all interfaces are updated)
	void setOutputLength(const int frames);
	void setOutputVideoCodec(const QString &);
	void setOutputAudioCodec(const QString &);
	void setOutputSubtitleCodec(const QString &);
	void setOutputAudioVolume(const int);

	bool hasErrorMessage();
	QString errorMessage();

	QString getBinPath(const int);
	inline QString getInputFilePath() const { return input->source.path; };
	inline encoder_settings_t::input_t *getInputSettings() const { return input; };
	inline encoder_target_t getOutputFile() const { return *outputFile; };
	int getEstimatedOutputFileSize(const int, const int);
	QString getOutputFilePath();
	QString getStatsFilePath();
	inline QString getOutputMuxer() const { return outputFile->muxer; };
	QString getOutputStandard();
	encoder_settings_t *getSettings(const int);
	encoder_engine_capability_t *getCapability(const int);
	encoder_engine_status_t *getStatus(const int);
	QString engineVersion(const int engine) { return getStatus(engine)->version; };

	int getAudioInputCount();
	int getSubtitleInputCount();

	// Common interface output settings are arbitrary taken from FFmpeg interface 
	inline QString getOutputVideoCodec() const { return ffmpegSettings->output.video.codec; };
	inline QString getOutputAudioCodec() const { return ffmpegSettings->output.audio.codec; };
	inline QString getOutputSubtitleCodec() const { return ffmpegSettings->output.subtitle.codec; };

	QStringList supportedMuxers();

	bool muxerSupport(const int, const QString &);
	bool muxerSupportVideo(const QString &, const QString &);
	bool muxerSupportAudio(const QString &, const QString &);
	bool muxerSupportSubtitle(const QString &, const QString &);
	bool supportMultiAudio(const int);
	bool supportMultiSubtitle(const int);

	QString getPreferredVideo(const QString &);
	QString getPreferredAudio(const QString &, const QString &);
	QString getPreferredSubtitle(const QString &, const QString &);

	static QString name(const int);
	static double recommendsFps(const encoder_video_settings_t*, const video_t *source);
	static QSize recommendsSize(const encoder_video_settings_t*, const video_t *source);
	static QString recommendsFileExtension(const QString &, const bool =false);

protected:
	int latencyStart(const int);
	int latencyFinished(const int);
	int latencyKill(const int);

	void reset(const int);
	void readSettings();

	void setVideoNames();
	void setAudioNames();
	void setSubtitleNames();
	void setMuxerNames();

	void setVideoShortNames();
	void setAudioShortNames();
	void setSubtitleShortNames();
	void setMuxerShortNames();

	void setMuxerLongNames();

	void setVideoSynonyms();
	void setAudioSynonyms();
	void setSubtitleSynonyms();
	void setMuxerSynonyms();

	void setPreferredVideo();
	void setPreferredAudio();
	void setPreferredSubtitle();
	
	void printLog(const QString &, const int=VERBOSITY_NORMAL);
	void printIn(const QString &, const int=VERBOSITY_NORMAL);
	void printOut(const QString &, const int=VERBOSITY_NORMAL);
	void printErr(const QString &, const int=VERBOSITY_NORMAL);

	void clearLog();
	void clearIn();
	void clearOut();
	void clearErr();

protected:
	QString appOrganization;	// for settings
	QString appApplication;
	
	int mainAudio;
	int mainSubtitle;
	encoder_settings_t::input_t *input;
	encoder_target_t *outputFile;

	InterfaceFFmpeg *ffmpeg;
	Latency ffmpegLatency;
	encoder_settings_t *ffmpegSettings;
	encoder_engine_capability_t *ffmpegCapability;
	encoder_engine_status_t *ffmpegStatus;
	QMap<QString, QString> ffmpegMuxers;
	QMap<QString, QString> ffmpegVideos;
	QMap<QString, QString> ffmpegAudios;
	QMap<QString, QString> ffmpegSubtitles;

	InterfaceMEncoder *mencoder;
	Latency mencoderLatency;
	encoder_settings_t *mencoderSettings;
	encoder_engine_capability_t *mencoderCapability;
	encoder_engine_status_t *mencoderStatus;
	QMap<QString, QString> mencoderMuxers;
	QMap<QString, QString> mencoderVideos;
	QMap<QString, QString> mencoderAudios;
	QMap<QString, QString> mencoderSubtitles;
	QMap<QString, QStringList> mencoderLibVideos;
	QMap<QString, QStringList> mencoderLibAudios;
	QMap<QString, QStringList> mencoderLibSubtitles;
	QMap<QString, QStringList> mencoderLibMuxers;

	QMap<QString, QString> muxers;
	QMap<QString, QString> videos;
	QMap<QString, QString> audios;
	QMap<QString, QString> subtitles;

	QMap<QString, QString> muxerNames;
	QMap<QString, QString> videoNames;
	QMap<QString, QString> audioNames;
	QMap<QString, QString> subtitleNames;

	QMap<QString, QString> muxerShortNames;
	QMap<QString, QString> videoShortNames;
	QMap<QString, QString> audioShortNames;
	QMap<QString, QString> subtitleShortNames;

	QMap<QString, QString> muxerLongNames;

	QMap<QString, QStringList> muxerSynonyms;
	QMap<QString, QStringList> videoSynonyms;
	QMap<QString, QStringList> audioSynonyms;
	QMap<QString, QStringList> subtitleSynonyms;

	// Recommended codecs
	QMap<QString, QString> preferredVideo;						// muxer -> video
	QMap<QString, QMap<QString, QString> > preferredAudio;		// muxer -> video -> audio
	QMap<QString, QMap<QString, QString> > preferredSubtitle;	// muxer -> video -> subtitle

	bool saveSettingsOnClose;	// for the Clear All Settings feature

	int verbosity;
	QTextEdit *log;				// log application errors/warnings
	QTextEdit *standardInput;	// process stdIn
	QTextEdit *standardOutput;	// process stdOut
	QTextEdit *standardError;	// process stdErr

	// Process latency
	enum Constants { DefaultLatencyStart = 3000, DefaultLatencyFinished = 3000, DefaultLatencyKill= 5000 };
};

#endif
