/*
 * Copyright 2009 Funambol, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id$ */

#pragma once

#define _WIN32_WINNT 0x0501
#include <windows.h>
#include "CondVariable.h"
#include "CritSection.h"

using namespace NS_DM_Client::NS_Common;

CondVariable::CondVariable() :
	m_waitersCount(0), m_broadcasted(false)
{
	//InitializeConditionVariable(&m_condition);
	// unnamed semaphore intially set to 0 and max count 0x7fffffff
	// this sem queue threads to be woke up on signal
	m_smWaiters = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);

	// create autoreset event
	m_evWaitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
}

CondVariable::~CondVariable()
{
	CloseHandle(m_smWaiters);
	CloseHandle(m_evWaitersDone);
}

void CondVariable::Wait(CritSection &cs)
{
	//SleepConditionVariableCS(&m_condition, &cs.m_critsection, INFINITE);

	m_csWCount.Lock();
	m_waitersCount++;
	m_csWCount.Unlock();
	
	SignalObjectAndWait(cs.m_mutex, m_smWaiters, INFINITE, FALSE);

	m_csWCount.Lock();
	m_waitersCount--;
	int last_waiter = m_waitersCount == 0;
	m_csWCount.Unlock();
	if (last_waiter)
		SignalObjectAndWait(m_evWaitersDone, cs.m_mutex, INFINITE, FALSE);
	else
		cs.Lock();
		//WaitForSingleObject(cs.m_mutex, INFINITE);
}

void CondVariable::Signal()
{	
	m_csWCount.Lock();
	int have_waiters = m_waitersCount > 0;
	m_csWCount.Unlock();
	if (have_waiters)
		ReleaseSemaphore(m_smWaiters, 1, 0);
	//WakeConditionVariable(&m_condition);				
}
