/*
	ZazouMiniWebServer

	Copyright (C) 2003-2011 Xavier Garreau <xavier@xgarreau.org>

	This file is part of ZazouMiniWebServer.

    ZazouMiniWebServer 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.

    ZazouMiniWebServer is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ZazouMiniWebServer; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
	
#include "stdafx.h"
#include "threadpool.h"

/* *** ZReqProvider class *** */
ZReqProvider::ZReqProvider()
{
	queue_mutex = CreateMutex(NULL, FALSE, NULL);
	if (!queue_mutex) {
		zprintf("ERROR: ZReqProvider: Could not create queue mutex");
		_exit(1);
	}
	request_semaphore = CreateSemaphore (NULL, 1, 0xffff, NULL);
	DWORD err = GetLastError();
	if (!request_semaphore) {
		zprintf("ERROR: ZReqProvider: Could not create requests semaphore");
		_exit(1);
	}
	switch (WaitForSingleSemaphore(request_semaphore, 30000)) {
		case WAIT_ABANDONED:
		case WAIT_TIMEOUT:
		case WAIT_FAILED:
			zprintf("ERROR: ZReqProvider: Could not get semaphore\n");
			_exit(1);
			break;
		case WAIT_OBJECT_0:
			break;
	}
}

ZReqProvider::~ZReqProvider()
{
}

void ZReqProvider::CloseSyncObjects() 
{
		switch (WaitForSingleMutex(queue_mutex, 60000)) {
		case WAIT_ABANDONED:
		case WAIT_TIMEOUT:
		case WAIT_FAILED:
			break;
		case WAIT_OBJECT_0:
			while (!requests.empty()) {
				delete requests.front();
				requests.pop();
			}
			ReleaseMutex(queue_mutex);
			break;
	}
	CloseMutex (queue_mutex);
	LONG pc;
	if (!ReleaseSemaphore(request_semaphore, 0xffff, &pc)) {
		while (pc--) {
			ReleaseSemaphore(request_semaphore, 1, NULL);
		}
	}
	CloseSemaphore (request_semaphore);
}

BYTE ZReqProvider::request_add (ZRequest* r)
{
	BYTE retval=1;
	
	switch (WaitForSingleMutex(queue_mutex, INFINITE)) {
		case WAIT_ABANDONED:
		case WAIT_TIMEOUT:
		case WAIT_FAILED:
			retval = 0;
			break;
		case WAIT_OBJECT_0:
			retval = 1;
			requests.push(r);
			LONG prev_count;
			ReleaseSemaphore(request_semaphore, 1, &prev_count);
			ReleaseMutex(queue_mutex);
			break;
	}

	return retval;
}

ZRequest* ZReqProvider::request_get()
{
	ZRequest* r = NULL;
	switch (WaitForSingleSemaphore(request_semaphore, INFINITE)) {
		case WAIT_ABANDONED:
		case WAIT_TIMEOUT:
		case WAIT_FAILED:
			break;
		case WAIT_OBJECT_0:
			switch (WaitForSingleMutex(queue_mutex, INFINITE)) {
				case WAIT_ABANDONED:
				case WAIT_TIMEOUT:
				case WAIT_FAILED:
					break;
				case WAIT_OBJECT_0:
					if (!requests.empty()) {
						r = requests.front();
						requests.pop();
					}
					ReleaseMutex(queue_mutex);
					break;
			}
			break;
	}
	return r;
}
/* *** End ZReqProvider class *** */

/* *** ZThread class *** */
void __cdecl ZThread::start(void* data)
{
	ZThread* a_thread = static_cast<ZThread*>(data);
	a_thread->run();
}

ZThread::ZThread() : stop_thread(FALSE)
{
	stop_mutex = CreateMutex (NULL, FALSE, NULL);
	if (!stop_mutex) stop_thread = TRUE;
}

ZThread::~ZThread()
{
	if (stop_mutex) CloseMutex(stop_mutex);
}

BYTE ZThread::stop()
{
	BYTE retval;

	switch (WaitForSingleMutex(stop_mutex, INFINITE)) {
		case WAIT_ABANDONED:
		case WAIT_TIMEOUT:
		case WAIT_FAILED:
			retval = 0;
			break;
		case WAIT_OBJECT_0:
			stop_thread=1;
			retval = 1;
			ReleaseMutex(stop_mutex);
			break;
	}
	return retval;
}

BOOL ZThread::should_stop()
{
	BOOL retval;
	switch (WaitForSingleMutex(stop_mutex, 60000)) {
		case WAIT_ABANDONED:
		case WAIT_TIMEOUT:
		case WAIT_FAILED:
			retval = TRUE;
			break;
		case WAIT_OBJECT_0:
			retval = stop_thread;
			ReleaseMutex(stop_mutex);
			break;
	}
	return retval;
}

void ZThread::run()
{
	ZRequest* r;
	while (!should_stop()) {
		r = request_provider->request_get();
		if (r) {
			handle_request(r);
		}
	}
	delete this;
}
/* *** End ZThread class *** */

