#include "PrefList.h"

#include <stdio.h>
#include <string.h>

#include "WimpLib:Choices.h"
#include "WimpLib:Desktop.h"
#include "WimpLib:DragDrop.h"
#include "WimpLib:Exception.h"
#include "WimpLib:Keyboard.h"
#include "WimpLib:mem.h"
#include "WimpLib:Message.h"
#include "WimpLib:Task.h"
#include "WimpLib:Template.h"
#include "WimpLib:Window.h"
#include "WimpLib:Utils.h"

#include "Cmds.h"
#include "CmdList.h"
#include "DigitalCD.h"
#include "Options.h"
#include "DocEvents.h"

#define Icon_PrefList   0
#define Icon_Originals  1
#define Icon_Add        2
#define Icon_Delete     3
#define Icon_Clear      4
#define Icon_Init       5

static const char pref_section[] = "Preference List";

static const MouseShape ptr_move = {"ptr_move", 0, 0};
static const MouseShape ptr_copy = {"ptr_copy", 0, 0};
static const MouseShape ptr_music = {"ptr_music", 0, 0};

struct CPrefList
{
	HWind   m_wnd;
	CDDesc* m_pDesc;
	WList   m_Originals;
	WList   m_PrefList;
	bool    m_bModified;
	bool    m_bDragPref;
};

static const char* PrefList_GetItemText(void* pHandle, const void* pItem)
{
	const CDTrack* pTrack = pItem;

	// Stop warnings
	IGNORE(pHandle);

	return CDTrack_GetLabel(pTrack);
}

static void PrefList_AddOriginals(CPrefList* This, int Pos)
{
	int i;
	bool bAdd = false;

	WList_AllowRefresh(&This->m_PrefList, false);

	try
	{
		for(i = 0; i < WList_Count(&This->m_Originals); i++)
		{
			if (WList_GetItemState(&This->m_Originals, i) & EWItem_Selected)
			{
				CDTrack* pTrack = WList_Get(&This->m_Originals, i);
				throw_WList_Insert(&This->m_PrefList, Pos, pTrack);
				Pos++;
				bAdd = true;
			}
		}
	}
	catch
	{
		App_ReportException();
	}
	catch_end

	WList_AllowRefresh(&This->m_PrefList, true);

	if (bAdd)
		PrefList_SetModified(This, true);
}

static void PrefWList_Selection_Copy(CPrefList* This, int Pos)
{
	int i;
	bool bAdd = false;
	int At;
	WList* pList = &This->m_PrefList;

	if (Pos > WList_Count(pList)) return;
	if (Pos < 0) Pos = WList_Count(pList);

	At = Pos;

	WList_AllowRefresh(pList, false);

	try
	{
		// First treat items before insertion point

		// Copy selected items at insertion point, select copies
		for(i = 0; (i < WList_Count(pList)) && (i < Pos); i++)
		{
			if (WList_GetItemState(pList, i) & EWItem_Selected)
			{
				CDTrack* pTrack = WList_Get(pList, i);
				throw_WList_Insert(pList, At, pTrack);
				At++;
				bAdd = true;
			}
		}

		// Move selected items after insertion point.
		// Insertion point moves according to the insertions
		for(i = Pos; i < WList_Count(pList); i++)
		{
			if (WList_GetItemState(pList, i) & EWItem_Selected)
			{
				CDTrack* pTrack = WList_Get(pList, i);
				throw_WList_Insert(pList, Pos, pTrack);
				Pos++;
				i++;
				bAdd = true;
			}
		}
	}
	catch
	{
		App_ReportException();
	}
	catch_end

	WList_AllowRefresh(pList, true);

	if (bAdd)
		PrefList_SetModified(This, true);
}

static void PrefWList_Selection_Move(CPrefList* This, int Pos)
{
	int i;
	bool bAdd = false;
	int At;
	WList* pList = &This->m_PrefList;

	if (Pos > WList_Count(pList)) return;
	if (Pos < 0) Pos = WList_Count(pList);

	At = Pos;

	WList_AllowRefresh(pList, false);

	try
	{
		// First treat items before insertion point

		// Copy selected items at insertion point, select copies
		for(i = 0; (i < WList_Count(pList)) && (i < Pos); i++)
		{
			if (WList_GetItemState(pList, i) & EWItem_Selected)
			{
				CDTrack* pTrack = WList_Get(pList, i);
				throw_WList_Insert(pList, At, pTrack);
				WList_SetItemState(pList, At, EWItem_Selected, EWItem_Selected);
				At++;
				bAdd = true;
			}
		}

		// Remove selected items
		for(i--; i >= 0; i--)
		{
			if (WList_GetItemState(pList, i) & EWItem_Selected)
				WList_Del(pList, i);
		}

		// Skip selected items already in good position
		for(; (Pos < WList_Count(pList)) && (WList_GetItemState(pList, Pos) & EWItem_Selected); Pos++)
			;

		// Move selected items after insertion point.
		// Insertion point moves according to the insertions
		for(i = Pos; i < WList_Count(pList); i++)
		{
			if (WList_GetItemState(pList, i) & EWItem_Selected)
			{
				CDTrack* pTrack = WList_Get(pList, i);
				throw_WList_Insert(pList, Pos, pTrack);
				WList_SetItemState(pList, Pos, EWItem_Selected, EWItem_Selected);
				Pos++;
				WList_Del(pList, i + 1);
				bAdd = true;
			}
		}
	}
	catch
	{
		App_ReportException();
	}
	catch_end

	WList_AllowRefresh(pList, true);

	if (bAdd)
		PrefList_SetModified(This, true);
}

static void PrefWList_Selection_Delete(CPrefList* This)
{
	int i;
	bool bDel = false;
	WList* pList = &This->m_PrefList;

	WList_AllowRefresh(pList, false);

	for(i = WList_Count(pList) - 1; i >= 0; i--)
	{
		if (WList_GetItemState(pList, i) & EWItem_Selected)
		{
			WList_Del(pList, i);
			bDel = true;
		}
	}

	WList_AllowRefresh(pList, true);

	if (bDel)
		PrefList_SetModified(This, true);
}

static void PrefWList_RemoveAll(CPrefList* This)
{
	int i;
	WList* pList = &This->m_PrefList;

	if (WList_Count(pList) <= 0) return;

	WList_AllowRefresh(pList, false);

	for(i = WList_Count(pList) - 1; i >= 0; i--)
	{
		WList_Del(pList, i);
	}

	WList_AllowRefresh(pList, true);

	PrefList_SetModified(This, true);
}

static void PrefList_Init(CPrefList* This)
{
	int i;

	PrefWList_RemoveAll(This);

	if (WList_Count(&This->m_Originals) <= 0) return;

	WList_AllowRefresh(&This->m_PrefList, false);

	try
	{
		for(i = 0; i < WList_Count(&This->m_Originals); i++)
		{
			CDTrack* pTrack = WList_Get(&This->m_Originals, i);
			throw_WList_Insert(&This->m_PrefList, -1, pTrack);
		}
	}
	catch
	{
		App_ReportException();
	}
	catch_end

	WList_AllowRefresh(&This->m_PrefList, true);

	PrefList_SetModified(This, true);
}

static int PrefList_CheckCommand(void* handle, CmdID id)
{
	CPrefList* This = handle;
	int state = 0;

	switch(id)
	{
		case Cmd_CD_Pref_Insert:
		case Cmd_CD_Orig_Clear:
		{
			if (WList_FindItemState(&This->m_Originals, 0, EWItem_Selected, EWItem_Selected) >= 0)
				state |= ECmdState_Allow;
		}
		break;
		case Cmd_CD_Pref_Delete:
		case Cmd_CD_Pref_Clear:
		{
			if (WList_FindItemState(&This->m_PrefList, 0, EWItem_Selected, EWItem_Selected) >= 0)
				state |= ECmdState_Allow;
		}
		break;
		case Cmd_CD_Pref_Initialize:
		{
			state |=  ECmdState_Allow;
		}
		break;
		case Cmd_CD_Pref_DeleteAll:
		case Cmd_CD_Pref_SelectAll:
		{
			if (WList_Count(&This->m_PrefList) > 0)
				state |= ECmdState_Allow;
		}
		break;
		case Cmd_CD_Orig_SelectAll:
		{
			if (WList_Count(&This->m_Originals) > 0)
				state |= ECmdState_Allow;
			return state;
		}
		break;
		default:
			return App_CheckCommand(handle, id);;
	}

	return state;
}

static bool PrefList_ExecCommand(void* handle, CmdID id)
{
	CPrefList* This = handle;

	switch(id)
	{
		case Cmd_CD_Pref_Insert:
		{
			PrefList_AddOriginals(This, WList_Count(&This->m_PrefList));
		}
		break;
		case Cmd_CD_Pref_Delete:
		{
			PrefWList_Selection_Delete(This);
		}
		break;
		case Cmd_CD_Pref_Initialize:
		{
			PrefList_Init(This);
		}
		break;
		case Cmd_CD_Pref_DeleteAll:
		{
			PrefWList_RemoveAll(This);
		}
		break;
		case Cmd_CD_Pref_SelectAll:
		{
			WList_SetItemsState(&This->m_PrefList, EWItem_Selected, EWItem_Selected, 0, 0);
		}
		break;
		case Cmd_CD_Pref_Clear:
		{
			WList_SetItemsState(&This->m_PrefList, 0, EWItem_Selected, EWItem_Selected, EWItem_Selected);
		}
		break;
		case Cmd_CD_Orig_SelectAll:
		{
			WList_SetItemsState(&This->m_Originals, EWItem_Selected, EWItem_Selected, 0, 0);
		}
		break;
		case Cmd_CD_Orig_Clear:
		{
			WList_SetItemsState(&This->m_Originals, 0, EWItem_Selected, EWItem_Selected, EWItem_Selected);
		}
		break;
		default:
			return App_ExecCommand(NULL, id);
	}

	return true;
}

static CmdHandler PrefList_CmdHandler =
{ PrefList_CheckCommand
, PrefList_ExecCommand
};

static bool PrefWList_OnDragging(void* handle, const Msg_Dragging* rcv)
{
	CPrefList*	This = handle;
	WList*		pList = &This->m_PrefList;
	int		flags;
	bool		bRelease = false;
	bool		bMove = false;

	// If we are not within work area of our own window
	// we must hide the ghost caret we could be showing
	// and return that the message is not for us.
	if (DragDrop_GetUserHandle() == pList)
	{
		if (rcv->pos.w == WList_GetWindow(pList))
			bMove = !Keyboard_PollShift();
		else
			bRelease = true;
	}
	else if (DragDrop_GetUserHandle() == &This->m_Originals)
	{
		if (rcv->pos.w == WList_GetWindow(pList))
			bMove = false;
		else
			bRelease = true;
	}
	else
		bRelease = true;

	if (bRelease
	||  (rcv->pos.i != HIcon_None)
	||  (rcv->flags & DragFlags_DoNotClaim))
	{
		WList_HideGhostCaret(pList);
		return false;
	}

	if (bMove)
		Desktop_SetPointer(&ptr_move);
	else
		Desktop_SetPointer(&ptr_copy);

	// Show ghost caret
	WList_ShowGhostCaret(pList, &rcv->pos.pt);

	Window_ScrollIfMouseOnBorder(rcv->pos.w, 0, 40);

	// Reply to message
	flags = ClaimFlags_PointerChange | ClaimFlags_RemoveDragBox;
	if (bMove) flags |= ClaimFlags_DeleteSource;

	DragDrop_ReplyToDragging(rcv, flags, NULL, NULL, NULL);

	return true;
}

static EListenerAction PrefWList_EventHandler(void* handle, const Event* e)
{
	CPrefList* This = handle;
	WList* pList = &This->m_PrefList;

	switch(e->Type)
	{
		case EEvent_Mouse:
		{
			const Mouse* m = e->pData;

			switch(m->but)
			{
				case EBut_Menu:
				{
					CmdHandler_OpenMenu(&PrefList_CmdHandler, handle, "CD_Pref");

					return EListenerAction_StopEvent;
				}
				break;
				case EBut_DragSelect:
				{
					int item = WList_ItemFromScreenPt(pList, &m->pt, EWListPtrMode_Hover);

					if (WList_GetItemState(pList, item) & EWItem_Selected)
					{
						DragDrop_Info Info;

						Info = ActiveDrag_DragPoint(pList, &Task_GetModeInfo()->box, &ptr_music);
						if (Info.task == Task_GetId())
						{
							m = Mouse_Get();

							if (m->w == WList_GetWindow(pList))
							{
								int Pos = WList_ItemFromScreenPt(pList, &m->pt, EWListPtrMode_Insert);

								if (Info.flags & ClaimFlags_DeleteSource)
									PrefWList_Selection_Move(This, Pos);
								else
									PrefWList_Selection_Copy(This, Pos);
							}
							else if (m->w == WList_GetWindow(&This->m_Originals))
								PrefWList_Selection_Delete(This);
						}
					}
					return EListenerAction_StopEvent;
				}
				break;
			}
		}
		break;
		case EEvent_Key:
		{
			int code = ((Event_Key*) e->pData)->code;

			if (CmdHandler_KeyPressed(&PrefList_CmdHandler, This, "CD_Pref", code))
				return EListenerAction_StopEvent;

			switch(code)
			{
				case 0x181: // F1
				{
					App_StrongHelp("CDs_Prefs");
					return EListenerAction_StopEvent;
				}
				break;
				case 0x18a: // Tab
				case 0x19a: // Shift-Tab
					Caret_SetInvisible(WList_GetWindow(&This->m_Originals));
					return EListenerAction_StopEvent;
				break;
			}
		}
		break;
		case EEvent_Message:
		case EEvent_MessageWantAck:
		{
			switch(((Msg*) e->pData)->hdr.action)
			{
				case EMsg_Dragging: // Drag & drop Message_Dragging
				{
					// If we accept the message, it adds a PreEventHandler
					// to ensure that only our OnDragging handles the
					// following Message_Dragging messages.
					if (DragDrop_SetOnDraggingCallback(e->pData, PrefWList_OnDragging, This))
						return EListenerAction_StopEvent;
				}
				break;
				case EMsg_HelpRequest:
				{
					const Msg_HelpRequest* msg = e->pData;

					Task_HelpReply(msg, Msg_Lookup("PrLi1H"));
					return EListenerAction_StopEvent;
				}
				break;
			}
		}
		break;
	}

	return EListenerAction_ContinueEvent;
}

static bool OrzWList_OnDragging(void* handle, const Msg_Dragging* rcv)
{
	CPrefList*	This = handle;
	WList* pList = &This->m_Originals;
	int		flags;

	// If we are not within work area of our own window
	// we must hide the ghost caret we could be showing
	// and return that the message is not for us.
	if ((DragDrop_GetUserHandle() != &This->m_PrefList)
	||  (rcv->pos.w != WList_GetWindow(pList))
	||  (rcv->pos.i != HIcon_None)
	||  (rcv->flags & DragFlags_DoNotClaim))
		return false;

	Desktop_SetPointer(&ptr_move);

	// Do not show ghost caret, do not scroll

	// Reply to message
	flags = ClaimFlags_PointerChange | ClaimFlags_RemoveDragBox;

	DragDrop_ReplyToDragging(rcv, flags, NULL, NULL, NULL);

	return true;
}

static EListenerAction OrzWList_EventHandler(void* handle, const Event* e)
{
	CPrefList* This = handle;
	WList* pList = &This->m_Originals;

	switch(e->Type)
	{
		case EEvent_Mouse:
		{
			const Mouse* m = e->pData;

			switch(m->but)
			{
				case EBut_Menu:
				{
					CmdHandler_OpenMenu(&PrefList_CmdHandler, handle, "CD_Orig");

					return EListenerAction_StopEvent;
				}
				break;
				case EBut_DragSelect:
				{
					int item = WList_ItemFromScreenPt(pList, &m->pt, EWListPtrMode_Hover);

					if (WList_GetItemState(pList, item) & EWItem_Selected)
					{
						DragDrop_Info Info;

						Info = ActiveDrag_DragPoint(pList, &Task_GetModeInfo()->box, &ptr_music);
						if (Info.task == Task_GetId())
						{
							m = Mouse_Get();

							if (m->w == WList_GetWindow(&This->m_PrefList))
							{
								int Pos = WList_ItemFromScreenPt(&This->m_PrefList, &m->pt, EWListPtrMode_Insert);

								PrefList_AddOriginals(This, Pos);
							}
						}
					}
					return EListenerAction_StopEvent;
				}
				break;
			}
		}
		break;
		case EEvent_Key:
		{
			int code = ((Event_Key*) e->pData)->code;

			if (CmdHandler_KeyPressed(&PrefList_CmdHandler, This, "CD_Orig", code))
				return EListenerAction_StopEvent;

			switch(code)
			{
				case 0x181: // F1
				{
					App_StrongHelp("CDs_Prefs");
					return EListenerAction_StopEvent;
				}
				break;
				case 0x18a: // Tab
				case 0x19a: // Shift-Tab
					Caret_SetInvisible(WList_GetWindow(&This->m_PrefList));
					return EListenerAction_StopEvent;
				break;
			}
		}
		break;
		case EEvent_Message:
		case EEvent_MessageWantAck:
		{
			switch(((Msg*) e->pData)->hdr.action)
			{
				case EMsg_Dragging: // Drag & drop Message_Dragging
				{
					// If we accept the message, it adds a PreEventHandler
					// to ensure that only our OnDragging handles the
					// following Message_Dragging messages.
					if (DragDrop_SetOnDraggingCallback(e->pData, OrzWList_OnDragging, This))
						return EListenerAction_StopEvent;
				}
				break;
				case EMsg_HelpRequest:
				{
					const Msg_HelpRequest* msg = e->pData;

					Task_HelpReply(msg, Msg_Lookup("PrLi0H"));
					return EListenerAction_StopEvent;
				}
				break;
			}
		}
		break;
	}

	return EListenerAction_ContinueEvent;
}

static EListenerAction PrefList_EventHandler(void* handle, const Event* e)
{
	CPrefList* This = handle;

	switch(e->Type)
	{
		case EEvent_Mouse:
		{
			const Mouse* m = e->pData;

			switch (m->i)
			{
				case Icon_Add:
				{
					CmdHandler_ExecCommand(&PrefList_CmdHandler, This, Cmd_CD_Pref_Insert);
				}
				break;
				case Icon_Delete:
				{
					CmdHandler_ExecCommand(&PrefList_CmdHandler, This, Cmd_CD_Pref_Delete);
				}
				break;
				case Icon_Clear:
				{
					CmdHandler_ExecCommand(&PrefList_CmdHandler, This, Cmd_CD_Pref_DeleteAll);
				}
				break;
				case Icon_Init:
				{
					CmdHandler_ExecCommand(&PrefList_CmdHandler, This, Cmd_CD_Pref_Initialize);
				}
				break;
			}
			return EListenerAction_StopEvent;
		}
		break;
		case EEvent_Key:
		{
			const Event_Key* key = e->pData;

			if (key->code == 0x181) // F1
			{
				App_StrongHelp("CDs_Prefs");
				return EListenerAction_StopEvent;
			}
		}
		break;
	}

	return EListenerAction_ContinueEvent;
}

void PrefList_Reload(CPrefList* This)
{
	int i;

	WList_AllowRefresh(&This->m_Originals, false);
	WList_AllowRefresh(&This->m_PrefList, false);

	WList_Clear(&This->m_PrefList);
	WList_Clear(&This->m_Originals);

	if (This->m_pDesc != NULL)
	{
		Array* pPrefList = CDDesc_GetPrefList(This->m_pDesc);

		for (i = 0; i < CDDesc_CountTracks(This->m_pDesc); i++)
			throw_WList_Insert(&This->m_Originals, -1, CDDesc_GetTrack(This->m_pDesc, i));

		for (i = 0; i < Array_Count(pPrefList); i++)
		{
			throw_WList_Insert(&This->m_PrefList, -1
				, CDDesc_GetTrack(This->m_pDesc, *(int*) Array_Get(pPrefList, i)));
		}
	}

	WList_AllowRefresh(&This->m_Originals, true);
	WList_AllowRefresh(&This->m_PrefList, true);

	PrefList_SetModified(This, false);
}

static void PrefList_RefreshText(CPrefList* This, CDTrack* pTrack)
{
	int i;

	for (i = 0; i < WList_Count(&This->m_Originals); i++)
	{
		if (WList_Get(&This->m_Originals, i) == pTrack)
			WList_Set(&This->m_Originals, i, pTrack);
	}

	for (i = 0; i < WList_Count(&This->m_PrefList); i++)
	{
		if (WList_Get(&This->m_PrefList, i) == pTrack)
			WList_Set(&This->m_PrefList, i, pTrack);
	}
}

static EListenerAction PrefList_OnDocEvent(void* pListener, const Event* pEvent)
{
	CPrefList* This = pListener;
	const DocEvent* pe = pEvent->pData;

	switch(pe->event)
	{
		case EDocEvent_UpdateElement:
		{
			PrefList_RefreshText(This, (CDTrack*) pe->pElement);
		}
		break;
	}

	return EListenerAction_ContinueEvent;
}

bool PrefList_IsModified(const CPrefList* This)
{
	return This->m_bModified;
}

void PrefList_SetModified(CPrefList* This, bool bModified)
{
	if (bModified)
	{
		// Check state
		Array* pPrefList = CDDesc_GetPrefList(This->m_pDesc);

		if (WList_Count(&This->m_PrefList) == Array_Count(pPrefList))
		{
			int i;

			for (i = Array_Count(pPrefList) - 1; i >= 0; i--)
			{
				if (WList_Get(&This->m_PrefList, i) != CDDesc_GetTrack(This->m_pDesc, *(int*) Array_Get(pPrefList, i)))
					break;
			}

			// Changed back to original list
			if (i == -1)
				bModified = false;
		}
	}

	if (This->m_bModified != bModified)
	{
		This->m_bModified = bModified;

		Window_SetTitle(This->m_wnd, "%s%s", Msg_Lookup("PrefTitle"), This->m_bModified ? " *" : "");
	}

	// Abuse doc event notification to signal change to parent
	try
	{
		DocEvent e = {EDocEvent_UpdateElement, NULL, NULL};
		DocEvents_NotifyListeners(This, &e);
	}
	catch
	{
		App_ReportException();
	}
	catch_end
}

void PrefList_GetPrefList(const CPrefList* This, Array* pPrefList)
{
	Array_Clear(pPrefList);

	for(int i = 0; i < WList_Count(&This->m_PrefList); i++)
	{
		CDTrack* pTrack = WList_Get(&This->m_PrefList, i);
		int nr = CDTrack_GetOrder(pTrack) - 1;
		Array_Insert(pPrefList, -1, &nr);
	}
}

void PrefList_Show(CPrefList* This, CDDesc* pDesc)
{
	if (This->m_pDesc != pDesc)
	{
		This->m_pDesc = pDesc;
		This->m_bModified = true;
		PrefList_SetModified(This, false);

		PrefList_Reload(This);
	}

	Window_Open(This->m_wnd);
}

void PrefList_Hide(CPrefList* This)
{
	Window_Close(This->m_wnd);

	WList_Clear(&This->m_PrefList);
	WList_Clear(&This->m_Originals);
	This->m_pDesc = NULL;
}

CPrefList* throw_New_PrefList(void)
{
	CPrefList* This = throw_mem_calloc(1, sizeof(*This));
	CTemplate* t = Templates_Find("PrefList");
	CWind* pw;
	CIcon info;
	CRect box;

	This->m_wnd = HWind_None;

	if (t == NULL) throw_string("Template 'PrefList' not found");

	pw = Template_GetWindow(t);
	box = pw->o.o.cvt.box;
	pw->o.o.cvt.box.x0 = Choices_ReadInt(pref_section, "PosX", pw->o.o.cvt.box.x0);
	pw->o.o.cvt.box.y0 = Choices_ReadInt(pref_section, "PosY", pw->o.o.cvt.box.y0);
	pw->o.o.cvt.box.x1 = pw->o.o.cvt.box.x0 + box.x1 - box.x0;
	pw->o.o.cvt.box.y1 = pw->o.o.cvt.box.y0 + box.y1 - box.y0;

	This->m_wnd = throw_Window_Create(t, "PrefH");

	Icon_GetInfo(This->m_wnd, Icon_PrefList, &info);
	info.box.x0 += 4;
	info.box.y0 += 4;
	info.box.x1 -= 4;
	info.box.y1 -= 4;
	throw_WList_WList(&This->m_PrefList, EWList_SelModeMulti, NULL, This, PrefList_GetItemText);
	throw_WList_SetPane(&This->m_PrefList, This->m_wnd, &info.box);

	Icon_GetInfo(This->m_wnd, Icon_Originals, &info);
	info.box.x0 += 4;
	info.box.y0 += 4;
	info.box.x1 -= 4;
	info.box.y1 -= 4;
	throw_WList_WList(&This->m_Originals, EWList_SelModeMulti, NULL, This, PrefList_GetItemText);
	throw_WList_SetPane(&This->m_Originals, This->m_wnd, &info.box);
	throw_Window_RegisterEventHandler(WList_GetWindow(&This->m_PrefList), PrefWList_EventHandler, This, false);
	throw_Window_RegisterEventHandler(WList_GetWindow(&This->m_Originals), OrzWList_EventHandler, This, false);
	throw_Window_RegisterEventHandler(This->m_wnd, PrefList_EventHandler, This, false);
	throw_DocEvents_AddListener(NULL, This, PrefList_OnDocEvent);

	return This;
}

void Delete_PrefList(CPrefList* This)
{
	if (This != NULL)
	{
		DocEvents_RemoveListener(NULL, This, PrefList_OnDocEvent);
		Window_DeRegisterEventHandler(WList_GetWindow(&This->m_PrefList), PrefWList_EventHandler, This);
		Window_DeRegisterEventHandler(WList_GetWindow(&This->m_Originals), OrzWList_EventHandler, This);
		WList_NotWList(&This->m_PrefList);
		WList_NotWList(&This->m_Originals);

		if (This->m_wnd != HWind_None)
		{
			CWindCvt Info = Window_GetPosInfo(This->m_wnd);
			Choices_Write(pref_section, "Open", "%d", Window_IsOpen(This->m_wnd));
			Choices_Write(pref_section, "PosX", "%d", Info.box.x0);
			Choices_Write(pref_section, "PosY", "%d", Info.box.y0);
			Window_DeRegisterEventHandler(This->m_wnd, PrefList_EventHandler, This);
			Window_Delete(This->m_wnd);
			This->m_wnd = HWind_None;
		}
		mem_free(This);
	}
}
