#include <windows.h>
#include <OW32/SyncObjects.h>

#include "AutoConnection.h"

CConnection** g_connections;

// event set when a connection becomes free
static CEvent g_connection_released;

// Map of in use connections & a lock for it
static CCriticalSection g_inuse_lock;
unsigned int* g_inuse;


// bit masks
static unsigned int masks[32] = {
	0x00000001, 0x00000002, 0x00000004, 0x00000008,
	0x00000010, 0x00000020, 0x00000040, 0x00000080,
	0x00000100, 0x00000200, 0x00000400, 0x00000800,
	0x00001000, 0x00002000, 0x00004000, 0x00008000,
	0x00010000, 0x00020000, 0x00040000, 0x00080000,
	0x00100000, 0x00200000, 0x00400000, 0x00800000,
	0x01000000, 0x02000000, 0x04000000, 0x08000000,
	0x10000000, 0x20000000, 0x40000000, 0x80000000 };

// The c'tor for auto_connection chooses a free connection, or waits for one
// to become available if there is nothing free to start with
auto_connection::auto_connection()
{
	while (1) {
		{
			CSingleLock lock(g_inuse_lock);

			// scan for a free connection
			unsigned int idx=0,count=0,bit=0;
			while (count < g_num_connections) {
				if (!(g_inuse[idx] & masks[bit])) {
					g_inuse[idx] |= masks[bit];
					m_connection = g_connections[count];
					return;
				}
				if (++bit > 31) { bit = 0; idx++; }
				++count;
			}
			g_connection_released.Reset();
		}

		// if no free connections, wait for one
		CSingleLock lock(g_connection_released);
	}
}

// The d'tor for auto_connection simply marks the connection as free and
// releases any waiting clients
auto_connection::~auto_connection()
{
	CSingleLock lock(g_inuse_lock);

	// mark as not in use
	g_inuse[m_connection->getIndex()/32] &= ~masks[m_connection->getIndex()%32];

	// free any waiting clients
	g_connection_released.Set();
}

