/*****************************************************************************
 *
 *  interfacemediainfo.cpp -- Interface to MediaInfo CLI.
 *
 *  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.
 *
 *****************************************************************************/

#define	RX_PARSE_MEDIAINFO_SIGNATURE	"(MediaInfo Command line).*(MediaInfoLib).*(v.*)"
#define	RX_PARSE_MEDIAINFO_WIDTH		"\\n(Complete name.*:)"
#define	RX_PARSE_MEDIAINFO_SIZE			"Stream size\\s+:\\s+([0-9\\.]+)\\sMiB"

#define	RX_CATCH_MEDIAINFO_GENERAL		"(Complete name.*).{0,1}\\n.{0,1}\\n"
#define	RX_CATCH_MEDIAINFO_VIDEO		"\\nVideo.{0,1}\\n(.*).{0,1}\\n.{0,1}\\n"
#define	RX_CATCH_MEDIAINFO_AUDIO		"\\nAudio\\s*(#\\d+){0,1}.{0,1}\\n(.*).{0,1}\\n.{0,1}\\n"
#define	RX_CATCH_MEDIAINFO_TEXT			"\\nText\\s*(#\\d+){0,1}.{0,1}\\n(.*).{0,1}\\n.{0,1}\\n"

#include "interfacemediainfo.h"
#include "macros.h"
#include <QProcess>
#include <QRegExp>
#include <QDebug>

InterfaceMediaInfo::InterfaceMediaInfo()
{
}

void InterfaceMediaInfo::initialize(const QString &p, 
		interfacemediainfo_data_t *d, utility_status_t *s)
{
	exec = p;
	data = d;
	status = s;
}

void InterfaceMediaInfo::setBinPath(const QString &binPath)
{
	exec = binPath;
}

void InterfaceMediaInfo::cliCmdGetInfo(const QString &path, QString *cmd, QStringList *args)
{
	cmd->clear();
	args->clear();

	// Command
	*cmd = exec.toLatin1();

	// Video source to read
	*args << path; 

	qDebug() << "InterfaceMediaInfo::cliCmdGetInfo() returns command:" << *cmd << "with options" << *args;	

}

void InterfaceMediaInfo::cliCmdGetStatus(QString *cmd, QStringList *args)
{
	cmd->clear();
	args->clear();

	// Command
	*cmd = exec.toLatin1();

	*args << "--version";

	qDebug() << "InterfaceMediaInfo::cliCmdGetStatus() returns command:" << *cmd << "with options" << *args;
}

void InterfaceMediaInfo::parseStatus()
{
	qDebug() << "InterfaceMediaInfo::parseStatus() starts parsing status raw data";

	if (status->state != Video::Status::RawStatus) 
	{
		status->state = Video::Status::ParseFail;
		return;
	}

	// Parse stardard out

	QRegExp rx(RX_PARSE_MEDIAINFO_SIGNATURE);
	rx.setMinimal(false);
	rx.indexIn(status->cout);
	if (rx.numCaptures() != 3 || rx.cap(1).length() == 0 || rx.cap(3).length() == 0)
	{
		qDebug("InterfaceMediaInfo::parseStatus() - Failed to parse MediaInfo standard output (parsing signature)");
		status->state = Video::Status::ParseFail;
		return;
	}
	status->utility = rx.cap(1);
	status->version = rx.cap(3).trimmed();

	status->state = Video::Status::EngineOk;
}

void InterfaceMediaInfo::parseData(interfacemediainfo_data_t *data)
{
	qDebug() << "InterfaceMediaInfo::parseData() starts parsing data";

	// Parse stardard out (only what we need to complete title/movie info

	int pos;
	QStringList infos;

	QString generalCatch, videoCatch;
	QStringList audioCatch, audioId;
	QStringList textCatch, textId;

	QRegExp rx(RX_PARSE_MEDIAINFO_WIDTH);
	rx.setMinimal(true);
	rx.indexIn(data->text);
	if ( rx.numCaptures() != 1 || rx.cap(1).length() == 0 )
	{
		qDebug("InterfaceMediaInfo::parseData() - Failed to parse MediaInfo standard output (catching fixed width)");
		status->state = Video::Status::ParseFail;
		return;
	}
	int fixedWidth =  rx.cap(1).length() -1;

	qDebug() << rx.capturedTexts() << fixedWidth;

	// Explode all files (General...)
	QStringList files = data->text.split("General");
	files.removeFirst(); // useless ""
	
	qDebug() << "InterfaceMediaInfo::parseData() catch files:" << files.count();

	// Retain the longuest file as the main file
	int main(0);
	double largestSize(0);
	for (int i = 0; i < files.count(); i++)
	{
		rx.setPattern(RX_CATCH_MEDIAINFO_VIDEO);
		rx.setMinimal(true);
		rx.indexIn(files[i]);
		if ( rx.numCaptures() == 1 && rx.cap(1).length() > 0 )
		{
			QRegExp rx2(RX_PARSE_MEDIAINFO_SIZE);
			rx2.setMinimal(true);
			rx2.indexIn(rx.cap(1));
			if ( rx2.numCaptures() != 1 || rx2.cap(1).length() > 0 )
			{
				qDebug() << "InterfaceMediaInfo::parseData() catch stream size:" << rx2.cap(1);
				
				double size = rx2.cap(1).toDouble();
				if (size > largestSize)
				{
					largestSize = size;
					main = i;
				}
			}
		}
	}

	QString mainFile = files[main];
	qDebug() << "InterfaceMediaInfo::parseData() main file:" << mainFile;
	
	rx.setPattern(RX_CATCH_MEDIAINFO_GENERAL);
	rx.setMinimal(true);
	rx.indexIn(mainFile);
	if ( rx.numCaptures() == 1 && rx.cap(1).length() > 0 )
	{
		generalCatch = rx.cap(1);
	}
	//qDebug() << "InterfaceMediaInfo::parseData() general catch:" << generalCatch;

	rx.setPattern(RX_CATCH_MEDIAINFO_VIDEO);
	rx.setMinimal(true);
	rx.indexIn(mainFile);
	if ( rx.numCaptures() == 1 && rx.cap(1).length() > 0 )
	{
		videoCatch = rx.cap(1);
	}
	//qDebug() << "InterfaceMediaInfo::parseData() video catch:" << videoCatch;

	rx.setPattern(RX_CATCH_MEDIAINFO_AUDIO);
	rx.setMinimal(true);
	pos = 0;
	while ((pos = rx.indexIn(mainFile, pos)) != -1) 
	{
		audioId << rx.cap(1);
		audioCatch << rx.cap(2);

		pos += rx.matchedLength() - 1;  // -1 for the \n before Audio
	}
	//qDebug() << "InterfaceMediaInfo::parseData() audio catch:" << audioId << audioCatch;

	rx.setPattern(RX_CATCH_MEDIAINFO_TEXT);
	rx.setMinimal(true);
	pos = 0;
	while ((pos = rx.indexIn(mainFile, pos)) != -1) 
	{
		textId << rx.cap(1);
		textCatch << rx.cap(2);

		pos += rx.matchedLength() - 1;  // -1 for the \n before Text
	}
	//qDebug() << "InterfaceMediaInfo::parseData() text catch:" << textId << textCatch;

	// Parse general info
	infos = generalCatch.split( "\n" );

	for (int i = 0; i < infos.count(); i++) 
	{
		QString field = infos[i].left(fixedWidth);
		field = field.trimmed();

		QString value = infos[i].right(infos[i].length() - fixedWidth - 1);;
		value = value.trimmed();

		if ( !field.isEmpty() ) data->general.insert( field, value);
	}

	// Parse video info
	infos = videoCatch.split( "\n" );

	for (int i = 0; i < infos.count(); i++) 
	{
		QString field = infos[i].left(fixedWidth);
		field = field.trimmed();

		QString value = infos[i].right(infos[i].length() - fixedWidth - 1);;
		value = value.trimmed();

		if ( !field.isEmpty() ) data->video.insert( field, value);
	}

	// Parse audio info
	while ( !audioCatch.isEmpty() )
	{
		QMap<QString, QString> trackInfo;

		infos = audioCatch.takeFirst().split( "\n" );

		for (int i = 0; i < infos.count(); i++) 
		{
			QString field = infos[i].left(fixedWidth);
			field = field.trimmed();

			QString value = infos[i].right(infos[i].length() - fixedWidth - 1);;
			value = value.trimmed();

			if ( !field.isEmpty() ) trackInfo.insert( field, value);
		}
			
		if ( !trackInfo.isEmpty() ) data->audio.append(trackInfo);
	}

	// Parse text info
	while ( !textCatch.isEmpty() )
	{
		QMap<QString, QString> trackInfo;

		infos = textCatch.takeFirst().split( "\n" );

		for (int i = 0; i < infos.count(); i++) 
		{
			QString field = infos[i].left(fixedWidth);
			field = field.trimmed();

			QString value = infos[i].right(infos[i].length() - fixedWidth - 1);;
			value = value.trimmed();

			if ( !field.isEmpty() ) trackInfo.insert( field, value);
		}
			
		if ( !trackInfo.isEmpty() ) data->subtitle.append(trackInfo);
	}
}
