/*
Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org)
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 version 2
of the License.
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, see .
*/
#include "stdafx.h"
extern BYTE nameOrder[NAMEORDERCOUNT];
/////////////////////////////////////////////////////////////////////////////////////////
char* StringFromBlob(BYTE *blob, WORD len)
{
	int j;
	char tmp[16];
	char *data = (char*)mir_alloc(3 * (len + 2));
	data[0] = 0;
	for (j = 0; j < len; j++) {
		mir_snprintf(tmp, "%02X ", blob[j]);
		mir_strcat(data, tmp);
	}
	return data;
}
int WriteBlobFromString(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue, int len)
{
	int j = 0, i = 0;
	BYTE b;
	int tmp, res = 0;
	BYTE *data = (BYTE*)mir_alloc(2 + len / 2);
	if (!data)
		return 0;
	while (j < len) {
		b = szValue[j];
		if ((b >= '0' && b <= '9') ||
			(b >= 'A' && b <= 'F') ||
			(b >= 'a' && b <= 'f')) {
			if (sscanf(&szValue[j], "%02X", &tmp) == 1) {
				data[i++] = (BYTE)(tmp & 0xFF);
				j++;
			}
		}
		j++;
	}
	if (i)
		res = !db_set_blob(hContact, szModule, szSetting, data, (WORD)i);
	mir_free(data);
	return res;
}
wchar_t* DBVType(BYTE type)
{
	switch (type) {
	case DBVT_BYTE:     return L"BYTE";
	case DBVT_WORD:     return L"WORD";
	case DBVT_DWORD:    return L"DWORD";
	case DBVT_ASCIIZ:   return L"STRING";
	case DBVT_WCHAR:
	case DBVT_UTF8:     return L"UNICODE";
	case DBVT_BLOB:     return L"BLOB";
	case DBVT_DELETED:  return L"DELETED";
	}
	return L"";
}
DWORD getNumericValue(DBVARIANT *dbv)
{
	switch (dbv->type) {
	case DBVT_DWORD:
		return dbv->dVal;
	case DBVT_WORD:
		return dbv->wVal;
	case DBVT_BYTE:
		return dbv->bVal;
	}
	return 0;
}
int setNumericValue(MCONTACT hContact, const char *module, const char *setting, DWORD value, int type)
{
	switch (type) {
	case DBVT_BYTE:
		if (value <= 0xFF)
			return !db_set_b(hContact, module, setting, (BYTE)value);
		break;
	case DBVT_WORD:
		if (value <= 0xFFFF)
			return !db_set_w(hContact, module, setting, (WORD)value);
		break;
	case DBVT_DWORD:
		return !db_set_dw(hContact, module, setting, value);
	}
	return 0;
}
int IsRealUnicode(wchar_t *value)
{
	BOOL nonascii = 0;
	WideCharToMultiByte(Langpack_GetDefaultCodePage(), WC_NO_BEST_FIT_CHARS, value, -1, nullptr, 0, nullptr, &nonascii);
	return nonascii;
}
int setTextValue(MCONTACT hContact, const char *module, const char *setting, wchar_t *value, int type)
{
	if (type == DBVT_UTF8 || type == DBVT_WCHAR)
		return !db_set_ws(hContact, module, setting, value);
	if (type == DBVT_ASCIIZ && IsRealUnicode(value))
		return 0;
	return !db_set_s(hContact, module, setting, _T2A(value));
}
int GetValueA(MCONTACT hContact, const char *module, const char *setting, char *value, int length)
{
	DBVARIANT dbv = {};
	if (!module || !setting || !value)
		return 0;
	if (length >= 10 && !db_get_s(hContact, module, setting, &dbv, 0)) {
		switch (dbv.type) {
		case DBVT_ASCIIZ:
			mir_strncpy(value, dbv.pszVal, length);
			break;
		case DBVT_DWORD:
		case DBVT_WORD:
		case DBVT_BYTE:
			_ultoa(getNumericValue(&dbv), value, 10);
			break;
		case DBVT_WCHAR:
			mir_strncpy(value, ptrA(mir_u2a(dbv.pwszVal)), length);
			break;
		case DBVT_UTF8:
			mir_strncpy(value, ptrA(mir_utf8decodeA(dbv.pszVal)), length);
			break;
		case DBVT_DELETED:
			value[0] = 0;
			return 0;
		}
		int type = dbv.type;
		db_free(&dbv);
		return type;
	}
	value[0] = 0;
	return 0;
}
int GetValueW(MCONTACT hContact, const char *module, const char *setting, WCHAR *value, int length)
{
	DBVARIANT dbv = {};
	if (!module || !setting || !value)
		return 0;
	if (length >= 10 && !db_get_s(hContact, module, setting, &dbv, 0)) {
		switch (dbv.type) {
		case DBVT_ASCIIZ:
			mir_wstrncpy(value, ptrW(mir_a2u(dbv.pszVal)), length);
			break;
		case DBVT_DWORD:
		case DBVT_WORD:
		case DBVT_BYTE:
			_ultow(getNumericValue(&dbv), value, 10);
			break;
		case DBVT_WCHAR:
			mir_wstrncpy(value, dbv.pwszVal, length);
			break;
		case DBVT_UTF8:
			mir_wstrncpy(value, ptrW(mir_utf8decodeW(dbv.pszVal)), length);
			break;
		case DBVT_DELETED:
			value[0] = 0;
			return 0;
		}
		int type = dbv.type;
		db_free(&dbv);
		return type;
	}
	value[0] = 0;
	return 0;
}
int GetContactName(MCONTACT hContact, const char *proto, wchar_t *value, int maxlen)
{
	if (!value)
		return 0;
	if (!hContact) {
		mir_wstrncpy(value, TranslateT("Settings"), maxlen);
		return 1;
	}
	char *szProto = (char*)proto;
	char tmp[FLD_SIZE];
	wchar_t name[NAME_SIZE]; name[0] = 0;
	if (hContact && (!proto || !proto[0]))
		if (!db_get_static(hContact, "Protocol", "p", tmp, _countof(tmp)))
			szProto = tmp;
	for (int i = 0; i < NAMEORDERCOUNT - 1; i++) {
		switch (nameOrder[i]) {
		case 0: // custom name
			GetValueW(hContact, "CList", "MyHandle", name, _countof(name));
			break;
		case 1: // nick
			if (!szProto) break;
			GetValueW(hContact, szProto, "Nick", name, _countof(name));
			break;
		case 2: // First Name
			// if (!szProto) break;
			// GetValueW(hContact, szProto, "FirstName", name, _countof(name));
			break;
		case 3: // E-mail
			if (!szProto) break;
			GetValueW(hContact, szProto, "e-mail", name, _countof(name));
			break;
		case 4: // Last Name
			// GetValueW(hContact, szProto, "LastName", name, _countof(name));
			break;
		case 5: // Unique id
			if (szProto) {
				// protocol must define a PFLAG_UNIQUEIDSETTING
				const char *uid = Proto_GetUniqueId(szProto);
				if (uid)
					GetValueW(hContact, szProto, uid, name, _countof(name));
			}
			break;
		case 6: // first + last name
			if (szProto) {
				GetValueW(hContact, szProto, "FirstName", name, _countof(name));
				int len = (int)mir_wstrlen(name);
				if (len + 2 < _countof(name)) {
					if (len)
						mir_wstrncat(name, L" ", _countof(name));
					len++;
					GetValueW(hContact, szProto, "LastName", &name[len], _countof(name) - len);
				}
			}
			break;
		}
		if (name[0])
			break;
	}
	if (!name[0])
		mir_wstrncpy(name, TranslateT(""), _countof(name));
	if (szProto && szProto[0]) {
		if (g_Order)
			mir_snwprintf(value, maxlen, L"(%S) %s", szProto, name);
		else
			mir_snwprintf(value, maxlen, L"%s (%S)", name, szProto);
	}
	else mir_wstrncpy(value, name, maxlen);
	PROTOACCOUNT *pa = Proto_GetAccount(szProto);
	if (!pa->IsEnabled()) {
		mir_wstrncat(value, L" ", maxlen);
		mir_wstrncat(value, TranslateT("[UNLOADED]"), maxlen);
	}
	return 1;
}
int ApplyProtoFilter(MCONTACT hContact)
{
	if (g_Mode == MODE_ALL)	return 0;
	int loaded = 0;
	char szProto[FLD_SIZE];
	if (!db_get_static(hContact, "Protocol", "p", szProto, _countof(szProto)))
		loaded = Proto_GetAccount(szProto) ? 1 : 0;
	if ((loaded && g_Mode == MODE_UNLOADED) || (!loaded && g_Mode == MODE_LOADED))
		return 1;
	return 0;
}
void loadListSettings(HWND hwnd, ColumnsSettings *cs)
{
	LVCOLUMN sLC = {};
	sLC.fmt = LVCFMT_LEFT;
	sLC.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
	int i = 0;
	while (cs[i].name) {
		sLC.pszText = TranslateW(cs[i].name);
		sLC.cx = g_plugin.getWord(cs[i].dbname, cs[i].defsize);
		ListView_InsertColumn(hwnd, cs[i].index, &sLC);
		i++;
	}
}
void saveListSettings(HWND hwnd, ColumnsSettings *cs)
{
	char tmp[FLD_SIZE];
	LVCOLUMN sLC = {};
	sLC.mask = LVCF_WIDTH;
	int i = 0;
	while (cs[i].name) {
		if (ListView_GetColumn(hwnd, cs[i].index, &sLC)) {
			mir_snprintf(tmp, cs[i].dbname, i);
			g_plugin.setWord(tmp, (WORD)sLC.cx);
		}
		i++;
	}
}
INT_PTR CALLBACK ColumnsCompare(LPARAM lParam1, LPARAM lParam2, LPARAM myParam)
{
	ColumnsSortParams params = *(ColumnsSortParams *)myParam;
	const int maxSize = 1024;
	wchar_t text1[maxSize];
	wchar_t text2[maxSize];
	ListView_GetItemText(params.hList, lParam1, params.column, text1, _countof(text1));
	ListView_GetItemText(params.hList, lParam2, params.column, text2, _countof(text2));
	int res = mir_wstrcmpi(text1, text2);
	return (params.column == params.last) ? -res : res;
}