/*
Scriver

Copyright (c) 2000-09 Miranda ICQ/IM project,

all portions of this codebase are copyrighted to the people
listed in contributors.txt.

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.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "commonheaders.h"

static MessageSendQueueItem *global_sendQueue = NULL;
static CRITICAL_SECTION queueMutex;

TCHAR * GetSendBufferMsg(MessageSendQueueItem *item)
{
	TCHAR *szMsg = NULL;
	size_t len = strlen(item->sendBuffer);

	if (item->flags & PREF_UTF)
		szMsg = mir_utf8decodeW(item->sendBuffer);
	else {
		szMsg = (TCHAR *)mir_alloc(item->sendBufferSize - len - 1);
		memcpy(szMsg, item->sendBuffer + len + 1, item->sendBufferSize - len - 1);
	}

	return szMsg;
}

void InitSendQueue()
{
	InitializeCriticalSection(&queueMutex);
}

void DestroySendQueue()
{
	DeleteCriticalSection(&queueMutex);
}

MessageSendQueueItem* CreateSendQueueItem(HWND hwndSender)
{
	MessageSendQueueItem *item = (MessageSendQueueItem *) mir_alloc(sizeof(MessageSendQueueItem));
	EnterCriticalSection(&queueMutex);
	ZeroMemory(item, sizeof(MessageSendQueueItem));
	item->hwndSender = hwndSender;
	item->next = global_sendQueue;
	if (global_sendQueue != NULL) {
		global_sendQueue->prev = item;
	}
	global_sendQueue = item;
	LeaveCriticalSection(&queueMutex);
	return item;
}

MessageSendQueueItem* FindOldestPendingSendQueueItem(HWND hwndSender, HANDLE hContact)
{
	MessageSendQueueItem *item, *found = NULL;
	EnterCriticalSection(&queueMutex);
	for (item = global_sendQueue; item != NULL; item = item->next) {
		if (item->hwndSender == hwndSender && item->hContact == hContact && item->hwndErrorDlg == NULL) {
			found = item;
		}
	}
	LeaveCriticalSection(&queueMutex);
	return found;
}

MessageSendQueueItem* FindSendQueueItem(HANDLE hContact, HANDLE hSendId)
{
	mir_cslock lock(queueMutex);
	for (MessageSendQueueItem *item = global_sendQueue; item != NULL; item = item->next)
		if (item->hContact == hContact && item->hSendId == hSendId)
			return item;

	return NULL;
}

BOOL RemoveSendQueueItem(MessageSendQueueItem* item)
{
	HWND hwndSender = item->hwndSender;

	mir_cslock lock(queueMutex);
	if (item->prev != NULL)
		item->prev->next = item->next;
	else
		global_sendQueue = item->next;

	if (item->next != NULL)
		item->next->prev = item->prev;
	
	mir_free(item->sendBuffer);
	mir_free(item->proto);
	mir_free(item);

	for (item = global_sendQueue; item != NULL; item = item->next)
		if (item->hwndSender == hwndSender)
			return FALSE;

	return TRUE;
}

void ReportSendQueueTimeouts(HWND hwndSender)
{
	MessageSendQueueItem *item, *item2;
	int timeout = db_get_dw(NULL, SRMMMOD, SRMSGSET_MSGTIMEOUT, SRMSGDEFSET_MSGTIMEOUT);

	mir_cslock lock(queueMutex);

	for (item = global_sendQueue; item != NULL; item = item2) {
		item2 = item->next;
		if (item->timeout < timeout) {
			item->timeout += 1000;
			if (item->timeout >= timeout) {
				if (item->hwndSender == hwndSender && item->hwndErrorDlg == NULL) {
					if (hwndSender != NULL) {
						ErrorWindowData *ewd = (ErrorWindowData *) mir_alloc(sizeof(ErrorWindowData));
						ewd->szName = GetNickname(item->hContact, item->proto);
						ewd->szDescription = mir_tstrdup(TranslateT("The message send timed out."));
						ewd->szText = GetSendBufferMsg(item);
						ewd->hwndParent = hwndSender;
						ewd->queueItem = item;
						PostMessage(hwndSender, DM_SHOWERRORMESSAGE, 0, (LPARAM)ewd);
					} else {
						/* TODO: Handle errors outside messaging window in a better way */
						RemoveSendQueueItem(item);
					}
				}
			}
		}
	}
}

void ReleaseSendQueueItems(HWND hwndSender)
{
	mir_cslock lock(queueMutex);

	for (MessageSendQueueItem *item = global_sendQueue; item != NULL; item = item->next) {
		if (item->hwndSender == hwndSender) {
			item->hwndSender = NULL;
			if (item->hwndErrorDlg != NULL)
				DestroyWindow(item->hwndErrorDlg);

			item->hwndErrorDlg = NULL;
		}
	}
}

int ReattachSendQueueItems(HWND hwndSender, HANDLE hContact)
{
	int count = 0;

	mir_cslock lock(queueMutex);

	for (MessageSendQueueItem *item = global_sendQueue; item != NULL; item = item->next) {
		if (item->hContact == hContact && item->hwndSender == NULL) {
			item->hwndSender = hwndSender;
			item->timeout = 0;
			count++;
		}
	}
	return count;
}

void RemoveAllSendQueueItems()
{
	MessageSendQueueItem *item, *item2;
	mir_cslock lock(queueMutex);
	for (item = global_sendQueue; item != NULL; item = item2) {
		item2 = item->next;
		RemoveSendQueueItem(item);
	}
}

void SendSendQueueItem(MessageSendQueueItem* item)
{
	mir_cslockfull lock(queueMutex);
	item->timeout = 0;

	if (item->prev != NULL) {
		item->prev->next = item->next;
		if (item->next != NULL)
			item->next->prev = item->prev;

		item->next = global_sendQueue;
		item->prev = NULL;
		if (global_sendQueue != NULL)
			global_sendQueue->prev = item;

		global_sendQueue = item;
	}
	lock.unlock();

	item->hSendId = (HANDLE)CallContactService(item->hContact, PSS_MESSAGE, item->flags, (LPARAM)item->sendBuffer);
}