/*

		Listtree.mcc (c) by kMel, Klaus Melchior

		Example for Listtree.mcc DragNDrop

		show_listtree_dd.c

*/

/* DMAKE */

//#define DEBUG
#define __FUNC__ ""


/*** includes ***/

#include <kmel/kmel.h>
#include <kmel/kmel_debug.h>

#include <mui/listtree_mcc.h>
#include <mui/listtreename_mcc.h>


/*** vars ***/

static APTR app;
static APTR window;
static APTR bt_open_nodes, bt_close_nodes, lt_nodes;
static APTR st_insert, bt_remove;
static APTR bt_save, bt_parent, bt_test;

static struct MUI_CustomClass *cl_ddstring;
static struct MUI_CustomClass *cl_ddlisttree;


/*** externals ***/
extern char *vers_tag;


/*** sample ***/
static const char *sample_array[12] =
{
	"Node1",
	"Node1.1",
	"Leaf1.1.1",
	"Leaf1.1.2",
	"Node1.2",
	"Node2",
	"k",
	"m",
	"e",
	"l",
	"Leaf3"
};



/*** hooks ***/
__geta4 LONG activefunc(
	__a2 APTR obj)
{
	DB("active\n");

	return(0);
}

static struct Hook activehook = {
	{NULL, NULL},
	(void *)activefunc,
	NULL, NULL
};


__geta4 LONG parentfunc(
	__a2 APTR obj)
{
	struct MUIS_Listtree_TreeNode *active, *tn;

	if(active = (struct MUIS_Listtree_TreeNode *)DoMethod(obj, MUIM_Listtree_GetEntry, NULL, MUIV_Listtree_GetEntry_Position_Active, 0))
	{
		tn = (struct MUIS_Listtree_TreeNode *)DoMethod(obj, MUIM_Listtree_GetEntry, active, MUIV_Listtree_GetEntry_Position_Parent, 0);
		DB("parent = %08lx\n", tn);

		set(obj, MUIA_Listtree_Active, tn);
	}


	return(0);
}

static struct Hook parenthook = {
	{NULL, NULL},
	(void *)parentfunc,
	NULL, NULL
};


__geta4 LONG testfunc(
	__a2 APTR obj)
{
	DoMethod(obj, MUIM_Listtree_Sort, MUIV_Listtree_Sort_ListNode_Active, 0);

	return(0);
}

static struct Hook testhook = {
	{NULL, NULL},
	(void *)testfunc,
	NULL, NULL
};


__geta4 LONG opnfunc(
	__a1 struct MUIA_Listtree_TreeNode *tn)
{
	DB("tn:%08lx\n", tn);

	DoMethod(lt_nodes, MUIM_Listtree_Insert, "OpenHook", NULL, tn, MUIV_Listtree_Insert_PrevNode_Tail, 0);

	return(0);
}

static struct Hook opnhook = {
	{NULL, NULL},
	(void *)opnfunc,
	NULL, NULL
};


__geta4 LONG clsfunc(
	__a1 struct MUIA_Listtree_TreeNode *tn)
{
	DB("tn:%08lx\n", tn);

	DoMethod(lt_nodes, MUIM_Listtree_Remove, tn, MUIV_Listtree_Remove_TreeNode_Tail, 0);

	return(0);
}

static struct Hook clshook = {
	{NULL, NULL},
	(void *)clsfunc,
	NULL, NULL
};




void save_list(void *fp, Object *lt, struct MUIS_Listtree_TreeNode *list)
{
	struct MUIS_Listtree_TreeNode *tn;
	UWORD pos=0;

	for(pos=0; ; pos++)
	{
		if(tn = (struct MUIS_Listtree_TreeNode *)DoMethod(lt, MUIM_Listtree_GetEntry, list, pos, MUIV_Listtree_GetEntry_Flags_SameLevel))
		{
			if(tn->tn_Flags & TNF_LIST)
			{
				fprintf(fp, ">>> %s %04lx\n", tn->tn_Name, tn->tn_Flags);
				DB(">>> %s\n", tn->tn_Name);
				save_list(fp, lt, tn);
				fprintf(fp, "<<<\n");
				DB("<<<\n");
			}
			else
			{
				fprintf(fp, "%s\n", tn->tn_Name);
				DB("%s\n", tn->tn_Name);
			}
		}
		else
			break;
	}
}


__geta4 LONG savefunc(
	__a2 APTR obj,
	__a1 test)
{
	void *fp;

	DB("save\n");

	if(fp = fopen("T:Listtree.list", "w"))
	{
		fprintf(fp, "List structure of Listtree:\n");

		save_list(fp, obj, MUIV_Listtree_GetEntry_ListNode_Root);

		fclose(fp);
	}

	return(0);
}

static struct Hook savehook = {
	{NULL, NULL},
	(void *)savefunc,
	NULL, NULL
};


SAVEDS ASM ULONG confunc(
	REG(a0) struct Hook *hook,
	REG(a2) APTR mem_pool,
	REG(a1) char *name)
{
	DB("con '%s'\n", name);

	return(name);
}

static struct Hook conhook = {
	{NULL, NULL},
	(void *)confunc,
	NULL, NULL
};


SAVEDS ASM LONG desfunc(
	REG(a0) struct Hook *hook,
	REG(a2) APTR mem_pool,
	REG(a1) char *name)
{
	DB("des '%s'\n", name);

	return(0);
}

static struct Hook deshook = {
	{NULL, NULL},
	(void *)desfunc,
	NULL, NULL
};





/*** objects ***/

Object *image_button(UWORD image)
{
	return(

	HGroup,

		Child, HSpace(0),

		Child, ImageObject,
			ImageButtonFrame,
			MUIA_Image_Spec,		image,
//			MUIA_Image_FreeVert,	TRUE,
//			MUIA_Image_FreeHoriz,	TRUE,
			MUIA_Background,		MUII_ButtonBack,
			MUIA_ShowSelState,		FALSE,
			End,

		Child, HSpace(0),

		End

	);
}


/*** classes ***/

struct Data_DDString
{
	Object *listtree;
};


SAVEDS ASM ULONG Dispatcher_DDString(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
{
	struct Data_DDString *data = INST_DATA(cl,obj);

	switch(msg->MethodID)
	{
		case MUIM_DragQuery:
		{
			struct MUIP_DragQuery *d = (struct MUIP_DragQuery *)msg;

			DB("DDString DragQuery: d->obj:%08lx data->listtree:%08lx\n", d->obj, data->listtree);

			if(d->obj == data->listtree)
			{
				return(MUIV_DragQuery_Accept);
			}

			return(MUIV_DragQuery_Refuse);
		}
		break;

		case MUIM_DragDrop:
		{
			DB("DDString MUIM_DragDrop\n");

			struct MUIP_DragQuery *d = (struct MUIP_DragQuery *)msg;

			if(d->obj == data->listtree)
			{
				struct MUIS_Listtree_TreeNode *active;

				DB("MUIM_DragDrop listtree ok\n");

				if(active = (struct MUIS_Listtree_TreeNode *)DoMethod(d->obj, MUIM_Listtree_GetEntry, NULL, MUIV_Listtree_GetEntry_Position_Active, 0))
				{
					DB("active: %08lx\n", active);
					set(obj, MUIA_String_Contents, active->tn_Name);
				}
			}

			return(0);
		}
		break;

	}

	return(DoSuperMethodA(cl,obj,msg));
}


struct Data_DDListtree
{
	Object *string;
	struct MUIS_Listtree_TreeNode *drop;
	UWORD drop_flags;
	LONG  old_entry;
};


SAVEDS ASM ULONG Dispatcher_DDListtree(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
{
	struct Data_DDListtree *data = INST_DATA(cl,obj);

	switch(msg->MethodID)
	{
		case MUIM_DragQuery:
		{
			struct MUIP_DragQuery *d = (struct MUIP_DragQuery *)msg;

			DB("DDListtree DragQuery: d->obj:%08lx data->string:%08lx obj:%08lx\n", d->obj, data->string, obj);

			if(d->obj == data->string)
				return(MUIV_DragQuery_Accept);
		}
		break;

		case MUIM_DragReport:
		{
			struct MUIP_DragReport *d = (struct MUIP_DragReport *)msg;

			if(d->obj == data->string)
			{
				struct MUIS_Listtree_TestPos_Result r;
				struct MUIS_Listtree_TreeNode *tn;

				DoMethod(obj, MUIM_Listtree_TestPos, d->x, d->y, &r);

				if((r.tpr_ListEntry != data->old_entry) || (r.tpr_Flags != data->drop_flags) )
				{
					if(!d->update) return(MUIV_DragReport_Refresh);

					data->old_entry = r.tpr_ListEntry;
					data->drop_flags = r.tpr_Flags;

//					if(tn = r.tpr_TreeNode)
//					{
//						/*** if entry to drop has a list ***/
//						if( (tn->tn_Flags & TNF_LIST) || (r.tpr_Flags != MUIV_Listtree_TestPos_Result_Flags_Onto) )
//						{
//							data->drop = tn;
//							DoMethod(obj, MUIM_Listtree_SetDropMark, r.tpr_ListEntry, r.tpr_Flags);
//						}
//						else
//						{
//							DoMethod(obj, MUIM_Listtree_SetDropMark, r.tpr_ListEntry, MUIV_Listtree_SetDropMark_Values_None);
//							data->drop = NULL;
//						}
//					}
//					else
//					{
						DoMethod(obj, MUIM_Listtree_SetDropMark, r.tpr_ListEntry, MUIV_Listtree_SetDropMark_Values_None);
						data->drop = NULL;
//					}


				}
			}
		}
		break;

		case MUIM_DragDrop:
		{
			struct MUIP_DragDrop *d = (struct MUIP_DragDrop *)msg;

			DB("DDListtree DragDrop: d->obj:%08lx data->drop_flags:%ld\n", d->obj, data->drop_flags);

			/*** object valid ? ***/
			if(d->obj == data->string)
			{
				char *name;

				get(d->obj, MUIA_String_Contents, &name);

				switch(data->drop_flags)
				{
					case MUIV_Listtree_TestPos_Result_Flags_Above:
						if(data->drop)
							DoMethod(obj, MUIM_Listtree_Insert, name, NULL, NULL, data->drop, MUIV_Listtree_Insert_Flags_NextNode);
					break;

					case MUIV_Listtree_TestPos_Result_Flags_Below:
						if(data->drop)
							DoMethod(obj, MUIM_Listtree_Insert, name, NULL, NULL, data->drop, 0);
					break;

					case MUIV_Listtree_TestPos_Result_Flags_Onto:
						if(data->drop)
							DoMethod(obj, MUIM_Listtree_Insert, name, NULL, data->drop, MUIV_Listtree_Insert_PrevNode_Sorted, 0);
					break;

					case MUIV_Listtree_TestPos_Result_Flags_Sorted:
						DoMethod(obj, MUIM_Listtree_Insert, name, NULL, MUIV_Listtree_Insert_ListNode_Root, MUIV_Listtree_Insert_PrevNode_Sorted, 0);
					break;
				}

				return(0);
			}
		}
		break;

	}

	return(DoSuperMethodA(cl,obj,msg));
}




/*** main ***/
int main(int argc,char *argv[])
{
	ULONG signals;
	BOOL running = TRUE;

	if(cl_ddstring = MUI_CreateCustomClass(NULL, MUIC_String, NULL, sizeof(struct Data_DDString), Dispatcher_DDString))
	{
		if(cl_ddlisttree = MUI_CreateCustomClass(NULL, MUIC_Listtree, NULL, sizeof(struct Data_DDListtree), Dispatcher_DDListtree))
		{
			app = ApplicationObject,
				MUIA_Application_Title      , "Show_ListtreeClass_DD",
				MUIA_Application_Version    , vers_tag+6,
				MUIA_Application_Copyright  , "©1995, kMel Klaus Melchior",
				MUIA_Application_Author     , "Klaus Melchior",
				MUIA_Application_Description, "Demonstrates Listtree DragNDrop.",
				MUIA_Application_Base       , "SHOWLISTTREEDD",

				SubWindow, window = WindowObject,
					MUIA_Window_Title, "DragNDrop",
					MUIA_Window_ID   , MAKE_ID('T','R','E','E'),
					MUIA_Window_AppWindow, TRUE,
					WindowContents, VGroup,

						Child, HGroup,
							Child, bt_open_nodes = KeyButton("Open", 'o'),
							Child, bt_close_nodes = KeyButton("Close", 'c'),
							End,

						/*** create a listtree ***/
						Child, ListviewObject,
							MUIA_CycleChain, 1,
							MUIA_Listview_Input, TRUE,
							MUIA_Listview_DragType, 1,
							MUIA_Listview_List, lt_nodes = NewObject(cl_ddlisttree->mcc_Class, NULL,
								InputListFrame,
								MUIA_Listtree_SortHook, MUIV_Listtree_SortHook_LeavesBottom,
								MUIA_Listtree_ConstructHook, &conhook,
								MUIA_Listtree_DestructHook, &deshook,
								MUIA_Listtree_DragDropSort, TRUE,
								MUIA_Listtree_EmptyNodes, TRUE,
//								MUIA_Listtree_OpenHook, &opnhook,
//								MUIA_Listtree_CloseHook, &clshook,
								MUIA_Listtree_MultiSelect, MUIV_Listview_MultiSelect_Default,
								End,
							End,

						Child, HGroup,
							Child, image_button(MUII_TapePlayBack),
							Child, image_button(MUII_TapePlay),
							Child, image_button(MUII_TapeUp),
							Child, image_button(MUII_TapeDown),
							End,

						Child, HGroup,
							Child, Label2("Insert"),
							Child, st_insert = NewObject(cl_ddstring->mcc_Class, NULL,
								StringFrame,
								MUIA_ControlChar, 'i',
								MUIA_String_MaxLen, 20,
								End,
							Child, bt_remove = KeyButton("Remove", 'r'),
							End,

						Child, HGroup,
							Child, bt_save = KeyButton("Save to 'T:Listtree.list'", 's'),
							Child, bt_parent = KeyButton("Parent", 'p'),
							Child, bt_test = KeyButton("Test", 't'),
							End,

						End,

					End,
				End;

			if(app)
			{
				/*** init data ***/
				struct Data_DDString *data_s = INST_DATA(cl_ddstring->mcc_Class, st_insert);
				struct Data_DDString *data_l = INST_DATA(cl_ddlisttree->mcc_Class, lt_nodes);
				data_s->listtree = lt_nodes;
				data_l->listtree = st_insert;

				/*** generate notifies ***/
				DoMethod(window, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
					app, 2,
					MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);

				/*** open/close all nodes ***/
				DoMethod(bt_open_nodes, MUIM_Notify, MUIA_Pressed, FALSE,
					lt_nodes, 4,
					MUIM_Listtree_Open, MUIV_Listtree_Open_ListNode_Root, MUIV_Listtree_Open_TreeNode_All, 0);
				DoMethod(bt_close_nodes, MUIM_Notify, MUIA_Pressed, FALSE,
					lt_nodes, 4,
					MUIM_Listtree_Close, MUIV_Listtree_Close_ListNode_Root, MUIV_Listtree_Close_TreeNode_All, 0);

				/*** remove ***/
				DoMethod(bt_remove, MUIM_Notify, MUIA_Pressed, FALSE,
					lt_nodes, 4,
					MUIM_Listtree_Remove, MUIV_Listtree_Remove_ListNode_Root, MUIV_Listtree_Remove_TreeNode_Active, 0);

				/*** active entry ***/
				DoMethod(lt_nodes, MUIM_Notify, MUIA_Listtree_Active, MUIV_EveryTime,
					lt_nodes, 3,
					MUIM_CallHook, &activehook, MUIV_TriggerValue);

				/*** save ***/
				DoMethod(bt_save, MUIM_Notify, MUIA_Pressed, FALSE,
					lt_nodes, 2,
					MUIM_CallHook, &savehook);

				/*** parent ***/
				DoMethod(bt_parent, MUIM_Notify, MUIA_Pressed, FALSE,
					lt_nodes, 2,
					MUIM_CallHook, &parenthook);

				/*** test ***/
				DoMethod(bt_test, MUIM_Notify, MUIA_Pressed, FALSE,
					lt_nodes, 2,
					MUIM_CallHook, &testhook);


				/*** string D&D ***/
				set(st_insert, MUIA_Dropable, TRUE);
				set(st_insert, MUIA_Draggable, TRUE);


				/*** insert sample nodes ***/
				{
					struct MUIS_Listtree_TreeNode *tn1, *tn2;
					WORD i=0;

					tn1 = (struct MUIS_Listtree_TreeNode *)DoMethod(lt_nodes, MUIM_Listtree_Insert, sample_array[i], sample_array[i], MUIV_Listtree_Insert_ListNode_Root, MUIV_Listtree_Insert_PrevNode_Tail, TNF_LIST); i++;
					tn2 = (struct MUIS_Listtree_TreeNode *)DoMethod(lt_nodes, MUIM_Listtree_Insert, sample_array[i], sample_array[i], tn1, MUIV_Listtree_Insert_PrevNode_Tail, TNF_LIST); i++;
					DoMethod(lt_nodes, MUIM_Listtree_Insert, sample_array[i], sample_array[i], tn2, MUIV_Listtree_Insert_PrevNode_Tail, 0); i++;
					DoMethod(lt_nodes, MUIM_Listtree_Insert, sample_array[i], sample_array[i], tn2, MUIV_Listtree_Insert_PrevNode_Tail, 0); i++;
					DoMethod(lt_nodes, MUIM_Listtree_Insert, sample_array[i], sample_array[i], tn1, MUIV_Listtree_Insert_PrevNode_Tail, TNF_LIST); i++;
					tn1 = DoMethod(lt_nodes, MUIM_Listtree_Insert, sample_array[i], sample_array[i], MUIV_Listtree_Insert_ListNode_Root, MUIV_Listtree_Insert_PrevNode_Tail, TNF_LIST); i++;
					DoMethod(lt_nodes, MUIM_Listtree_Insert, sample_array[i], sample_array[i], tn1, MUIV_Listtree_Insert_PrevNode_Tail, 0); i++;
					DoMethod(lt_nodes, MUIM_Listtree_Insert, sample_array[i], sample_array[i], tn1, MUIV_Listtree_Insert_PrevNode_Tail, 0); i++;
					DoMethod(lt_nodes, MUIM_Listtree_Insert, sample_array[i], sample_array[i], tn1, MUIV_Listtree_Insert_PrevNode_Tail, 0); i++;
					DoMethod(lt_nodes, MUIM_Listtree_Insert, sample_array[i], sample_array[i], tn1, MUIV_Listtree_Insert_PrevNode_Tail, 0); i++;
					DoMethod(lt_nodes, MUIM_Listtree_Insert, sample_array[i], sample_array[i], MUIV_Listtree_Insert_ListNode_Root, MUIV_Listtree_Insert_PrevNode_Tail, 0); i++;
				}

				/*** ready to open the window ... ***/
				set(window,MUIA_Window_Open,TRUE);

				while(running)
				{
					switch(DoMethod(app,MUIM_Application_Input,&signals))
					{
						case MUIV_Application_ReturnID_Quit:
							running = FALSE;
							break;
					}

					if(running && signals)
						Wait(signals);
				}

				set(window, MUIA_Window_Open, FALSE);
			}
			else
				printf("Failed to create Application.\n");

			/*** shutdown ***/
			MUI_DisposeObject(app);      /* dispose all objects. */

			MUI_DeleteCustomClass(cl_ddlisttree);
		}

		MUI_DeleteCustomClass(cl_ddstring);
	}

	return(0);
}

