/****************************************************************************
** MediaScanner class
**
** Created: Tue Jan 02 22:06:51 2004
**      by: Varol Okan using Kate
**
** This class spinns off a new thread and generate a Preview of the Job 
** which was set through MediaCreator::registerWithMediaScanner.
** 
** Once the preview is generated we will call the update function in 
** the main thread ( Currently MovieObject::updatePixmap () )
**
** if after 5 seconds after termination of the thread there are no new 
** requests in the queue then the thread will be termintaed to free 
** some memory.
**
****************************************************************************/

#include <qapplication.h>
#include <qimage.h>

#include "../sourcefileentry.h"
#include "mediascanner.h"
#include "mediacreator.h"
#include "mediainfo.h"


MediaScanner::MediaScanner()
	: QThread ()
{
	m_bHasFinished = false;
	m_bSemaphore   = false;
}

bool MediaScanner::hasFinished ()
{
	return m_bHasFinished;
}

void MediaScanner::append(ExecuteJob *pNewJob)
{
	// Please remember that this is executed in the main thread
	if ( ! setSemaphore ( true ) )
		return;
	m_listExecuteFifo.append (pNewJob);
	setSemaphore ( false );
	if (!running())	{
#if (QT_VERSION > 0x0301FF)
		start (QThread::LowPriority);
#else
		start ();
#endif
	}
}

void MediaScanner::remove ( SourceFileInfo *pSourceFileInfo )
{
	// Please remember that this is executed in the main thread
	uint t;
	ExecuteJob *pJob = NULL;
	if ( ! setSemaphore ( true ) )
		return;
	for (t=0;t<m_listExecuteFifo.count();t++)	{
		pJob = m_listExecuteFifo[t];
		if (pJob->pSourceFileInfo == pSourceFileInfo)	{
			pJob->pSourceFileInfo = NULL;
			pJob->pOrigObject     = NULL;
		}
	}
	setSemaphore ( false );
}
			
void MediaScanner::remove (QObject *pObject)
{
	// Please remember that this is executed in the main thread
	uint t;
	ExecuteJob *pJob = NULL;
	if ( ! setSemaphore ( true ) )
		return;
	for (t=0;t<m_listExecuteFifo.count();t++)	{
		pJob = m_listExecuteFifo[t];
		if (pJob->pOrigObject == pObject)	{
			pJob->pOrigObject = NULL;
		}
	}
	setSemaphore ( false );
}

bool MediaScanner::setSemaphore ( bool bSet )
{
	uint iMaxWait = 0;
	// FALSE== freeing the semaphore does not require a check ...
	if ( bSet )	{
		// wait for max 3 seconds ...
		while ((m_bSemaphore) || (iMaxWait++ > 3000))
			usleep (1000);	// wait for 1 mSec
		// Status check if we reached max waiting time without success ...
		if (iMaxWait > 2998)
			return false;
	}
	m_bSemaphore = bSet;
	return true;
}

void MediaScanner::run()
{
	// And this is executed in the child thread ...
	uint t;
	m_pMediaInfo = MediaCreator::createInfo ();
	QValueList<ExecuteJob *> listOfExecutedJobs;
	QString qsFileName;
	QImage theImage;
	// Generate the preview(s)
	while (m_listExecuteFifo.count())	{
		// I need the two loops because after running through the inner loop we see if the user 
		// will generate a new request within 5 seconds or not.
		while (m_listExecuteFifo.count())	{
			if ( ! setSemaphore ( true ) )
				return;	// timed out.
			ExecuteJob *pCurrentJob = m_listExecuteFifo.first();
			// Check if the object was destroyed from some other thread ...
			if ( ! pCurrentJob->pOrigObject )	{
				m_listExecuteFifo.remove  (pCurrentJob);
				listOfExecutedJobs.append (pCurrentJob);
				setSemaphore ( false );
				continue;
			}

			if (pCurrentJob->pSourceFileInfo)	{
				qsFileName = pCurrentJob->pSourceFileInfo->qsFileName;
				setSemaphore ( false );// unblock since the next function can take a few seconds.
				m_pMediaInfo->setFileName (qsFileName);
				if ( ( setSemaphore ( true ) ) && (pCurrentJob->pOrigObject) && ( pCurrentJob->bUpdateAllInfo ) )	{
					pCurrentJob->pSourceFileInfo->qsVideoFormat= m_pMediaInfo->getFormat     ( true  );
					pCurrentJob->pSourceFileInfo->qsResolution = m_pMediaInfo->getResolutionString ( );
					pCurrentJob->pSourceFileInfo->qsLength     = m_pMediaInfo->getLengthString     ( );
					pCurrentJob->pSourceFileInfo->qsSize       = m_pMediaInfo->getSizeString       ( );
					pCurrentJob->pSourceFileInfo->qsRatio      = m_pMediaInfo->getRatio            ( );
					pCurrentJob->pSourceFileInfo->qsStatus     = m_pMediaInfo->getStatus           ( );
					pCurrentJob->pSourceFileInfo->qsFPS        = QString ("%1").arg ( m_pMediaInfo->getFPS  ( ) );
					// And also store the audio props ...
					pCurrentJob->pSourceFileInfo->qsBits       = QString ("%1").arg ( m_pMediaInfo->getBits ( ) );
					pCurrentJob->pSourceFileInfo->qsAudioFormat= m_pMediaInfo->getFormat     ( false );
					pCurrentJob->pSourceFileInfo->qsBPS        = m_pMediaInfo->getBPSString  ( false );
					pCurrentJob->pSourceFileInfo->qsSample     = m_pMediaInfo->getSampleString     ( );
				}
				setSemaphore ( false );// unblock since the next function can take a few seconds.
				theImage = m_pMediaInfo->getScreenshot (pCurrentJob->iMSecondsOffset);
				// Sanity check ... and copying the image over.
				if ( ( setSemaphore ( true ) ) && (pCurrentJob->pOrigObject) )	{
					QSize sizeButton = pCurrentJob->pSourceFileInfo->pPreview->size();
					if (theImage.isNull())
						*pCurrentJob->pSourceFileInfo->pPreview = QImage().fromMimeSource( "error.jpg" ).smoothScale(sizeButton, QImage::ScaleFree);
					else
						*pCurrentJob->pSourceFileInfo->pPreview = theImage.smoothScale(sizeButton, QImage::ScaleMin);
					pCurrentJob->pSourceFileInfo->bUpdateInfo = true;
				}
				setSemaphore ( false );
			}
			else	{
				m_pMediaInfo->setFileName (pCurrentJob->qsFileName);
				setSemaphore ( false );	// unblock since the next function can take a few seconds.
				theImage = m_pMediaInfo->getScreenshot (pCurrentJob->iMSecondsOffset);
				// Sanity check ...
				if ( ( setSemaphore ( true ) ) && (pCurrentJob->pOrigObject) )	{
					if (theImage.isNull())
						*pCurrentJob->pImage = QImage().fromMimeSource( "error.jpg" );
					else
						*pCurrentJob->pImage = theImage;
				}
				setSemaphore ( false );
			}
			if ( setSemaphore ( true ) )  {	// Protect the Fifo ...
			  m_listExecuteFifo.remove  (pCurrentJob);
			  listOfExecutedJobs.append (pCurrentJob);
			  if ( pCurrentJob->pOrigObject )
			    QApplication::postEvent(pCurrentJob->pOrigObject, new QTimerEvent(MEDIASCANNER_EVENT));
			}
			setSemaphore ( false );
		}
		sleep (5);	// wait for 5 seconds. In this time the user could start another task ...
	}

	for (t=0;t<listOfExecutedJobs.count();t++)	
		delete listOfExecutedJobs[t];
	m_bHasFinished = true;
	delete m_pMediaInfo;
	m_pMediaInfo = NULL;
}


/*
void MediaScanner::run()
{
	// And this is executed in the child thread ...
	uint t;
	int iMaxWait;
	m_pMediaInfo = MediaCreator::createInfo ();
	QValueList<ExecuteJob *> listOfExecutedJobs;
	QImage theImage;
	// Generate the preview(s)
	while (m_listExecuteFifo.count())	{
		// I need the two loops because after running through the inner loop we see if the user 
		// will generate a new request within 5 seconds or not.
		while (m_listExecuteFifo.count())	{
			iMaxWait = 0;
			// wait for max 3 seconds ...
			while ((m_bSemaphore) || (iMaxWait++ > 3000))
				usleep (1000);	// wait for 1 mSec
			// Status check if we reached max waiting time without success ...
			if (iMaxWait > 2998)
				return;
			m_bSemaphore = true;
			ExecuteJob *pCurrentJob = m_listExecuteFifo.first();
			m_listExecuteFifo.remove (pCurrentJob);
			m_bSemaphore = false;
			if (pCurrentJob->pSourceFileInfo)	{
				m_pMediaInfo->setFileName (pCurrentJob->pSourceFileInfo->qsFileName);
				pCurrentJob->pSourceFileInfo->qsFormat     = m_pMediaInfo->getFormat (true);
				pCurrentJob->pSourceFileInfo->qsResolution = m_pMediaInfo->getResolutionString ();
				pCurrentJob->pSourceFileInfo->qsLength     = m_pMediaInfo->getLengthString ();
				pCurrentJob->pSourceFileInfo->qsSize       = m_pMediaInfo->getSizeString();
				pCurrentJob->pSourceFileInfo->qsRatio      = m_pMediaInfo->getRatio ();
				pCurrentJob->pSourceFileInfo->qsFPS        = QString ("%1").arg(m_pMediaInfo->getFPS());
				pCurrentJob->pSourceFileInfo->qsStatus     = m_pMediaInfo->getStatus();
				theImage = m_pMediaInfo->getScreenshot (pCurrentJob->iMSecondsOffset);
				// Sanity check ... and copying the image over.
				if ( pCurrentJob->pOrigObject )	{
					QSize sizeButton = pCurrentJob->pSourceFileInfo->pPreview->size();
					if (theImage.isNull())
						*pCurrentJob->pSourceFileInfo->pPreview = QImage().fromMimeSource( "error.jpg" ).smoothScale(sizeButton, QImage::ScaleFree);
					else
						*pCurrentJob->pSourceFileInfo->pPreview = theImage.smoothScale(sizeButton, QImage::ScaleMin);
					pCurrentJob->pSourceFileInfo->bUpdateInfo = true;
				}
			}
			else	{
				m_pMediaInfo->setFileName (pCurrentJob->qsFileName);

//				theImage = m_pMediaInfo->getScreenshot (pCurrentJob->iMSecondsOffset);
//				theImage = QImage (QPixmap::fromMimeSource( "error.jpg" ).convertToImage());
				// Sanity check ...
				if ( pCurrentJob->pOrigObject )	{
//					if (theImage.isNull())
//						*pCurrentJob->pImage = QImage (10, 10, 16);
//						*pCurrentJob->pImage = QImage (QPixmap::fromMimeSource( "error.jpg" ).convertToImage());
						*pCurrentJob->pImage = QImage().fromMimeSource( "error.jpg" );
//						sleep (1);
//					else
//						*pCurrentJob->pImage = theImage;
				}
			}
			listOfExecutedJobs.append (pCurrentJob);
			if ( pCurrentJob->pOrigObject )	{
printf ("MediaScanner::run Before Post <%X>-><%X>\n", pCurrentJob, pCurrentJob->pOrigObject);
				QApplication::postEvent(pCurrentJob->pOrigObject, new QTimerEvent(MEDIASCANNER_EVENT));
printf ("MediaScanner::run After  Post <%X>\n", pCurrentJob->pOrigObject);
			}
		}
		sleep (5);	// wait for 5 seconds ...
	}

	for (t=0;t<listOfExecutedJobs.count();t++)	
		delete listOfExecutedJobs[t];
	m_bHasFinished = true;
	delete m_pMediaInfo;
	m_pMediaInfo = NULL;
}
*/
