//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// copyright            : (C) 2008 by Eran Ifrah                            
// file name            : jobqueue.cpp              
//                                                                          
// -------------------------------------------------------------------------
// A                                                                        
//              _____           _      _     _ _                            
//             /  __ \         | |    | |   (_) |                           
//             | /  \/ ___   __| | ___| |    _| |_ ___                      
//             | |    / _ \ / _  |/ _ \ |   | | __/ _ )                     
//             | \__/\ (_) | (_| |  __/ |___| | ||  __/                     
//              \____/\___/ \__,_|\___\_____/_|\__\___|                     
//                                                                          
//                                                  F i l e                 
//                                                                          
//    This program is free software; you can redistribute it and/or modify  
//    it under the terms of the GNU General Public License as published by  
//    the Free Software Foundation; either version 2 of the License, or     
//    (at your option) any later version.                                   
//                                                                          
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
 #include "jobqueue.h"
#include "job.h"

JobQueueWorker::JobQueueWorker(wxCriticalSection *cs, std::deque<Job*> *queue)
		: wxThread(wxTHREAD_JOINABLE)
		, m_cs(cs)
		, m_queue(queue)
{
}

JobQueueWorker::~JobQueueWorker()
{
}

void JobQueueWorker::Stop()
{
	// Notify the thread to stop
	// and wait for its termination
	if ( IsAlive() )
		Delete();

	while ( IsAlive() ) {
		wxThread::Sleep( 5 );
	}
}

void JobQueueWorker::Start(int priority)
{
	Create();
	SetPriority(priority);
	Run();
}

Job *JobQueueWorker::GetJob()
{
	wxCriticalSectionLocker locker(*m_cs);
	Job *req(NULL);
	if ( !m_queue->empty() ) {
		req = m_queue->front();
		m_queue->pop_front();
	}
	return req;
}

void* JobQueueWorker::Entry()
{
	while ( true ) {
		// Did we get a request to terminate?
		if (TestDestroy())
			break;

		Job *job = GetJob();
		if ( job ) {
			// Call user's implementation for processing request
			ProcessJob( job );

			wxThread::Sleep(10);  // Allow other threads to work as well
			delete job;
			job = NULL;
			continue; // to avoid the sleep
		}

		// Sleep for 200ms , and then try again
		wxThread::Sleep(200);
	}
	return NULL;
}

void JobQueueWorker::ProcessJob(Job *job)
{
	if ( job ) {
		job->Process(this);
	}
}

//--------------------------------------------------------------
// JobQueue
//--------------------------------------------------------------

JobQueue::JobQueue()
{
}

JobQueue::~JobQueue()
{
	if ( !m_queue.empty() ) {
		std::deque<Job*>::iterator iter = m_queue.begin();
		for (; iter != m_queue.end(); iter++) {
			delete (*iter);
		}
		m_queue.clear();
	}
}

void JobQueue::PushJob(Job *job)
{
	wxCriticalSectionLocker locker(m_cs);
	m_queue.push_front(job);
}

void JobQueue::Start(size_t poolSize, int priority)
{
	size_t maxPoolSize = poolSize > 250 ? 250 : poolSize;
	for(size_t i=0; i<maxPoolSize; i++) {
		//create new thread
		JobQueueWorker *worker = new JobQueueWorker(&m_cs, &m_queue);
		worker->Start(priority);
		m_threads.push_back(worker);
	}
}

void JobQueue::Stop()
{
	//first loop and stop all running threads
	for(size_t i=0; i<m_threads.size(); i++){
		JobQueueWorker *worker = m_threads.at(i);
		//stop it 
		worker->Stop();
		//delete it
		delete worker;
	}
	m_threads.clear();
}

//-----------------------------------------------------
// Job queue singleton
//-----------------------------------------------------
JobQueue* JobQueueSingleton::ms_instance = new JobQueue();

JobQueueSingleton::JobQueueSingleton()
{
}

JobQueueSingleton::~JobQueueSingleton()
{
}

JobQueue* JobQueueSingleton::Instance()
{
	return ms_instance;
}

void JobQueueSingleton::Release()
{
	if (ms_instance) {
		delete ms_instance;
	}
	ms_instance = 0;
}
