/****************************************************************************
** QMPlayerWidget - class
**
** Created: Fri Dec 10 12:09:08 2004
**      by: Varol Okan using kate editor
**
** This class implements the MPLayerWidget
** MediaInterface to this class for integration in QDVDAUthor is MPlayerWidget
** 
****************************************************************************/

#include <stdlib.h>

#include <qstringlist.h>
#include <qfileinfo.h>
#include <qprocess.h>
#include <qwidget.h>
//#include <qregexp.h>
#include <qstring.h>
#include <qfile.h>
#include <qdir.h>
#include <qdom.h>

#include "xml_mplayer.h"
#include "qplayer_global.h"
#include "qmplayerwidget.h"

QMPlayerWidget::QMPlayerWidget(QWidget *pParent, const char *pName, WFlags iFlags)
	: QWidget (pParent, pName, iFlags)
{
	m_iExitError = -1;
	m_iSeekValue =  5;					
	m_fLength    =  0.0;
	m_qsScreenshotName = QString (MPLAYER_TEMP_FILE);

	m_bInPauseMode = false;
	m_pMasterProcess = new QProcess;

	m_rxParseElapsedTime = QRegExp ("V:(.*[0-9]) ");
	m_rxParseElapsedTime.setMinimal(true);
	m_rxParseLength = QRegExp ("ID_LENGTH=([0-9]*)");
	// Setting some defaults
	m_listPluginOptions.append (QString("x11"));
	m_listPluginOptions.append (QString(""));
	m_listPluginOptions.append (QString("alsa"));
	m_listPluginOptions.append (QString(""));

	QObject::connect (m_pMasterProcess, SIGNAL(readyReadStdout()), this, SLOT (slotReadStdout     ()));
	QObject::connect (m_pMasterProcess, SIGNAL(readyReadStderr()), this, SLOT (slotReadStderr     ()));
	QObject::connect (m_pMasterProcess, SIGNAL(processExited  ()), this, SLOT (slotProcessExited  ()));
	QObject::connect (m_pMasterProcess, SIGNAL(wroteToStdin   ()), this, SLOT (slotWroteToStdin   ()));
	QObject::connect (m_pMasterProcess, SIGNAL(launchFinished ()), this, SLOT (slotLaunchFinished ()));

	// And finally load the initFile
	loadInitFile();
}

QMPlayerWidget::~QMPlayerWidget()
{
	if (m_pMasterProcess)
		delete m_pMasterProcess;
}

bool QMPlayerWidget::start(QStringList *pEnvironment)
{
	m_bInPauseMode = false;
	if (m_pMasterProcess->isRunning())
		return false;
	QStringList listCommand;
	m_pMasterProcess->clearArguments();
	listCommand.append(QString("mplayer")); 
	listCommand.append(QString("-zoom"));	// Automatically adjust to window size
	listCommand.append(QString("-noautosub"));
	listCommand.append(QString("-cache"));
	listCommand.append(QString("1024"));
	listCommand.append(QString("-double"));
//	listCommand.append(QString("-quiet"));
	listCommand.append(QString("-noquiet"));
	listCommand.append(QString("-ontop"));

	listCommand.append(QString("-wid"));
	listCommand.append(QString("%1").arg(winId()));
	listCommand.append(QString("-slave"));
	if (!m_listPluginOptions[QMPlayerWidget::AudioPlugin].isEmpty())	{
		listCommand.append(QString("-ao"));
		listCommand.append(QString("%1%2").arg(m_listPluginOptions[QMPlayerWidget::AudioPlugin]).arg(m_listPluginOptions[QMPlayerWidget::AudioPluginOptions]));
	}
	listCommand.append(QString("-vo"));
	if (m_listPluginOptions[QMPlayerWidget::VideoPlugin].isEmpty())	
		listCommand.append(QString("x11"));
	else
		listCommand.append(QString("%1%1").arg(m_listPluginOptions[QMPlayerWidget::VideoPlugin]).arg(m_listPluginOptions[QMPlayerWidget::VideoPluginOptions]));

	listCommand.append(QString("-xy"));	// Scales it by keeping aspect ratio
	listCommand.append(QString("%1").arg(width()));

	listCommand.append(QString("-identify"));
	listCommand.append(QString("-framedrop"));
	listCommand.append(QString("--"));
	listCommand.append(QString("%1").arg(m_qsFileName));

	// -ss 01:10:00 seeks to 1 hour 10 min
	m_fLength = 0.0;

	m_pMasterProcess->setArguments (listCommand);
	emit (signalMPlayerStarted());
	return m_pMasterProcess->start(pEnvironment);
}

void QMPlayerWidget::loadInitFile ()
{
	QFileInfo fileInfo;
	QString qsPlayerIniFile;
	qsPlayerIniFile = QDir::homeDirPath();
	qsPlayerIniFile.append(MPLAYER_INIT_FILE);

	// Assign the file
	QFile iniFile(qsPlayerIniFile);
	if (!iniFile.open(IO_ReadWrite))
		return;
	// Try to get the right xml contents ...
	QDomDocument xmlDoc( XML_DOCTYPE_MPLAYER );
	if (!xmlDoc.setContent (&iniFile))	{
		// Error handling ...
		iniFile.close();
		printf ( (const char *) QObject::tr ("MPlayer xml init file <%1> seems to be defective. Re-setting values.\n").arg(qsPlayerIniFile));
 		saveInitFile();
		return;
	}

	// Here is the main loop to extract the info ...
	QDomElement searchXMLTree;
	QDomElement docElem = xmlDoc.documentElement();
	QString  domText    = docElem.tagName();
	QDomNode xmlNode    = docElem.firstChild();
	QString qsVersion   = docElem.attributeNode(MPLAYER_VERSION).value();

	if (domText == MPLAYER_INI)	{
		// First we take care of the QDVDAuthor variables ...
		while( !xmlNode.isNull() ) {
			searchXMLTree = xmlNode.toElement();
			domText = searchXMLTree.text();
			if (MPLAYER_VIDEO_PLUGIN  == searchXMLTree.tagName () )	{
				 m_listPluginOptions[QMPlayerWidget::VideoPluginOptions] = searchXMLTree.attributeNode(MPLAYER_ATTRIB_PLUGIN_OPTIONS).value();
				 m_listPluginOptions[QMPlayerWidget::VideoPlugin] = searchXMLTree.text();
			}
			else if (MPLAYER_AUDIO_PLUGIN  == searchXMLTree.tagName () )	{
				 m_listPluginOptions[QMPlayerWidget::AudioPluginOptions] = searchXMLTree.attributeNode(MPLAYER_ATTRIB_PLUGIN_OPTIONS).value();
				 m_listPluginOptions[QMPlayerWidget::AudioPlugin] = searchXMLTree.text();
			}
			else
				printf ("Warning: MPlayer::loadHistory -=> wrong XML Node <%s>\nContinuing ...\n",
						(const char *)searchXMLTree.tagName());
			// Go to the next node ...
			xmlNode = xmlNode.nextSibling();
		}
	}
	iniFile.close();
}

void QMPlayerWidget::saveInitFile ()
{
	QFileInfo fileInfo;
	QString qsPlayerIniFile;
	qsPlayerIniFile = QDir::homeDirPath();
	qsPlayerIniFile.append(MPLAYER_INIT_FILE);

	// First we create the document, ...
	QDomText domText;
	QDomElement elem, rootElem;
	QDomDocument xmlDoc( XML_DOCTYPE_MPLAYER );
	rootElem = xmlDoc.createElement  ( MPLAYER_INI );
	rootElem.setAttribute( MPLAYER_VERSION, "0.0.9" );

	elem = xmlDoc.createElement  ( MPLAYER_VIDEO_PLUGIN );
	domText = xmlDoc.createTextNode ( m_listPluginOptions[QMPlayerWidget::VideoPlugin] );
	elem.setAttribute( MPLAYER_ATTRIB_PLUGIN_OPTIONS, m_listPluginOptions[QMPlayerWidget::VideoPluginOptions] );
	elem.appendChild ( domText );
	rootElem.appendChild( elem );

	elem = xmlDoc.createElement  ( MPLAYER_AUDIO_PLUGIN );
	domText = xmlDoc.createTextNode ( m_listPluginOptions[QMPlayerWidget::AudioPlugin] );
	elem.setAttribute( MPLAYER_ATTRIB_PLUGIN_OPTIONS, m_listPluginOptions[QMPlayerWidget::AudioPluginOptions] );
	elem.appendChild ( domText );
	rootElem.appendChild( elem );

	xmlDoc.appendChild( rootElem );

	// Assign the file
	QFile iniFile(qsPlayerIniFile);
	if (!iniFile.open(IO_ReadWrite))
		return;

	QString xml = xmlDoc.toString();
	iniFile.writeBlock(xml, qstrlen (xml));
	iniFile.close();
}

void QMPlayerWidget::setFilename(const QString &qsFileName)
{
	QString qsBuffer;
	// Here we set the global file name.
	m_qsFileName = qsFileName;

	if (m_pMasterProcess->isRunning ())	{
		qsBuffer = QString ("loadfile %1\n").arg(qsFileName);
		writeToStdin (qsBuffer);
		m_fLength = 0.0;
	}
}

void QMPlayerWidget::slotReadStdout     ()
{
	QString qsStdout(m_pMasterProcess->readStdout());
	if (qsStdout.length() == 0)
		return;

	int iTemp, iElapsedTime, iElapsedLength, iSec, iMin, iHour;
	QString qsElapsedTime;
	iTemp = m_rxParseElapsedTime.match(qsStdout);
	iElapsedLength = 0;
	if (iTemp != -1)	{
		float fElapsedTime = m_rxParseElapsedTime.cap(1).toFloat();
		iElapsedTime = (int)fElapsedTime;
		if ( m_fLength > 0.0 )
		  iElapsedLength = (int)(fElapsedTime / m_fLength * 65535.0 );
		iHour = (int) (fElapsedTime / 3600.0); //(iElapsedTime - iSec - iMin*60)%3600;
		iMin  = (int)((fElapsedTime-iHour*3600)/60.0);
		iSec  = (int) (fElapsedTime-iHour*3600-iMin*60);
		qsElapsedTime = qsElapsedTime.sprintf ("%02d:%02d:%02d.%03d", iHour, iMin, iSec, (uint)((fElapsedTime - iElapsedTime)*1000.0));
		emit (signalNewPosition ( iElapsedLength, qsElapsedTime ) );
		emit (signalNewPosition ( (int)(fElapsedTime * 1000.0) ) );
	}

	if ( m_rxParseLength.search(qsStdout) > -1 )
	  m_fLength = m_rxParseLength.cap (1).toFloat ();
}

void QMPlayerWidget::slotReadStderr     ()
{
	QString qsStderr(m_pMasterProcess->readStdout());
	if (qsStderr.length() == 0)
		return;
}

void QMPlayerWidget::slotProcessExited  ()
{
	if (m_pMasterProcess->normalExit())
		m_iExitError = m_pMasterProcess->exitStatus();
	emit (signalMPlayerExited(m_iExitError));
	emit (signalPlaybackFinished ());
	m_fLength = 0.0;
}

void QMPlayerWidget::slotWroteToStdin   ()
{
}

void QMPlayerWidget::slotLaunchFinished ()
{
}

void QMPlayerWidget::writeToStdin(QString &qsBuffer)
{
	m_pMasterProcess->writeToStdin(qsBuffer.latin1());
}

void QMPlayerWidget::slotForward()
{
	slotSeek(m_iSeekValue,0);
}

void QMPlayerWidget::slotBack()
{
	slotSeek(-m_iSeekValue,0);
}

void QMPlayerWidget::slotPlay()
{
	if (m_bInPauseMode)
		slotPause ();
	if (m_pMasterProcess->isRunning())
		return;
	start();
}

void QMPlayerWidget::slotPause()
{
	m_bInPauseMode = !m_bInPauseMode;
	QString qsBuffer="pause\n";
	writeToStdin (qsBuffer);
}

void QMPlayerWidget::slotStop()
{
	if (m_bInPauseMode)
		slotPause ();
	if (m_pMasterProcess->isRunning())	{
		QString qsBuffer="quit\n";
		writeToStdin (qsBuffer);
	}
	m_bInPauseMode = false;
	m_fLength = 0.0;
}

void QMPlayerWidget::slotSetSpeed(float fValue)
{
	QString qsBuffer = QString("speed_set %1\n").arg(fValue);
	writeToStdin (qsBuffer);
}

void QMPlayerWidget::slotSetVolume(float fValue)
{
  // The slave mode seems to take relative values for the volume,
  // thus to quiet things down values between [0.0 and 1.0[
  // To increase volume values between [1.0 and oo[
  // are to be set.
  // Note: The volume does only depend on the number of times you set the 
  //       volume and not on the actual value. 
  //       I.e. 10*1.1 is the same as 10*1.0000001
  static float m_fOldVolume = 1.0f;
  double fVolume = fValue - m_fOldVolume + 1.0;
  m_fOldVolume   = fValue;
  QString qsBuffer = QString ( "volume %1\n" ).arg( fVolume );
  writeToStdin ( qsBuffer );
}

void QMPlayerWidget::slotScreenshot()
{
	system (QString("rm %1").arg(m_qsScreenshotName));
	QString qsBuffer = QString("screenshot %1\n").arg(m_qsScreenshotName);
	writeToStdin (qsBuffer);
	// Next we verify that the file has been created.
	QFileInfo fileInfo(m_qsScreenshotName);
	if (fileInfo.exists())	{

	}
}

void QMPlayerWidget::slotFullscreen()
{
	QString qsBuffer="vo_fullscreen\n";
	writeToStdin(qsBuffer);
}

void QMPlayerWidget::slotSeek(float fValue,int iMode)
{
	QString qsBuffer;
	if (iMode == 0)	// seek relative
		qsBuffer.sprintf("seek %d %d\n", (int)fValue, iMode);
	else if (iMode == 1)	// seek in % of total movie
		qsBuffer.sprintf("seek %f %d\n", fValue, iMode);
	else if (iMode == 2)	// seek in absolute total movie
		qsBuffer.sprintf("seek %d %d\n", (int)fValue, iMode);
	else	{
		printf ("Bad seeking mode, only 1 and 0 allowed\n");
		return;
	}
	writeToStdin(qsBuffer);
}

void QMPlayerWidget::slotSetSeek(int iNewValue)
{
	m_iSeekValue=iNewValue;
}

// Non mandatory functions.
void QMPlayerWidget::setAspectRatio (uint iAspectRatio)
{
	// Can be ASPECT_AUTO, ASPECT_34, ASPECT_169, or ASPECT_SQUARE
	QString qsBuffer;
	float fAspectRatio = 1.0f;
	switch (iAspectRatio)	{
	case ASPECT_AUTO:
		return;
	break;
	case ASPECT_34:
		fAspectRatio = 3.0 / 4.0;
	break;
	case ASPECT_169:
		fAspectRatio = 16.0 / 9.0;
	break;
	case ASPECT_SQUARE:
	default:
		fAspectRatio = 1.0;
	break;
	}
	qsBuffer.sprintf("switch_aspect %f\n", fAspectRatio);
	writeToStdin(qsBuffer);
}

bool QMPlayerWidget::isPlaying()
{
	return m_pMasterProcess->isRunning();
}

void QMPlayerWidget::playChapter (int iChapter)
{
	QString qsBuffer;
	qsBuffer.sprintf("pt_step %d\n", iChapter);
	writeToStdin(qsBuffer);
}

