#include "WimpLib:WFiler.h"

#include <stdlib.h>
#include <string.h>

#include "WimpLib:mem.h"
#include "WimpLib:Display.h"
#include "WimpLib:Desktop.h"
#include "WimpLib:DragDrop.h"
#include "WimpLib:Exception.h"
#include "WimpLib:Keyboard.h"
#include "WimpLib:Task.h"
#include "WimpLib:Window.h"

EListenerAction WFiler_EventHandler(void* handle, const Event* pevent);

void throw_WFiler_WFiler(WFiler* This
		, unsigned int flags
		, CTemplate* t
		, void* pHandle
		, int NrSizes
		, WListCore_FWList* pFWList
		)
{
	throw_WListCore_WListCore(This, flags, t, pHandle, NrSizes, pFWList);
	throw_Window_RegisterEventHandler(WListCore_GetWindow(This), WFiler_EventHandler, This, false);
}

void WFiler_NotWFiler(WFiler* This)
{
	WListCore_NotWListCore(This);
}

EListenerAction WFiler_EventHandler(void* handle, const Event* e)
{
	if (e->Type != EEvent_Mouse) return EListenerAction_ContinueEvent;

	WFiler* This = handle;
	const Mouse* m = e->pData;
	WItemArea area;
	int item;

	// Ignore click on icons
	if ((m->i != HIcon_None)
	||  !WListCore_IsRefreshAllowed(This))
		return EListenerAction_ContinueEvent;

	item = WListCore_ItemAreaFromScreenPt(This, m, EWListPtrMode_Hover, &area);

	// Clicked on inactive area ?
	if (area.id > EWItemArea_Select)
		return EListenerAction_ContinueEvent;

	switch(m->but)
	{
		case EBut_ClickAdjust:
		case EBut_ClickSelect:
		{
			if (area.id == EWItemArea_Select)
			{
				if (WListCore_GetFocus(This) != item) WListCore_SetFocus(This, item, true);

				if ((m->but == EBut_ClickAdjust)
				&&  ((WListCore_GetFlags(This) & EWList_SelModeMask) == EWList_SelModeMulti))
				{
					// Invert selection status of item
					WListCore_InvertItemState(This, item, EWItem_Selected);
					WListCore_NotifySelChange(This, item);
				}
				else
				{
					if (!(WListCore_GetItemState(This, item) & EWItem_Selected))
					{
						// Clear selection and select item
						if ((WListCore_GetFlags(This) & EWList_SelModeMask) == EWList_SelModeMulti)
							WListCore_SetItemsState(This, 0, EWItem_Selected, 0, 0);
						WListCore_SetItemState(This, item, EWItem_Selected, EWItem_Selected);
						WListCore_NotifySelChange(This, item);
					}
				}

				return EListenerAction_StopEvent;
			}
			else
			{
				if (m->but == EBut_ClickSelect)
				{
					if (WListCore_SetItemsState(This, 0, EWItem_Selected, 0, 0))
						WListCore_NotifySelChange(This, -1);
				}
			}

			return EListenerAction_ContinueEvent;
		}
		break;
		case EBut_DragSelect:
		case EBut_DragAdjust:
		{
			if (((WListCore_GetFlags(This) & EWList_SelModeMask) == EWList_SelModeMulti)
			&&  (area.id == EWItemArea_Outside))
			{
				CWindCvt info = Window_GetPosInfo(WListCore_GetWindow(This));
				bool bCompleted = false;

				try
				{
					// Prepare dragging
					WListCore_StartSelection(This
						, EWListCore_DragMouse
						  | ((m->but == EBut_DragAdjust) ? EWListCore_DragAdjust : 0)
						, throw_New_WGridSelect(This, m)
						);

						bCompleted = Drag_DragPoint(NULL, NULL, &info.box, NULL);

					// Clear activation state and eventually update selection
					WListCore_EndSelection(This, bCompleted);
				}
				catch
				{
					Task_ReportException();
				}
				catch_end

				return EListenerAction_StopEvent;
			}
			return EListenerAction_ContinueEvent;
		}
		break;
	}

	return EListenerAction_ContinueEvent;
}
