#include "EditDirList.h"

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

#include "WimpLib:Exception.h"
#include "WimpLib:File.h"
#include "WimpLib:Hourglass.h"
#include "WimpLib:mem.h"
#include "WimpLib:Message.h"
#include "WimpLib:Menu.h"
#include "WimpLib:Task.h"
#include "WimpLib:Template.h"
#include "WimpLib:Window.h"
#include "WimpLib:WStringList.h"

#include "DigitalCD.h"
#include "FileTypes.h"
#include "FileList.h"
#include "MetaScan.h"
#include "Options.h"
#include "DocEvents.h"
#include "UserEvents.h"

#define Prop_DirOpen     0x0001
#define Prop_BaseDir     0x0002
#define Prop_Title       0x0004
#define Prop_Artist      0x0008
#define Prop_Info        0x0010
#define Prop_Autoload    0x0020
#define Prop_ScanMode    0x0040
#define Prop_AllProps    0x007f
#define Prop_SingleObject    0x80000000
#define Prop_RefreshContents 0x40000000
#define Prop_RefreshState    0x20000000

typedef unsigned int Props;

#define EIcon_ColorMask   0xf0000000
#define EIcon_ColorNormal 0x00000000
#define EIcon_ColorDiffer 0x20000000

#define EIcon_FillColorMask   0xf0000020
#define EIcon_FillColorNormal 0x10000000
#define EIcon_FillColorDiffer 0x20000020

#define EditFlags_Create   0x01
#define EditFlags_Updating 0x02 // We are fiddling with the tracks, ignore DocEvents

typedef struct
{
	HWind             m_wnd;
	List*             m_pTracks;
	const FLTrack*    m_pRefTrack;
	void*             m_pView;
	Props             m_AllowedProps;
	Props             m_DifferingProps;
	Props             m_ModifiedProps;
	unsigned int      m_flags;
	struct
	{
		const char*   basedir;
		const char*   title;
		const char*   artist;
		const char*   info;
		bool          autoload;
		unsigned int  scanmode;
	} m_ref;
	struct
	{
		bool          autoload;
		unsigned int  scanmode;
	} m_new;
	WStringList*      m_pWArtistList;
} EditDirList;

static EditDirList TheEditDirList = {HWind_None};

#define Icon_Set            0
#define Icon_Cancel         1
#define Icon_DirOpen        2
#define Icon_BaseDir        3
#define Icon_Title          5
#define Icon_Artist         7
#define Icon_Info           9
#define Icon_Autoload      10
#define Icon_ScanMode      12
#define Icon_ScanMenu      13

/**
 * Sets the reference track to use for building the properties.
 * If the reference track is not contained in the list of edited tracks
 * the first one from the list is used as reference.
 *
 * @param  pRef  Pointer to the reference track to use.
 */
static void EditDirList_SetRefTrack(EditDirList* This, const FLTrack* pRef)
{
	This->m_pRefTrack = NULL;

	if (pRef)
	{
		if (List_Find(This->m_pTracks, 0, pRef) != -1)
			This->m_pRefTrack = pRef;
	}

	if (!This->m_pRefTrack && (List_Count(This->m_pTracks) > 0))
		This->m_pRefTrack = List_Get(This->m_pTracks, 0);
}

/**
 * Refreshes the state of buttons
 */
static void EditDirList_RefreshButtons(EditDirList* This)
{
	bool b;

	b = !This->m_ModifiedProps;
	if (This->m_flags & EditFlags_Create) b = false;

	Icon_SetDimmed(This->m_wnd, Icon_Set, b);
}

/**
 * Refreshes the window contents for given properties
 *
 * @param  props  bitlist of properties to refresh
 *                + Prop_RefreshContents is the properties values are to be updated
 *                + Prop_RefreshState is the properties common/allowed status are to be updated.
 */

static void EditDirList_Refresh(EditDirList* This, Props props)
{
	bool b;

	if (props & Prop_DirOpen)
	{
		b = (This->m_AllowedProps & Prop_DirOpen) == 0;

		if (props & Prop_RefreshState)
			Icon_SetDimmed(This->m_wnd, Icon_DirOpen, b);
	}

	if (props & Prop_BaseDir)
	{
		b = (This->m_AllowedProps & Prop_BaseDir) == 0;

		if (props & Prop_RefreshContents)
			Icon_SetData(This->m_wnd, Icon_BaseDir, This->m_ref.basedir);

		if (props & Prop_RefreshState)
		{
			Icon_SetDimmed(This->m_wnd, Icon_BaseDir - 1, b);
			Icon_SetDimmed(This->m_wnd, Icon_BaseDir, b);
			Icon_SetState(This->m_wnd, Icon_BaseDir
			             , (This->m_DifferingProps & Prop_BaseDir)
			             ? EIcon_ColorDiffer: EIcon_ColorNormal, EIcon_ColorMask);
		}
	}

	if (props & Prop_Title)
	{
		b = (This->m_AllowedProps & Prop_Title) == 0;

		if (props & Prop_RefreshContents)
			Icon_SetData(This->m_wnd, Icon_Title, This->m_ref.title);

		if (props & Prop_RefreshState)
		{
			Icon_SetDimmed(This->m_wnd, Icon_Title - 1, b);
			Icon_SetDimmed(This->m_wnd, Icon_Title, b);
			Icon_SetState(This->m_wnd, Icon_Title
			             , (This->m_DifferingProps & Prop_Title)
			             ? EIcon_ColorDiffer: EIcon_ColorNormal, EIcon_ColorMask);
		}
	}

	if (props & Prop_Artist)
	{
		b = (This->m_AllowedProps & Prop_Artist) == 0;

		if (props & Prop_RefreshContents)
			WStringList_SetIconData(This->m_pWArtistList, This->m_ref.artist);

		if (props & Prop_RefreshState)
		{
			Icon_SetDimmed(This->m_wnd, Icon_Artist - 1, b);
			Icon_SetDimmed(This->m_wnd, Icon_Artist, b);
			Icon_SetState(This->m_wnd, Icon_Artist
			             , (This->m_DifferingProps & Prop_Artist)
			             ? EIcon_ColorDiffer: EIcon_ColorNormal, EIcon_ColorMask);
		}
	}

	if (props & Prop_Info)
	{
		b = (This->m_AllowedProps & Prop_Info) == 0;

		if (props & Prop_RefreshContents)
			Icon_SetData(This->m_wnd, Icon_Info, This->m_ref.info);

		if (props & Prop_RefreshState)
		{
			Icon_SetDimmed(This->m_wnd,Icon_Info - 1, b);
			Icon_SetDimmed(This->m_wnd,Icon_Info, b);
			Icon_SetState(This->m_wnd, Icon_Info
			             , (This->m_DifferingProps & Prop_Info)
			             ? EIcon_ColorDiffer: EIcon_ColorNormal, EIcon_ColorMask);
		}
	}

	if (props & Prop_Autoload)
	{
		b = (This->m_AllowedProps & Prop_Autoload) == 0;

		if (props & Prop_RefreshContents)
			Icon_SetHighlight(This->m_wnd, Icon_Autoload, This->m_new.autoload);

		if (props & Prop_RefreshState)
		{
			Icon_SetDimmed(This->m_wnd,Icon_Autoload, b);
			Icon_SetState(This->m_wnd, Icon_Autoload
			             , (This->m_DifferingProps & Prop_Autoload)
			             ? EIcon_FillColorDiffer: EIcon_FillColorNormal, EIcon_FillColorMask);
		}
	}

	if (props & Prop_ScanMode)
	{
		b = (This->m_AllowedProps & Prop_ScanMode) == 0;

		if (props & Prop_RefreshContents)
			Icon_SetData(This->m_wnd, Icon_ScanMode, Menu_ItemGetText(MetaScanList_GetMenu(), This->m_new.scanmode));

		if (props & Prop_RefreshState)
		{
			Icon_SetDimmed(This->m_wnd,Icon_ScanMode - 1, b);
			Icon_SetDimmed(This->m_wnd,Icon_ScanMode, b);
			Icon_SetDimmed(This->m_wnd,Icon_ScanMode + 1, b);
			Icon_SetState(This->m_wnd, Icon_ScanMode
			             , (This->m_DifferingProps & Prop_ScanMode)
			             ? EIcon_FillColorDiffer: EIcon_FillColorNormal, EIcon_FillColorMask);
		}
	}
}

/**
 * Builds the properties initial values and allowed status.
 */

static void EditDirList_BuildProperties(EditDirList* This)
{
	const FLTrack* pTrack;
	bool b;

	This->m_AllowedProps = Prop_AllProps;
	This->m_ModifiedProps = 0;

	if (List_Count(This->m_pTracks) == 1)
		This->m_AllowedProps |= Prop_SingleObject;
	else
		This->m_AllowedProps &= ~Prop_BaseDir;

	if (This->m_flags & EditFlags_Create)
		This->m_AllowedProps &= ~Prop_DirOpen;

	pTrack = This->m_pRefTrack;

	b = (This->m_AllowedProps & Prop_BaseDir) == 0;
	throw_mem_setstring(&This->m_ref.basedir, b ? NULL : FLTrack_GetFilename(pTrack));

	b = (This->m_AllowedProps & Prop_Title) == 0;
	throw_mem_setstring(&This->m_ref.title, b ? NULL : FLTrack_GetMetaString(pTrack, EMetaId_StreamTitle));

	b = (This->m_AllowedProps & Prop_Artist) == 0;
	throw_mem_setstring(&This->m_ref.artist, b ? NULL : FLTrack_GetMetaString(pTrack, EMetaId_StreamArtist));

	b = (This->m_AllowedProps & Prop_Info) == 0;
	throw_mem_setstring(&This->m_ref.info, b ? NULL : FLTrack_GetInfo(pTrack));

	b = (This->m_AllowedProps & Prop_Autoload) == 0;
	This->m_new.autoload = This->m_ref.autoload
		= b ? false : ((FLTrack_GetFlags(pTrack) & FLTrack_DoNotAutoload) == 0);

	b = (This->m_AllowedProps & Prop_ScanMode) == 0;
	This->m_ref.scanmode = MetaScanList_GetMenuIndex(FLTrack_GetScannerName(pTrack));
	This->m_new.scanmode = This->m_ref.scanmode = b ? 0 : This->m_ref.scanmode;

	EditDirList_Refresh(This, Prop_RefreshContents | Prop_AllProps);

	EditDirList_RefreshButtons(This);
}

/**
 * Takes note of the properties for which the values are not identical in all tracks.
 */

static void EditDirList_BuildCommonStatus(EditDirList* This)
{
	if (This->m_AllowedProps & Prop_SingleObject)
	{
		This->m_DifferingProps = 0;
	}
	else
	{
		ListNode* pNode;
		const FLTrack* pTrack;
		Props commons = This->m_AllowedProps;

		// Check all allowed/non-modified properties to see
		// if their values correspond to the initial values.
		pNode = NULL;

		while (commons && ((pNode = List_GetSuccessor(This->m_pTracks, pNode)) != NULL))
		{
			pTrack = List_GetNodeData(This->m_pTracks, pNode);

			if (commons & Prop_BaseDir)
			{
				if (strcmp(nvl(This->m_ref.basedir), FLTrack_GetFilename(pTrack)))
					commons &= ~Prop_BaseDir;
			}

			if (commons & Prop_Title)
			{
				if (strcmp(nvl(This->m_ref.title), FLTrack_GetMetaString(pTrack, EMetaId_StreamTitle)))
					commons &= ~Prop_Title;
			}

			if (commons & Prop_Artist)
			{
				if (strcmp(nvl(This->m_ref.artist), FLTrack_GetMetaString(pTrack, EMetaId_StreamArtist)))
					commons &= ~Prop_Artist;
			}

			if (commons & Prop_Info)
			{
				if (strcmp(nvl(This->m_ref.info), FLTrack_GetInfo(pTrack)))
					commons &= ~Prop_Info;
			}

			if (commons & Prop_Autoload)
			{
				bool b = ((FLTrack_GetFlags(pTrack) & FLTrack_DoNotAutoload) == 0);
				if (This->m_ref.autoload != b)
					commons &= ~Prop_Autoload;
			}

			if (commons & Prop_ScanMode)
			{
				int scanmode = MetaScanList_GetMenuIndex(FLTrack_GetScannerName(pTrack));

				if (This->m_ref.scanmode != scanmode)
					commons &= ~Prop_ScanMode;
			}
		}

		This->m_DifferingProps = This->m_AllowedProps & ~commons;
	}

	EditDirList_Refresh(This, Prop_RefreshState | Prop_AllProps);
}

/**
 * Takes note of the properties which were modified.
 */

static void EditDirList_CheckChanges(EditDirList* This, Props props)
{
	Props modifs = 0;
	Props updated;

	props &= This->m_AllowedProps;

	// Check values with references
	if (props & Prop_BaseDir)
	{
		if (strcmp(nvl(This->m_ref.basedir), Icon_GetData(This->m_wnd, Icon_BaseDir)))
			modifs |= Prop_BaseDir;
	}

	if (props & Prop_Title)
	{
		if (strcmp(nvl(This->m_ref.title), Icon_GetData(This->m_wnd, Icon_Title)))
			modifs |= Prop_Title;
	}

	if (props & Prop_Artist)
	{
		if (strcmp(nvl(This->m_ref.artist), Icon_GetData(This->m_wnd, Icon_Artist)))
			modifs |= Prop_Artist;
	}

	if (props & Prop_Info)
	{
		if (strcmp(nvl(This->m_ref.info), Icon_GetData(This->m_wnd, Icon_Info)))
			modifs |= Prop_Info;
	}

	if (props & Prop_Autoload)
	{
		This->m_new.autoload = (Icon_GetState(This->m_wnd, Icon_Autoload, EIcon_Selected) != 0);
		if (This->m_ref.autoload != This->m_new.autoload)
			modifs |= Prop_Autoload;
	}

	if (props & Prop_ScanMode)
	{
		if (This->m_ref.scanmode != This->m_new.scanmode)
			modifs |= Prop_ScanMode;
	}

	// Any change compared to old status?
	updated = (modifs ^ This->m_ModifiedProps) & props;

	if (This->m_AllowedProps & Prop_SingleObject)
	{
		// reflect even reversion to original values
		if (updated)
		{
			This->m_ModifiedProps ^= updated;

			EditDirList_RefreshButtons(This);
		}
	}
	else
	{
		// reflect new changes but there is no reversion
		// to original value since any change affected old values
		updated &= modifs;

		if (updated)
		{
			This->m_ModifiedProps |= updated;
			This->m_DifferingProps &= ~updated;
			EditDirList_Refresh(This, Prop_RefreshState | updated);

			EditDirList_RefreshButtons(This);
		}
	}
}

static void EditDirList_ClearTracks(EditDirList* This)
{
	This->m_flags |= EditFlags_Updating;

	try
	{
		if (This->m_flags & EditFlags_Create)
		{
			ListNode* pNode;
			FLTrack* pTrack;

			pNode = NULL;

			while ((pNode = List_GetSuccessor(This->m_pTracks, pNode)) != NULL)
			{
				pTrack = List_GetNodeData(This->m_pTracks, pNode);
				Delete_FLTrack(pTrack);
			}
		}
	}
	catch
	{
		App_ReportException();
	}
	catch_end

	List_Clear(This->m_pTracks);

	This->m_flags &= ~EditFlags_Updating;
}

static bool EditDirList_OnOk(EditDirList* This)
{
	ListNode* pNode;
	FileList* pOwner = NULL;
	const FLTrack* pTrack;
	const char* string;
	int i = 0;
	int max = List_Count(This->m_pTracks);

	// Checks
	pTrack = This->m_pRefTrack;

	if ((This->m_ModifiedProps & Prop_BaseDir)
	||  (This->m_flags & EditFlags_Create))
	{
		// Convert spaces to hardspaces
		string = Icon_GetData(This->m_wnd, Icon_BaseDir);
		for (char* pc = (char*) string; *pc; pc++)
		{
			if (*pc == ' ') *pc = 0xa0;
		}

		if (string[0])
		{
			if (File_GetFileType(string) == -2)
			{
				App_ReportError("DSErr3:%s", string);
				return false;
			}
			if (File_GetFileType(string) < 0x1000)
			{
				App_ReportError("DSErr6:%s", string);
				return false;
			}
		}
		else
		{
			App_ReportError("DSErr8");
			return false;
		}
	}

	// Set
	bool off = !WLib_Hourglass_IsOn();
	if (off) WLib_Hourglass_On();
	pNode = NULL;

	This->m_flags |= EditFlags_Updating;

	try
	{
		while ((pNode = List_GetSuccessor(This->m_pTracks, pNode)) != NULL)
		{
			FLTrack* pTrack = List_GetNodeData(This->m_pTracks, pNode);

			WLib_Hourglass_Percentage((100 * i++)/max);

			if (pOwner != FLTrack_GetOwner(pTrack))
			{
				if (pOwner != NULL) FileList_EndUpdate(pOwner, false, false);

				pOwner = FLTrack_GetOwner(pTrack);
				if (pOwner != NULL) FileList_StartUpdate(pOwner);
			}

			FileList* pList = NULL;

			bool bAutoModSubList = false;
			bool bModSubList = false;
			bool bModList = false;
			bool bModTrack = false;

			// Ensure filename is set for create mode
			if (This->m_ModifiedProps & Prop_BaseDir)
			{
				string = Icon_GetData(This->m_wnd, Icon_BaseDir);

				if (strcmp(FLTrack_GetFilename(pTrack), string))
				{
					// The following line updates the track pathname, so must come first
					if (pList) Delete_FileList(pList);
					bModTrack |= FLTrack_SetFilename(pTrack, string, false);
					if (pList) pList = throw_New_FileList_FromTrack(pTrack);
				}
			}

			if (This->m_flags & EditFlags_Create)
			{
				try
				{
					pOwner = (FileList*) View_GetDocument(This->m_pView);
					int pos = throw_FileList_InsertTrackAt(pOwner, -1, pTrack);
					FileList_Show(pOwner, pos);
					pList = throw_New_FileList_FromTrack(pTrack);
					FileList_Show(pList, -1);
				}
				catch
				{
					App_ReportException();
				}
				catch_end
			}
			else
			{
				pList = FLTrack_GetSubList(pTrack);
			}

			if (This->m_ModifiedProps & Prop_Title)
			{
				string = Icon_GetData(This->m_wnd, Icon_Title);
				bModTrack |= FLTrack_SetMetaText(pTrack, EMetaId_StreamTitle, EMetaOrigin_User, string);
				if (pList) bAutoModSubList |= FileList_SetTitle(pList, string);
			}

			if (This->m_ModifiedProps & Prop_Artist)
			{
				string = Icon_GetData(This->m_wnd, Icon_Artist);
				bModTrack |= FLTrack_SetMetaText(pTrack, EMetaId_StreamArtist, EMetaOrigin_User, string);
				if (pList) bAutoModSubList |= FileList_SetAuthor(pList, string);
			}

			if (This->m_ModifiedProps & Prop_Info)
			{
				string = Icon_GetData(This->m_wnd, Icon_Info);
				bModTrack |= FLTrack_SetInfo(pTrack, string);
				if (pList) bAutoModSubList |= FileList_SetInfo(pList, string);
			}

			if (This->m_ModifiedProps & Prop_Autoload)
				bModTrack |= FLTrack_SetFlags(pTrack, This->m_new.autoload ? 0 : FLTrack_DoNotAutoload, FLTrack_DoNotAutoload);

			if (This->m_ModifiedProps & Prop_ScanMode)
			{
				MetaScan* pScanner = MetaScanList_Get(This->m_new.scanmode);

				bModTrack |= FLTrack_SetScannerName(pTrack, pScanner ? MetaScan_GetName(pScanner) : NULL);
			}

			if (pList)
			{
				if (bAutoModSubList) FileList_SetAutoModifiedFlag(pList);
				if (bModSubList) FileList_SetModifiedFlag(pList, true);
			}

			FLTrack_RefreshViews(pTrack, This, bModTrack, bModList);
		}

		if (pOwner != NULL) FileList_EndUpdate(pOwner, false, false);
	}
	catch
	{
		App_ReportException();
	}
	catch_end

	This->m_flags &= ~EditFlags_Updating;

	if (off) WLib_Hourglass_Off();

	// Once here new modications are updates
	This->m_flags &= ~EditFlags_Create;

	// Reset settings
	EditDirList_BuildProperties(This);
	EditDirList_BuildCommonStatus(This);

	return true;
}

static void EditDirList_OnCancel(EditDirList* This)
{
	// Reset settings
	EditDirList_BuildProperties(This);
	EditDirList_BuildCommonStatus(This);
}

static EListenerAction EditDirList_Listener(void* handle, const Event* e)
{
	EditDirList* This = handle;

	switch(e->Type)
	{
		case EEvent_OptionParentalLock:
		{
			if (Options()->Player.bParentalLock)
			{
				EditDirList_OnCancel(This);
				Window_Close(This->m_wnd);
			}
		}
		break;
	}

	return EListenerAction_ContinueEvent;
}

static EListenerAction EditDirList_MenuHandler(void* handle, const int* hit, const Event* e)
{
	EditDirList* This = handle;

	switch(e->Type)
	{
		case EEvent_Menu:
		{
			This->m_new.scanmode = hit[0];
			Icon_SetData(This->m_wnd, Icon_ScanMode, Menu_ItemGetText(MetaScanList_GetMenu(), This->m_new.scanmode));
			EditDirList_CheckChanges(This, Prop_ScanMode);

			return EListenerAction_StopEvent;
		}
		break;
	}

	return EListenerAction_ContinueEvent;
}

static EListenerAction EditDirList_EventHandler(void* handle, const Event* e)
{
	EditDirList* This = handle;

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

			if (m->but & EBut_Menu)
				return EListenerAction_StopEvent;

			switch(m->i)
			{
				case Icon_Cancel:
				{
					EditDirList_OnCancel(This);
					if (m->but & EBut_Select)
						Window_Close(This->m_wnd);
				}
				break;
				case Icon_Set:
				{
					if (EditDirList_OnOk(This)
					&&  (m->but & EBut_Select))
						Window_Close(This->m_wnd);
				}
				break;
				case Icon_DirOpen:
				{
					FLTrack_OpenFileDir(This->m_pRefTrack);
				}
				break;
				case Icon_Autoload:
				{
					EditDirList_CheckChanges(This, Prop_Autoload);
				}
				break;
				case Icon_ScanMenu:
				{
					Menu_Popup(m->w, m->i, MetaScanList_GetMenu(), EditDirList_MenuHandler, handle);
				}
				break;
			}

			return EListenerAction_StopEvent;
		}
		break;
		case EEvent_Key:
		{
			const Event_Key* pkey = e->pData;

			switch(pkey->code)
			{
				case 0x1b: // Esc
				{
					EditDirList_OnCancel(This);
					Window_Close(This->m_wnd);
					return EListenerAction_StopEvent;
				}
				break;
				case 0x0d: // Return
				{
					if (pkey->caret.pos.i == Icon_Info)
					{
						if (EditDirList_OnOk(This))
							Window_Close(This->m_wnd);
					}
					return EListenerAction_StopEvent;
				}
				break;
				case 0x181: // F1
				{
					App_StrongHelp("Playlist_PropDirs");
					return EListenerAction_StopEvent;
				}
				break;
				default:
				{
					switch (pkey->caret.pos.i)
					{
						case Icon_BaseDir:
						{
							EditDirList_CheckChanges(This, Prop_BaseDir);
						}
						break;
						case Icon_Title:
						{
							EditDirList_CheckChanges(This, Prop_Title);
						}
						break;
						case Icon_Artist:
						{
							EditDirList_CheckChanges(This, Prop_Artist);
						}
						break;
						case Icon_Info:
						{
							EditDirList_CheckChanges(This, Prop_Info);
						}
						break;
					}
					break;
				}
			}
		}
		break;
		case EEvent_Message:
		case EEvent_MessageWantAck:
		{
			const Msg* msg = e->pData;

			switch(msg->hdr.action)
			{
				case EMsg_DataLoad:
				{
					const Msg_FileData* msg = e->pData;

					if ((msg->pos.i == Icon_BaseDir)
					&&  (This->m_AllowedProps & Prop_BaseDir)
					&&  (File_GetFileType(msg->name) >= 0x1000))
					{
						Icon_SetData(This->m_wnd, Icon_BaseDir, msg->name);
						EditDirList_CheckChanges(This, Prop_BaseDir);
					}

					return EListenerAction_StopEvent; // any other drag is ignored
				}
				break;
			}
		}
		break;
	}

	return EListenerAction_ContinueEvent;
}

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

	if ((This->m_wnd == HWind_None)
	||  (This->m_flags & EditFlags_Updating))
		return EListenerAction_ContinueEvent;

	switch(pe->event)
	{
		case EDocEvent_RemoveElement:
		case EDocEvent_UpdateElement:
		{
			int pos = List_Find(This->m_pTracks, 0, pe->pElement);

			if (pos != -1)
			{
				EditDirList_OnCancel(This);
				EditDirList_ClearTracks(This);
				Window_Close(This->m_wnd);
			}
		}
		break;
	}

	return EListenerAction_ContinueEvent;
}

void EditDirList_EditNew(void* pView)
{
	EditDirList_Edit(pView, NULL, NULL);
}

void EditDirList_Edit(void* pView, List* pList, const FLTrack* pRef)
{
	EditDirList* This = &TheEditDirList;

	if (Options()->Player.bParentalLock)
		return;

	if (This->m_wnd == HWind_None)
	{
		memset(This, 0, sizeof(*This));
		This->m_wnd = HWind_None;

		try
		{
			This->m_pTracks = New_List();

			This->m_wnd = throw_Window_CreateFrom("PropDir", "DPropH");

			throw_Window_RegisterEventHandler(This->m_wnd, EditDirList_EventHandler, This, false);
			throw_Task_AddListener(EEvent_OptionParentalLock, EditDirList_Listener, This, false);

			This->m_pWArtistList = throw_New_WStringList(DigitalCD.pArtistsCol, This->m_wnd, Icon_Artist);
			throw_DocEvents_AddListener(NULL, This, EditDirList_OnDocEvent);
		}
		catch
		{
			EditDirList_NotEdit();
			App_ReportException();
			return;
		}
		catch_end
	}

	This->m_pView = pView;

	EditDirList_ClearTracks(This);

	try
	{
		if (pList && List_Count(pList))
		{
			ListNode* pNode;
			FLTrack* pTrack;

			pNode = NULL;

			while ((pNode = List_GetSuccessor(pList, pNode)) != NULL)
			{
				pTrack = List_GetNodeData(pList, pNode);

				List_InsertBefore(This->m_pTracks, NULL, pTrack);
			}

			This->m_flags &= ~EditFlags_Create;
		}
		else if (!pList && pView)
		{
			FileList* pOwner = (FileList*) View_GetDocument(pView);
			FLTrack* pTrack = throw_New_FLTrack
								( pOwner
								, FLTrack_IsPlaylist|FLTrack_IsDir
								, &nil
								);

			List_InsertBefore(This->m_pTracks, NULL, pTrack);

			This->m_flags |= EditFlags_Create;
		}
	}
	catch
	{
		App_ReportException();
		EditDirList_ClearTracks(This);
	}
	catch_end

	EditDirList_SetRefTrack(This, pRef);

	if (!List_Count(This->m_pTracks))
	{
		Window_Close(This->m_wnd);
	}
	else
	{
		EditDirList_BuildProperties(This);
		EditDirList_BuildCommonStatus(This);

		Window_Open(This->m_wnd);
		if (This->m_AllowedProps & Prop_BaseDir)
			Icon_SetFocus(This->m_wnd, Icon_BaseDir, -1);
		else Icon_SetFocus(This->m_wnd, Icon_Title, -1);
	}
}

void EditDirList_NotEdit(void)
{
	EditDirList* This = &TheEditDirList;

	if (This->m_pTracks)
	{
		EditDirList_ClearTracks(This);
		Delete_List(This->m_pTracks);
	}

	Delete_WStringList(This->m_pWArtistList);

	if (This->m_wnd != HWind_None)
	{
		DocEvents_RemoveListener(NULL, This, EditDirList_OnDocEvent);
		Task_RemoveListener(EEvent_OptionParentalLock, EditDirList_Listener, This);
		Window_DeRegisterEventHandler(This->m_wnd, EditDirList_EventHandler, This);
		Window_Delete(This->m_wnd);
	}

	mem_free(This->m_ref.basedir);
	mem_free(This->m_ref.title);
	mem_free(This->m_ref.artist);
	mem_free(This->m_ref.info);

	memset(This, 0, sizeof(*This));
	This->m_wnd = HWind_None;
}
