#include "headers.h"

CClistProxyWindow *g_clistProxyWnd = 0;
extern ITaskbarList3 *g_pTaskbarList;

CClistProxyWindow::CClistProxyWindow() : m_overlayEvents(5)
{
	g_clistProxyWnd = this;

	m_activeOverlay = 0;
	m_overlayIcon = 0;
	m_overlayText = 0;

	SetWindowText(hwnd(), _T("Miranda IM"));
	SendMessage(hwnd(), WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIcon(SKINICON_OTHER_MIRANDA));
	SendMessage(hwnd(), WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(SKINICON_OTHER_MIRANDA));

	SetEventHook(ME_CLIST_STATUSMODECHANGE, &CClistProxyWindow::OnStatusModeChanged);
	SetEventHook(ME_AV_MYAVATARCHANGED, &CClistProxyWindow::OnAvatarChanged);
	SetEventHook(ME_SYSTEM_MODULESLOADED, &CClistProxyWindow::OnModulesLoaded);
	SetEventHook(ME_PROTO_ACCLISTCHANGED, &CClistProxyWindow::OnAccListChanged);

	SetTimer(1, 500);
}

CClistProxyWindow::~CClistProxyWindow()
{
	KillObjectEventHooks(this);
}

int __cdecl CClistProxyWindow::OnStatusModeChanged(WPARAM wParam, LPARAM lParam)
{
	Update();
	return 0;
}
int __cdecl CClistProxyWindow::OnAvatarChanged(WPARAM wParam, LPARAM lParam)
{
	Update();
	return 0;
}
int __cdecl CClistProxyWindow::OnModulesLoaded(WPARAM wParam, LPARAM lParam)
{
	Update();
	return 0;
}
int __cdecl CClistProxyWindow::OnAccListChanged(WPARAM wParam, LPARAM lParam)
{
	Update();
	return 0;
}

HANDLE CClistProxyWindow::SetEventHook(char *evt, int (__cdecl CClistProxyWindow::*fn)(WPARAM, LPARAM))
{
	return HookEventObj(evt, *(MIRANDAHOOKOBJ *)&fn, this);
}

void CClistProxyWindow::Flash()
{
	FlashWindow(hwnd(), TRUE);
}

void CClistProxyWindow::SetOverlayIcon(HICON hIcon)
{
	m_overlayIcon = hIcon;
	m_overlayIconHandle = 0;
}

void CClistProxyWindow::SetOverlayIconHandle(HANDLE hIcolibIcon)
{
	m_overlayIcon = 0;
	m_overlayIconHandle = hIcolibIcon;
}

void CClistProxyWindow::AddOverlayEvent(int idx)
{
	m_overlayEvents[idx].Push();
}

void CClistProxyWindow::RemoveOverlayEvent(int idx)
{
	m_overlayEvents[idx].Pop();
}

int CClistProxyWindow::AllocateOverlayEvent(HANDLE hIcolibIcon)
{
	m_overlayEvents.insert(new COverlayEventSlot(hIcolibIcon, _T("")), m_overlayEvents.getCount());
	return m_overlayEvents.getCount() - 1;
}

void CClistProxyWindow::Update()
{
	AddButton(LoadSkinnedIcon(SKINICON_OTHER_MIRANDA), TranslateT("Menu"), -1);

	int nAccounts = 0;
	PROTOACCOUNT **accounts;
	ProtoEnumAccounts(&nAccounts, &accounts);
	for (int i = 0; i < nAccounts; ++i)
	{
		if (!accounts[i]->bIsEnabled || !accounts[i]->bIsVisible || !accounts[i]->ppro || !(accounts[i]->ppro->GetCaps(PFLAGNUM_1) & PF1_IM))
			continue;

		HICON hIcon = LoadSkinnedProtoIcon(accounts[i]->szModuleName, CallProtoService(accounts[i]->szModuleName, PS_GETSTATUS, 0, 0));
		AddButton(hIcon, accounts[i]->tszAccountName, (INT_PTR)accounts[i]->tszAccountName);
	}
	UpdateButtons(g_pTaskbarList);

	InvalidateThumbnail();
}

void CClistProxyWindow::OnActivate(HWND hwndFrom)
{
	CallService(MS_CLIST_SHOWHIDE, 0, 0);

	HWND hwndClui = (HWND)CallService(MS_CLUI_GETHWND, 0, 0);
	if (hwndFrom != hwndClui && !IsIconic(hwndClui) && IsWindowVisible(hwndClui))
		SetForegroundWindow(hwndClui);
	else
		SetForegroundWindow(NULL);
}

void CClistProxyWindow::OnToolbar(int id, INT_PTR data)
{
	POINT pt; GetCursorPos(&pt);
	HMENU hMenu = NULL;
	HWND hwndClui = (HWND)CallService(MS_CLUI_GETHWND, 0, 0);

	switch (data)
	{
		case -1:
		{
			hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDMAIN, 0, 0);
			break;
		}

		default:
		{
			hMenu = (HMENU)CallService(MS_CLIST_MENUGETSTATUS, 0, 0);
			int nItems = GetMenuItemCount(hMenu);
			for (int i = 0; i < nItems; ++i)
			{
				TCHAR buf[128];
				MENUITEMINFO mii = {0};
				mii.cbSize = sizeof(mii);
				mii.fMask = MIIM_STRING|MIIM_SUBMENU;
				mii.dwTypeData = buf;
				mii.cch = SIZEOF(buf);
				GetMenuItemInfo(hMenu, i, TRUE, &mii);

				if (mii.hSubMenu && !lstrcmp(mii.dwTypeData, (TCHAR*)data))
				{
					hMenu = mii.hSubMenu;
					break;
				}
			}
		}
	}

	SetForegroundWindow(hwndClui);
	TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hwndClui, NULL);
}

void CClistProxyWindow::OnRenderThumbnail(int width, int height)
{
	HBITMAP hbmp = CreateDwmBitmap(width, height);
	HDC hdc = CreateCompatibleDC(0);
	SelectObject(hdc, hbmp);

	RGBQUAD rgb0, rgb1;
	rgb0.rgbRed =  0; rgb0.rgbGreen =  0; rgb0.rgbBlue =  0;
	rgb1.rgbRed = 19; rgb1.rgbGreen = 58; rgb1.rgbBlue = 89;
	DrawGradient(hdc, 0, 0, width, height, &rgb0, &rgb1);

	HFONT hfntSave = (HFONT)SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
	SetTextColor(hdc, RGB(255, 255, 255));
	SetBkMode(hdc, TRANSPARENT);

	RECT rc;
	SIZE sz;
	SetRect(&rc, 5, 5, width-10, height-10);

	int avatarWidth = 0;
	int avatarHeight = 0;
	if (true)
	{
		AVATARCACHEENTRY *ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM)"");
		if (ace && (ace != (AVATARCACHEENTRY *)CALLSERVICE_NOTFOUND))
		{
			if (ace->bmWidth < width / 4)
			{
				avatarWidth = ace->bmWidth;
				avatarHeight = ace->bmHeight;
			} else
			{
				avatarWidth = width / 4;
				avatarHeight = avatarWidth * ace->bmHeight / ace->bmWidth;
			}

			AVATARDRAWREQUEST avdr = {0};
			avdr.cbSize = sizeof(avdr);
			avdr.hContact = NULL;
			avdr.hTargetDC = hdc;
			avdr.rcDraw = rc;
			avdr.rcDraw.bottom = avdr.rcDraw.top + avatarHeight;
			avdr.rcDraw.right = avdr.rcDraw.left + avatarWidth;
			avdr.dwFlags = AVDRQ_FALLBACKPROTO | AVDRQ_FORCEALPHA | AVDRQ_OWNPIC;
			avdr.szProto = "";

			avdr.alpha = 255;
			CallService(MS_AV_DRAWAVATAR, 0, (LPARAM)&avdr);

			rc.left += avatarWidth + 5;
		}
	}

	int nAccounts = 0;
	PROTOACCOUNT **accounts;
	ProtoEnumAccounts(&nAccounts, &accounts);
	for (int i = 0; i < nAccounts; ++i)
	{
		if (!accounts[i]->bIsEnabled /*|| !accounts[i]->ppro || !(accounts[i]->ppro->GetCaps(PFLAGNUM_1) & PF1_IM)*/)
			continue;

		char *proto = accounts[i]->szModuleName;

		if (true)
		{
			TCHAR name[128]; name[0] = 0;

			CONTACTINFO ci = {0};
			ci.cbSize = sizeof(ci);
			ci.hContact = NULL;
			ci.szProto = proto;
			ci.dwFlag = CNF_UNIQUEID | CNF_TCHAR;
			if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM)&ci))
			{
				switch (ci.type)
				{
					case CNFT_ASCIIZ:
						mir_sntprintf(name, SIZEOF(name), _T("%s - %s"), accounts[i]->tszAccountName, ci.pszVal);
						mir_free((void *)ci.pszVal);
						break;
					case CNFT_DWORD:
						mir_sntprintf(name, SIZEOF(name), _T("%s - %u"), accounts[i]->tszAccountName, ci.dVal);
						break;
				}

			} else
			{
				lstrcpyn(name, accounts[i]->tszAccountName, SIZEOF(name));
			}

			RECT rcText = rc;
			rcText.left += 20;
			DrawText(hdc, name, -1, &rcText, DT_LEFT|DT_NOPREFIX|DT_WORDBREAK|DT_TOP|DT_SINGLELINE);
			GetTextExtentPoint32(hdc, name, lstrlen(name), &sz);
		}

		if (true)
		{
			HICON hIcon = LoadSkinnedProtoIcon(proto, CallProtoService(proto, PS_GETSTATUS, 0, 0));
			DrawIconEx(hdc, rc.left, rc.top + (sz.cy - 16) / 2, hIcon, 16, 16, 0, NULL, DI_NORMAL);
		}

		rc.top += sz.cy + 5;
	}

	SelectObject(hdc, hfntSave);

	DeleteDC(hdc);
	MakeBitmapOpaque(hbmp);
	SetThumbnail(hbmp);
	DeleteObject(hbmp);
}

void CClistProxyWindow::OnClose()
{
	CallService("CloseAction", NULL, NULL);
}

void CClistProxyWindow::OnTimer(int id)
{
	HANDLE hIcolibItem = m_overlayIconHandle;
	for (m_activeOverlay = (m_activeOverlay + 1) % (m_overlayEvents.getCount() + 1); m_activeOverlay < m_overlayEvents.getCount(); ++m_activeOverlay)
		if (m_overlayEvents[m_activeOverlay])
		{
			hIcolibItem = m_overlayEvents[m_activeOverlay].GetIcon();
			break;
		}

	HICON hIcon = hIcolibItem ? (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)hIcolibItem) : m_overlayIcon;
	if (hIcon) g_pTaskbarList->SetOverlayIcon(hwnd(), hIcon, L"");
}