/*
 * Still Image class installer
 *
 * Copyright (C) 2005 Damjan Jovanovic
 * Copyright (C) 2006 Igor Farinic
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


#include "sti_internal.h"
#include "wine/list.h"

typedef struct
{
	InternalDevice *device;
	struct list entry;
} DeviceListEntry;

static HANDLE deviceMutex;
static struct list deviceList = LIST_INIT(deviceList);
	
static DWORD InitializeDeviceList()
{
	static int initialized = 0;
	if (!initialized)
	{
		deviceMutex = CreateMutexA(NULL, FALSE, NULL);
		if (deviceMutex != INVALID_HANDLE_VALUE && deviceMutex != NULL)
			initialized = 1;
		else
			return GetLastError();
	}
	return 0;
}

static DeviceListEntry* find_entry(WCHAR *internalName)
{
	DeviceListEntry *devListEntry, *found = 0;
	LIST_FOR_EACH_ENTRY(devListEntry, &deviceList, DeviceListEntry, entry)
	{
		if (strcmpW(devListEntry->device->m_internalName, internalName) == 0)
		{
			found = devListEntry;
			break;
		}
	}
	return found;
}

InternalDevice* find_device(WCHAR *internalName)
{
	DeviceListEntry *entry;
	WaitForSingleObject(deviceMutex, INFINITE);
	entry = find_entry(internalName);
	if (entry)
		++entry->device->m_refCount;
	ReleaseMutex(deviceMutex);
	if (entry)
		return entry->device;
	else
		return NULL;
}

static DWORD add_device(WCHAR *internalName)
{
	DeviceListEntry *dev;
	dev = (DeviceListEntry*) malloc(sizeof(DeviceListEntry));
	if (!dev)
		return E_OUTOFMEMORY;
	dev->device = (InternalDevice*) malloc(sizeof(InternalDevice));
	if (!dev->device)
	{
		free(dev);
		return E_OUTOFMEMORY;
	}
	dev->device->m_refCount = 1;
	lstrcpynW(dev->device->m_internalName, internalName, sizeof(dev->device->m_internalName)/sizeof(dev->device->m_internalName[0]));
	dev->device->m_mutex = CreateMutexA(NULL, FALSE, NULL);
	list_add_head(&deviceList, &dev->entry);
}

static void delete_device(DeviceListEntry *entry)
{
	list_remove(&entry->entry);
	--entry->device->m_refCount;
}

void update_devices(STI_DEVICE_INFORMATIONW *devices, DWORD deviceCount)
{
	int i;
	DeviceListEntry *entry;
	
	WaitForSingleObject(deviceMutex, INFINITE);
	for (i = 0; i < deviceCount; ++i)
	{
		entry = find_entry(devices[i].szDeviceInternalName);
		if (strlenW(devices[i].pszPortName) == 0)
		{
			/* Device isn't there, if we have it listed, delete it */
			if (entry)
				delete_device(entry);
		}
		else
		{
			/* Device is there, if we don't have it listed, add it */
			if (!entry)
				add_device(devices[i].szDeviceInternalName);
		}
	}
	ReleaseMutex(deviceMutex);
}
