/*
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 "stdafx.h"

static MessageSendQueueItem *global_sendQueue = nullptr;
static mir_cs queueMutex;

wchar_t* GetSendBufferMsg(MessageSendQueueItem *item)
{
	return mir_utf8decodeW(item->sendBuffer);
}

MessageSendQueueItem* CreateSendQueueItem(HWND hwndSender)
{
	MessageSendQueueItem *item = (MessageSendQueueItem*)mir_calloc(sizeof(MessageSendQueueItem));

	mir_cslock lck(queueMutex);
	item->hwndSender = hwndSender;
	item->next = global_sendQueue;
	if (global_sendQueue != nullptr)
		global_sendQueue->prev = item;

	global_sendQueue = item;
	return item;
}

MessageSendQueueItem* FindOldestPendingSendQueueItem(HWND hwndSender, MCONTACT hContact)
{
	mir_cslock lck(queueMutex);
	for (MessageSendQueueItem *item = global_sendQueue; item != nullptr; item = item->next)
		if (item->hwndSender == hwndSender && item->hContact == hContact && item->hwndErrorDlg == nullptr)
			return item;

	return nullptr;
}

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

	return nullptr;
}

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

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

	if (item->next != nullptr)
		item->next->prev = item->prev;

	mir_free(item->sendBuffer);
	mir_free(item->proto);
	mir_free(item);

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

	return TRUE;
}

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

	mir_cslock lock(queueMutex);

	for (item = global_sendQueue; item != nullptr; item = item2) {
		item2 = item->next;
		if (item->timeout < timeout) {
			item->timeout += 1000;
			if (item->timeout >= timeout) {
				if (item->hwndSender == hwndSender && item->hwndErrorDlg == nullptr) {
					if (hwndSender != nullptr) {
						ErrorWindowData *ewd = (ErrorWindowData *)mir_alloc(sizeof(ErrorWindowData));
						ewd->szName = mir_wstrdup(pcli->pfnGetContactDisplayName(item->hContact, 0));
						ewd->szDescription = mir_wstrdup(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 != nullptr; item = item->next) {
		if (item->hwndSender == hwndSender) {
			item->hwndSender = nullptr;
			if (item->hwndErrorDlg != nullptr)
				DestroyWindow(item->hwndErrorDlg);

			item->hwndErrorDlg = nullptr;
		}
	}
}

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

	mir_cslock lock(queueMutex);

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

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

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

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

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

		global_sendQueue = item;
	}
	lock.unlock();

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