#include <windows.h>
#include <commctrl.h>
#include <TCHAR.H>
#include <SWI-Prolog.h>

#include "resource.h"
#include "defs.h"

HWND HElv;
LPLVITEM LpLviElvSelection;	/* Most recently selected episode. */

HWND
ElvCreate()
{
	LVCOLUMN lvc;
	term_t t;

	LpLviElvSelection = malloc(sizeof(LVITEM));
	if (!LpLviElvSelection) return NULL;
	HElv = LvCreate((HMENU)IDC_EPISODELISTVIEW);

	lvc.mask = LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM;
	lvc.iSubItem = 0;
	lvc.pszText = TEXT("#");
	lvc.cx = Dpi(42);
	ListView_InsertColumn(HElv, 0, &lvc);

	lvc.iSubItem = 1;
	lvc.pszText = TEXT("Title");
	lvc.cx = 500;
	ListView_InsertColumn(HElv, 1, &lvc);

	t = T(0);
	P("track_episodes","update_tracked_episodes",0,t);
	ElvUpdate();
	ElvSelectRecent();
	return HElv;
}

LRESULT
ElvHandleNotify(LPARAM lParam)
{
	LPNMLISTVIEW lpNmLv;
	lpNmLv = (LPNMLISTVIEW)lParam;

	switch (lpNmLv->hdr.code) {
	case LVN_ITEMCHANGED:
		if ((lpNmLv->uChanged & LVIF_STATE) &&
		    (lpNmLv->uNewState & LVIS_FOCUSED)) {
			LpLviElvSelection->iItem = lpNmLv->iItem;
			LpLviElvSelection->lParam = lpNmLv->lParam;
			ElvUpdateName(LpLviElvSelection);
			DlvShowEpisode(lpNmLv->lParam);
		}
		break;
	case NM_CUSTOMDRAW:	/* Make unwatched episodes bold. */
	    {
		LPNMLVCUSTOMDRAW lpLvCd;
		lpLvCd = (LPNMLVCUSTOMDRAW)lParam;
		switch (lpLvCd->nmcd.dwDrawStage) {
		case CDDS_PREPAINT:
			return CDRF_NOTIFYITEMDRAW;
			break;
		case CDDS_ITEMPREPAINT:
		    {
			term_t t;
			extern HFONT HfBold;
			t = T(1);
			PI(t,lpLvCd->nmcd.lItemlParam) break;
			P("track_episodes","watched",1,t) {
				SelectObject(lpLvCd->nmcd.hdc, HfBold);
				return CDRF_NEWFONT;
			}
			break;
		    }
		}
		break;
	    }
	case NM_DBLCLK:		/* Open clicked episode. */
	    {
		term_t t;
		t = T(1);
		PI(t,LpLviElvSelection->lParam) break;
		P("local_episodes","open_episode",1,t);
		break;
	    }
	case NM_RETURN:		/* Open all selected episodes. */
	    {
		LVITEM lvi;
		term_t t;
		extern HWND HElv;
		lvi.mask = LVIF_PARAM;
		lvi.iItem = -1;
		t = T(1);
		while ((lvi.iItem = ListView_GetNextItem(
			    HElv, lvi.iItem, LVNI_SELECTED)) != -1) {
			if (!ListView_GetItem(HElv, &lvi)) goto b;
			PI(t,lvi.lParam) goto b;
			P("local_episodes","open_episode",1,t);
		}
	    b:	break;
	    }
	case NM_RCLICK:
	    {
		DWORD dwPos;
		extern HWND HWnd;
		extern HMENU HPopupMenu;
		dwPos = GetMessagePos();
		TrackPopupMenu(HPopupMenu, TPM_RIGHTBUTTON,
		    LOWORD(dwPos), HIWORD(dwPos), 0,
		    HWnd, NULL);
		break;
	    }
	}

	return 0;
}
void
ElvRedraw()
{
	RedrawWindow(HElv, NULL, NULL,
	    RDW_ERASE|RDW_FRAME|RDW_INVALIDATE|RDW_ALLCHILDREN);
}

void
ElvSetTop(int iItem)
{
	int iLast;
	iLast = ListView_GetItemCount(HElv)-1;
	ListView_EnsureVisible(HElv, iLast, TRUE);
	ListView_EnsureVisible(HElv, iItem, TRUE);
}

/* Select most recent episode. */
void
ElvSelectRecent()
{
	int iEpisode, iItem;
	LVFINDINFO lvfi;
	term_t t;

	t = T(1);
	iItem = 0;
	P("track_episodes","most_recently_watched",1,t) goto s;
	GI(t,&iEpisode) return;

	lvfi.flags = LVFI_PARAM;
	lvfi.lParam = iEpisode;

	iItem = ListView_FindItem(HElv, -1, &lvfi);
	if (iItem == -1) return;

s:	ElvSetTop(iItem > 5? iItem-5: 0);
	ListView_SetItemState(HElv, iItem,
	    LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
	LpLviElvSelection->iItem = iItem;
	LpLviElvSelection->lParam = iEpisode;
	ElvUpdateName(LpLviElvSelection);
	DlvShowEpisode(iEpisode);
}

/* Update episode list. */
void
ElvUpdate()
{
	int iLast, iTop;
	LVITEM lviEpisode, lviName;
	term_t t;

	SendMessage(HElv, WM_SETREDRAW, FALSE, 0);
	iTop = ListView_GetTopIndex(HElv);
	ListView_DeleteAllItems(HElv);

	lviEpisode.mask = LVIF_TEXT|LVIF_PARAM;
	lviName.mask = LVIF_TEXT;

	t = T(1);
	P("episode_data","last_episode",1,t) return;
	GI(t,&iLast) return;

	for (int i = 0; i < iLast; i++) {
		char *szName;
		int cb;
		TCHAR *tszEpisode, *tszName;
		term_t t2;

		/* Format name string. */

		t2 = T(3);
		PI(t2,i+1) return;
		tszName = NULL;
		P("episode_data","lookup_episode_local",3,t2) goto ep;
		GAC(t2+1,&szName) goto ep;
		tszName = TszFromSz(szName, CP_UTF8);
		if (!tszName) return;

		/* Format episode number string. */
	ep:    	cb = 100;
		tszEpisode = malloc(cb*sizeof(TCHAR));
		if (!tszEpisode) goto e;
		_stprintf_s(tszEpisode, cb, TEXT("%d"), i+1);

		/* Insert item. */

		lviEpisode.iItem = i;
		lviEpisode.iSubItem = 0;
		lviEpisode.pszText = tszEpisode;
		lviEpisode.lParam = i+1;
		ListView_InsertItem(HElv, &lviEpisode);

		if (tszName) {
			lviName.iItem = i;
			lviName.iSubItem = 1;
			lviName.pszText = tszName;
			ListView_SetItem(HElv, &lviName);
		}

		free(tszEpisode);
	e:     	if (tszName) free(tszName);
	}

	/* Reset selection and scrolling position. */

	ElvSetTop(iTop);
	if (LpLviElvSelection)
		ListView_SetItemState(HElv, LpLviElvSelection->iItem,
		    LVIS_SELECTED, LVIS_SELECTED);

	SendMessage(HElv, WM_SETREDRAW, TRUE, 0);
	ElvRedraw();
}

/* Update episode name. */
void
ElvUpdateName(LPLVITEM lpLvi)
{
	char *szName;
	TCHAR *tszName;
	term_t t;

	t = T(3);
	PI(t,lpLvi->lParam) return;
	P("episode_data","lookup_episode",3,t) return;
	GAC(t+1,&szName) return;

	tszName = TszFromSz(szName, CP_UTF8);
	if (!tszName) return;

	ListView_SetItemText(HElv, lpLvi->iItem, 1, tszName);
}