/*****************************************************************************
 *
 *  encoderwidget.h -- Container for encoder controls.
 *
 *  Copyright (C) 2010 Starbuck <starbuck@labdv.com>
 *  All rights reserved.
 *
 *  This file is part of the Gui4 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 ENCODERWIDGET_H
#define ENCODERWIDGET_H

#include "../video/video_struct.h"
#include "../encoder/encoder.h"
#include "../encoder/configurator.h"
#include "activecombobox.h"
#include "consoledialog.h"
#include "jobmanagerdialog.h"
#include "../job/jobmanager.h"
#include "encoderpreviewdialog.h"
#include "playerdialog.h"

#include <QWidget>
#include <QProcess>
#include <QLabel>
#include <QMenu>
#include <QPushButton>
#include <QCheckBox>
#include <QSpinBox>
#include <QComboBox>
#include <QRadioButton>
#include <QGroupBox>
#include <QGridLayout>
#include <QSignalMapper>
#include <QMultiMap>

class EncoderWidget : public QWidget
{
	Q_OBJECT

public:
	struct Preferences
	{
		bool test_mode;
		int test_frames;
		int test_chapter;
		int test_position;
		int volume_correction;
		int validation_frames;
		int validation_size;

		int latency_start;
		int latency_finished;
		int latency_kill;

		bool force_output_name;
		QString output_name;

		Preferences() { reset(); }

		void reset()
		{
			test_mode = false;
			test_frames = 1000;		// MEncoder only (-frames)
			test_chapter = 4;		// MEncoder only (-chapter)
			test_position = 12;		// FFmpeg only (-ss) seek in seconds from start

			volume_correction = 0;
			
			validation_frames = 50;		// MEncoder only (-frames)
			validation_size = 1000000;	// FFmpeg only (-fs) size in Bytes

			latency_start = 3000;
			latency_finished = 3000;
			latency_kill = 5000;

			force_output_name = false;
			output_name = "output";
		}
	};

	struct CodecOptions
	{
		QString codec;
		QString name;
		QMultiMap<QString, QString> options;
	};

	EncoderWidget(QWidget *, JobManager *, const QString &, const QString &, 
		QTextEdit *, QTextEdit *, QTextEdit *, QTextEdit *, const int,
		Preferences *prefs=0, QWidget *parent=0);
	~EncoderWidget();

	void setPlayerPreferences(QWidget *, const QString &, const QString &, const QString &, 
		QTextEdit *, QTextEdit *, QTextEdit *, QTextEdit *, const int,
		PlayerWidget::Preferences *);

	void initialize();
	void getStatus(bool *, bool *);

	QString codec();
	QString audio();
	void enableControls(bool);	// enable encoding (a movie is loaded, ready to encode)
	void setBinPath(const int, const QString &);
	void setPreferences(Preferences *);
	void resetPreferences();

	inline encoder_engine_status_t readFFmpegStatus() const { return (*encoder->getStatus(Video::Encoder::FFmpeg)); };
	inline encoder_engine_status_t readMEncoderStatus() const { return (*encoder->getStatus(Video::Encoder::MEncoder)); };
	inline encoder_engine_capability_t readFFmpegCapability() const { return (*encoder->getCapability(Video::Encoder::FFmpeg)); };
	inline encoder_engine_capability_t readMEncoderCapability() const { return (*encoder->getCapability(Video::Encoder::MEncoder)); };

	inline encoder_settings_t::input_t readInputSettings() const { return *encoder->getInputSettings(); };
	inline encoder_settings_t readSettings(const int engine) const { return *encoder->getSettings(engine); };

	inline bool audioAndVideoSelected() const { return encoder->audioAndVideoSelected(); };

	inline bool isIdle() { return !isEncoding; };
	inline bool isReady(const int engine) { return encoder->isInterfaceReady(engine); };
	inline bool isReady() { return isFFmpegReady() && isMEncoderReady(); };

	inline int readAudioCorrection() const { return encoder->getSettings(Video::Encoder::MEncoder)->output.audio.volume; };
	
	void setNoConsoleButton(bool);
	void setVerbosity(const int);
	void setSaveSettingsOnClose(const bool);
	
	inline bool isFFmpegReady() const { return encoder->isInterfaceReady(Video::Encoder::FFmpeg); };
	inline bool isMEncoderReady() const { return encoder->isInterfaceReady(Video::Encoder::MEncoder); };
	inline bool isRunninTestMode() const { return preferences.test_mode; };

	inline QString enginePath(const int engine) const { return encoder->getBinPath(engine); };
	inline QString engineVersion(const int engine) const { return encoder->engineVersion(engine); };

	void setInput(const QString &path, const int media);
	void setOutputFile(const QString &folder, const QString &name);

	void updateInputTracks(video_t, bool, audio_t, bool, subtitle_t, bool, bool=true);

signals:
	void encodingComplete(Process *);
	void optionsChanged();

protected:
	bool caseInsensitiveLessThan(const QString &, const QString &);
	QString newFileNameInFolder(const QString &, const QString &);

	bool runEncoding();
	bool runFinalizing(const QString &, const QString &, double, int, bool, QLayout *);
	bool runFinalizingAudio(const QString &, const QString &, int, bool, QLayout *);

	void resizeEvent(QResizeEvent *ev);
	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();

	void populateOptions(QString, QString, QString, QString);
	void populateVideoOptions(QString, QString);
	void populateAudioOptions(QString, QString);
	void populateSubtitleOptions(QString, QString);

	void updateIdleLabel(const QString &, const QString &, const QString &);

	void readSettings();
	void writeShowCodecsSettings();

protected slots:
	void readJobProcessStdOut(Process *);
	void readJobProcessStdErr(Process *);
	void finishJobProcess(Process *, int, QProcess::ExitStatus);
	void finalizeEncoding(Process *);
	void startProcessConsole(Task *);

	void abortedByUser();

	void selectMuxer();
	void selectVideo();
	void selectAudio();
	void selectSubtitle();

	void switchState();
	void codecBarFlipFlop();
	void configure();
	void loadProfileSettings();
	void switchTestMode(int);
	void adjustAudioCorrection(int);

protected:
	Encoder *encoder;			// one unique Encoder with all Interfaces
	Configurator *configurator;

	QString mencoderBinPath;	// path to mencoder binary
	QString ffmpegBinPath;

	bool showConsoleButton;
	int verbosity;
	bool saveSettingsOnClose;
	QString previousSessionMuxer;

	QTextEdit *log;				// log application errors/warnings
	QTextEdit *standardInput;	// process stdIn
	QTextEdit *standardOutput;	// process stdOut
	QTextEdit *standardError;	// process stdErr
	
	QFrame *backFrame;			// a frame for the encoder controls
	QPushButton *controllerButton;	// start/stop button
	QPushButton *configureButton;	// configure rez, fps, bitrate etc.
	QPushButton *codecButton;		// show/hide codec selections
	QSpinBox *volumeSpin;			// adjust volume gain
	QVBoxLayout *controls;
	QGroupBox *targetGroup;
	QGroupBox *settingsGroup;
	QLabel *settingsLabel;
	QWidget *codecSelectionWidget;
	ActiveComboBox *muxerSelectCombo;
	ActiveComboBox *videoSelectCombo;
	ActiveComboBox *audioSelectCombo;
	ActiveComboBox *subtitleSelectCombo;
	QLabel *targetFolderLabel;
	QLineEdit *targetFolderLine;
	QLabel *targetNameLabel;
	QLineEdit *targetNameLine;
	QCheckBox *testCheckBox;		// set test mode 

	JobManager *jobManager;

	JobManager *previewJobManager;
	JobManagerWidget *previewJobManagerWidget;
	EncoderPreviewDialog *encoderPreviewDialog;

	bool controllerButtonIsActivable;
	bool isEncoding;
	bool isEncodingStartable;
	bool isAbortedByUser;

	Preferences preferences;
	PlayerDialog::Preferences playerPreferences;
};

#endif
