/****************************************************************************
*
* $RCSfile: DocketEditor.c $
* $Revision: 1.6 $
* $Date: 1997/09/16 00:25:37 $
* $Author: ssolie $
*
*****************************************************************************
*
* Copyright (c) 1997 Software Evolution.  All Rights Reserved.
*
*****************************************************************************
*
* DocketEditor.c -- DocketEditor class source file
*
* This file contains all the source code for DocketEditor objects.
*/

#include <classact.h>
#include <classes/window.h>
#include <exec/memory.h>
#include <gadgets/button.h>
#include <gadgets/layout.h>
#include <gadgets/listbrowser.h>
#include <intuition/icclass.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>

#include <clib/alib_protos.h>
#include <clib/alib_stdio_protos.h>
#include <proto/button.h>
#include <proto/exec.h>
#include <proto/gadtools.h>
#include <proto/intuition.h>
#include <proto/layout.h>
#include <proto/listbrowser.h>
#include <proto/window.h>

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

#include "Debug.h"
#include "DocketEditor.h"
#include "LibraryManager.h"
#include "LocaleManager.h"
#include "ChangeGadget.h"
#include "AboutReq.h"
#include "ItemEditor.h"

#define GetString(x)	(getString(locale_mgr, x, x##_STR))


/*** Global variables ***/
IMPORT LocaleManager		locale_mgr;
IMPORT struct ExecBase		*SysBase;
IMPORT struct IntuitionBase	*IntuitionBase;
struct Library				*GadToolsBase;
struct ClassLibrary			*ButtonBase;
struct ClassLibrary			*ChooserBase;
struct ClassLibrary			*ClickTabBase;
struct ClassLibrary			*IntegerBase;
struct ClassLibrary			*LabelBase;
struct ClassLibrary			*LayoutBase;
struct ClassLibrary			*ListBrowserBase;
struct ClassLibrary			*StringBase;
struct ClassLibrary			*WindowBase;


/*** Local definitions ***/
#define STRING_BUFFER_SIZE	1024	/* string buffer */

#define GADTOOLS_LIB		"gadtools.library"
#define GADTOOLS_VER		39
#define WINDOW_CLASS		"window.class"
#define WINDOW_VER			42
#define LAYOUT_GADGET		"gadgets/layout.gadget"
#define LAYOUT_VER			42
#define LISTBROWSER_GADGET	"gadgets/listbrowser.gadget"
#define LISTBROWSER_VER		41
#define BUTTON_GADGET		"gadgets/button.gadget"
#define BUTTON_VER			41
#define LABEL_IMAGE			"images/label.image"
#define LABEL_VER			41
#define CHOOSER_GADGET		"gadgets/chooser.gadget"
#define CHOOSER_VER			41
#define CLICKTAB_GADGET		"gadgets/clicktab.gadget"
#define CLICKTAB_VER		41
#define INTEGER_GADGET		"gadgets/integer.gadget"
#define INTEGER_VER			41
#define STRING_GADGET		"gadgets/string.gadget"
#define STRING_VER			41

#define GADGET_ITEMS		1
#define GADGET_NEW			2
#define GADGET_EDIT			3
#define GADGET_REMOVE		4

#define MENU_PROJECT		0
#define MENU_SAVE			0
#define MENU_HIDE			2
#define MENU_ABOUT			4
#define MENU_QUIT			6

enum {
	COLUMN_TYPE,			/* type column number */
	COLUMN_WHEN,			/* when column number */
	COLUMN_COMMAND,			/* command column number */
	COLUMN_COUNT			/* number of columns */
};


/*** Local constants ***/
const UWORD 	WINDOW_WIDTH			= 600;	/* default width */
const UWORD 	WINDOW_HEIGHT			= 200;	/* default height */
const WORD		TYPE_PERCENT_WIDTH		= 20;	/* "Type" % width */
const WORD		WHEN_PERCENT_WIDTH		= 30;	/* "When" % width */
const WORD		COMMAND_PERCENT_WIDTH	= 50;	/* "Command" % width */


/*** Local data types ***/
struct DocketEditorClass {
	Docket docket;					/* reference to docket object */
	LibraryManager lib_mgr;			/* extra library manager */
	BOOL quit;						/* quit flag */
	BOOL hide;						/* hide flag */

	struct Screen *screen;			/* Screen pointer */
	struct DrawInfo *draw_info;		/* DrawInfo pointer */
	APTR visual_info;				/* VisualInfo pointer */

	APTR editor_window;				/* editor window object */
	struct Window *window;			/* editor window pointer */
	struct Menu *menu;				/* editor window menu bar */

	APTR items_browser;				/* items browser object */
	struct List browser_list;		/* items browser list */
	APTR edit_button;				/* edit button object */
	APTR remove_button;				/* remove button object */

	AboutReq about_req;				/* about requester object */
	ItemEditor item_editor;			/* docket item editor object */
	struct Node *edited_node;		/* edited docket item node */
	DocketItem edited_item;			/* edited docket item */
};

typedef struct {
	APTR *base;			/* pointer to base pointer */
	STRPTR name;		/* library name */
	ULONG version;		/* library version */
} LibraryTemplate;


/*** Local function prototypes ***/
STATIC BOOL open_libs(LibraryManager lib_mgr);
STATIC BOOL open_window(DocketEditor this);
STATIC BOOL create_menu(DocketEditor this);
STATIC STRPTR get_type_string(DocketItem docket_item);
STATIC STRPTR get_when_string(DocketItem docket_item);
STATIC STRPTR get_command_string(DocketItem docket_item);
STATIC VOID process_gadget_event(DocketEditor this, WORD gadget_id);
STATIC VOID process_menu_event(DocketEditor this, UWORD menu_num);
STATIC VOID new_item(DocketEditor this);
STATIC VOID edit_item(DocketEditor this);
STATIC VOID remove_item(DocketEditor this);
STATIC VOID refresh_item(DocketEditor this);


/*
 * newDocketEditor -- New DocketEditor
 *
 * Creates a new docket editor window and displays it on the default
 * public screen.  Returns a reference to the DocketEditor object or NULL
 * on error.
 */
DocketEditor newDocketEditor(Docket docket)
{
	DocketEditor this;

	D(bug("newDocketEditor(%08lx)\n", docket));

	if ( docket == NULL )
		return(NULL);

	/*** Create the object ***/
	this = AllocVec(sizeof(struct DocketEditorClass), MEMF_CLEAR);
	if ( this == NULL )
		return(NULL);

	/*** Initialize attributes ***/
	this->docket = docket;
	this->hide = FALSE;
	this->quit = FALSE;
	NewList(&this->browser_list);

	/*** Open GUI libraries and classes ***/
	this->lib_mgr = newLibraryManager(NULL);
	if ( open_libs(this->lib_mgr) == FALSE )  {
		deleteLibraryManager(this->lib_mgr);
		FreeVec(this);
		return(NULL);
	}

	/*** Get the Intuition resources we need ***/
	this->screen = LockPubScreen(NULL);
	if ( this->screen == NULL )  {
		D2(bug(" cannot lock default public screen\n"));
		deleteDocketEditor(this);
		return(NULL);
	}

	this->visual_info = GetVisualInfoA(this->screen, NULL);
	this->draw_info = GetScreenDrawInfo(this->screen);

	if ( this->visual_info == NULL || this->draw_info == NULL )  {
		D2(bug(" cannot get graphic info\n"));
		deleteDocketEditor(this);
		return(NULL);
	}

	if ( open_window(this) == FALSE )  {
		D2(bug(" cannot open editor window\n"));
		deleteDocketEditor(this);
		return(NULL);
	}

	this->item_editor = newItemEditor(this->screen, this->draw_info,
		this->window->UserPort);
	if ( this->item_editor == NULL )  {
		D2(bug(" cannot create item editor object\n"));
		deleteDocketEditor(this);
		return(NULL);
	}

	return(this);
}


/*
 * deleteDocketEditor -- Delete DocketEditor object
 *
 * Deletes a DocketEditor object, closes any windows and frees all its
 * resources.
 */
VOID deleteDocketEditor(DocketEditor this)
{
	D(bug("deleteDocketEditor(%08lx)\n", this));

	if ( this == NULL )
		return;

	deleteItemEditor(this->item_editor);
	deleteAboutReq(this->about_req);

	DisposeObject(this->editor_window);
	FreeListBrowserList(&this->browser_list);
	FreeMenus(this->menu);

	if ( this->screen != NULL )  {
		FreeScreenDrawInfo(this->screen, this->draw_info);
		FreeVisualInfo(this->visual_info);
		UnlockPubScreen(NULL, this->screen);
	}

	deleteLibraryManager(this->lib_mgr);

	FreeVec(this);
}


/*
 * getDocketEditorSignal -- Get DocketEditor signal
 *
 * Returns the DocketEditor signal mask or NULL if the window is not open.
 */
ULONG getDocketEditorSignal(DocketEditor this)
{
	ULONG signal;

	D(bug("getDocketEditorSignal(%08lx)\n", this));

	if ( this == NULL )
		return(NULL);
	else  {
		GetAttr(WINDOW_SigMask, this->editor_window, &signal);
		return(signal);
	}
}


/*
 * handleDocketEditorSignal -- Handle DocketEditor signal
 *
 * Handles the receipt of a DocketEditor signal by processing and acting
 * on any messages present at the message port. Returns several values
 * as follows:
 *		DOCKETEDITOR_ERROR	- error
 *		DOCKETEDITOR_OK		- OK
 *		DOCKETEDITOR_HIDE	- hide editor
 *		DOCKETEDITOR_QUIT	- quit docket
 */
LONG handleDocketEditorSignal(DocketEditor this)
{
	ULONG class, result;
	UWORD menu_num;
	WORD code, gadget_id;
	BOOL done_about_req, done_item_editor;

	D(bug("handleDocketEditorSignal(%08lx)\n", this));

	if ( this == NULL || this->editor_window == NULL )
		return(DOCKETEDITOR_ERROR);

	/*** Handle messages for the about requester ***/
	if ( this->about_req != NULL )  {
		done_about_req = handleAboutReqSignal(this->about_req);
		if ( done_about_req == TRUE )  {
			deleteAboutReq(this->about_req);
			this->about_req = NULL;
		}
	}

	/*** Handle messages for the item editor ***/
	done_item_editor = handleItemEditorSignal(this->item_editor);
	if ( done_item_editor == TRUE )  {
		closeItemEditor(this->item_editor);
		SetAttrs(this->editor_window, WA_BusyPointer, FALSE, TAG_END);
		if ( this->edited_item != NULL )  {
			refresh_item(this);
			this->edited_node = NULL;
			this->edited_item = NULL;
		}
	}

	/*** Handle messages for the docket editor ***/
	this->hide = FALSE;
	this->quit = FALSE;
	result = DoMethod(this->editor_window, WM_HANDLEINPUT, &code);
	while ( result != WMHI_LASTMSG && !this->hide && !this->quit )  {
		class = result & WMHI_CLASSMASK;
		switch ( class )  {
			case WMHI_MENUPICK:
				menu_num = (UWORD)(result & WMHI_MENUMASK);
				process_menu_event(this, menu_num);
				break;
			case WMHI_GADGETUP:
				gadget_id = (WORD)(result & WMHI_GADGETMASK);
				process_gadget_event(this, gadget_id);
				break;
			case WMHI_NEWSIZE:
				D2(bug(" WMHI_NEWSIZE\n"));
				break;
			case WMHI_CLOSEWINDOW:
				this->hide = TRUE;
				break;
			default:
				D2(bug(" unknown class=%lx code=%lx\n", class, code));
		}

		result = DoMethod(this->editor_window, WM_HANDLEINPUT, &code);
	}

	if ( this->quit == TRUE )
		return(DOCKETEDITOR_QUIT);
	else if ( this->hide == TRUE )
		return(DOCKETEDITOR_HIDE);
	else
		return(DOCKETEDITOR_OK);
}


/*
 * open_libs -- Open libraries for DocketEditor
 *
 * This private function opens the libraries for a DocketEditor object.
 * Returns TRUE if successful or FALSE on error.
 */
STATIC BOOL open_libs(LibraryManager lib_mgr)
{
	STATIC LibraryTemplate libs[] = {
		{(APTR*)&GadToolsBase, GADTOOLS_LIB, GADTOOLS_VER},
		{(APTR*)&WindowBase, WINDOW_CLASS, WINDOW_VER},
		{(APTR*)&LayoutBase, LAYOUT_GADGET, LAYOUT_VER},
		{(APTR*)&ListBrowserBase, LISTBROWSER_GADGET, LISTBROWSER_VER},
		{(APTR*)&ButtonBase, BUTTON_GADGET, BUTTON_VER},
		{(APTR*)&LabelBase, LABEL_IMAGE, LABEL_VER},
		{(APTR*)&ChooserBase, CHOOSER_GADGET, CHOOSER_VER},
		{(APTR*)&ClickTabBase, CLICKTAB_GADGET, CLICKTAB_VER},
		{(APTR*)&IntegerBase, INTEGER_GADGET, INTEGER_VER},
		{(APTR*)&StringBase, STRING_GADGET, STRING_VER},
		{NULL}
	};
	struct Library *library;
	UWORD i;

	D2(bug(" open_libs(%08lx)\n", lib_mgr));

	if ( lib_mgr == NULL )
		return(FALSE);

	i = 0;
	while ( libs[i].base != NULL )  {
		library = openLibrary(lib_mgr, libs[i].name, libs[i].version);
		if ( library == NULL )  {
			D2(bug("  failed to open library %s %ld\n",
				libs[i].name, libs[i].version));
			return(FALSE);
		}

		*(libs[i].base) = library;
		i++;
	}

	return(TRUE);
}


/*
 * open_window -- Open docket editor window
 *
 * This private function opens the docket editor window and presents it to
 * the user.  Returns TRUE if successful or FALSE on error.
 */
STATIC BOOL open_window(DocketEditor this)
{
	STATIC struct ColumnInfo item_cols[COLUMN_COUNT + 1];
	DocketItem docket_item;
	struct Node *browser_node;

	if ( this == NULL )
		return(FALSE);

	/*** Create the menu bar ***/
	if ( create_menu(this) == FALSE )  {
		D2(bug(" cannot create menu\n"));
		return(FALSE);
	}

	/*** Prepare docket item list browser ***/
	item_cols[0].ci_Width = TYPE_PERCENT_WIDTH;
	item_cols[0].ci_Title = GetString(MSG_TYPE_COL);
	item_cols[0].ci_Flags = NULL;
	item_cols[1].ci_Width = WHEN_PERCENT_WIDTH;
	item_cols[1].ci_Title = GetString(MSG_WHEN_COL);
	item_cols[1].ci_Flags = NULL;
	item_cols[2].ci_Width = COMMAND_PERCENT_WIDTH;
	item_cols[2].ci_Title = GetString(MSG_COMMAND_COL);
	item_cols[2].ci_Flags = NULL;
	item_cols[3].ci_Width = -1;

	docket_item = firstDocketItem(this->docket);
	while ( docket_item != NULL )  {
		browser_node = AllocListBrowserNode(COLUMN_COUNT,
			LBNA_Column, COLUMN_TYPE,
			LBNCA_CopyText, TRUE,
			LBNCA_Text, get_type_string(docket_item),
			LBNA_Column, COLUMN_WHEN,
			LBNCA_CopyText, TRUE,
			LBNCA_Text, get_when_string(docket_item),
			LBNA_Column, COLUMN_COMMAND,
			LBNCA_CopyText, TRUE,
			LBNCA_Text, get_command_string(docket_item),
			LBNA_UserData, docket_item,		/* link to the DocketItem */
			TAG_END);
		if ( browser_node == NULL )  {
			D2(bug(" cannot create browser node\n"));
			return(FALSE);
		}

		AddHead(&this->browser_list, browser_node);
		docket_item = nextDocketItem(this->docket);
	}

	/*** Create the GUI objects ***/
	this->editor_window = WindowObject,
		WA_Title, GetString(MSG_DOCKET_EDITOR_TITLE),
		WA_Flags, WFLG_DEPTHGADGET | WFLG_DRAGBAR | WFLG_ACTIVATE |
			WFLG_SIZEGADGET | WFLG_CLOSEGADGET,
		WA_PubScreen, this->screen,
		WA_Width, WINDOW_WIDTH,
		WA_Height, WINDOW_HEIGHT,
		WINDOW_MenuStrip, this->menu,
		WINDOW_Position, WPOS_CENTERSCREEN,
		WINDOW_Layout, LayoutObject,
			GA_DrawInfo, this->draw_info,
			LAYOUT_DeferLayout, TRUE,
			LAYOUT_Orientation, LAYOUT_ORIENT_VERT,
			LAYOUT_HorizAlignment, LAYOUT_ALIGN_CENTER,
			LAYOUT_SpaceOuter, TRUE,

			LAYOUT_AddChild, this->items_browser = ListBrowserObject,
				GA_ID, GADGET_ITEMS,
				GA_RelVerify, TRUE,
				LISTBROWSER_Labels, &this->browser_list,
				LISTBROWSER_ColumnInfo, item_cols,
				LISTBROWSER_ColumnTitles, TRUE,
				LISTBROWSER_ShowSelected, TRUE,
				LISTBROWSER_Separators, TRUE,
				LISTBROWSER_AutoFit, TRUE,
			ListBrowserEnd,
			CHILD_WeightedHeight, 100,

			LAYOUT_AddChild, LayoutObject,
				LAYOUT_Orientation, LAYOUT_ORIENT_HORIZ,
				LAYOUT_EvenSize, TRUE,
				LAYOUT_AddChild, ButtonObject,
					GA_ID, GADGET_NEW,
					GA_Text, GetString(MSG_NEW_BUTTON),
					GA_RelVerify, TRUE,
				ButtonEnd,
				CHILD_NominalSize, TRUE,
				CHILD_WeightedWidth, 0,
				LAYOUT_AddChild, this->edit_button = ButtonObject,
					GA_ID, GADGET_EDIT,
					GA_Text, GetString(MSG_EDIT_BUTTON),
					GA_RelVerify, TRUE,
					GA_Disabled, TRUE,
				ButtonEnd,
				CHILD_NominalSize, TRUE,
				CHILD_WeightedWidth, 0,
				LAYOUT_AddChild, this->remove_button = ButtonObject,
					GA_ID, GADGET_REMOVE,
					GA_Text, GetString(MSG_REMOVE_BUTTON),
					GA_RelVerify, TRUE,
					GA_Disabled, TRUE,
				ButtonEnd,
				CHILD_NominalSize, TRUE,
				CHILD_WeightedWidth, 0,
			LayoutEnd,
			CHILD_WeightedHeight, 0,
		LayoutEnd,
	EndWindow;

	if ( this->editor_window == NULL )  {
		D2(bug(" cannot create editor window object\n"));
		return(FALSE);
	}

	/*** Open the completed window for the user ***/
	this->window = (struct Window*)DoMethod(this->editor_window, WM_OPEN);
	if ( this->window == NULL )  {
		D2(bug(" cannot open editor window\n"));
		return(FALSE);
	}

	return(TRUE);
}


/*
 * create_menu -- Create docket editor menu
 *
 * This private function creates the docket editor menu.  Returns TRUE if
 * successful or FALSE on error.
 */
STATIC BOOL create_menu(DocketEditor this)
{
	STATIC struct NewMenu new_menu[] = {
		{NM_TITLE, NULL, NULL, NULL, NULL, NULL},	/* Project */
		{ NM_ITEM, NULL, NULL, NULL, NULL, NULL},	/*  Save */
		{ NM_ITEM, NM_BARLABEL},
		{ NM_ITEM, NULL, NULL, NULL, NULL, NULL},	/*  Hide */
		{ NM_ITEM, NM_BARLABEL},
		{ NM_ITEM, NULL, NULL, NULL, NULL, NULL},	/*  About... */
		{ NM_ITEM, NM_BARLABEL},
		{ NM_ITEM, NULL, NULL, NULL, NULL, NULL},	/*  Quit */
		{NM_END}
	};
	BOOL result;

	new_menu[0].nm_Label	= GetString(MSG_PROJECT_MENU);
	new_menu[1].nm_Label	= GetString(MSG_SAVE_MENU);
	new_menu[1].nm_CommKey	= GetString(MSG_SAVE_MENU_KEY);
	new_menu[3].nm_Label	= GetString(MSG_HIDE_MENU);
	new_menu[3].nm_CommKey	= GetString(MSG_HIDE_MENU_KEY);
	new_menu[5].nm_Label	= GetString(MSG_ABOUT_MENU);
	new_menu[5].nm_CommKey	= GetString(MSG_ABOUT_MENU_KEY);
	new_menu[7].nm_Label	= GetString(MSG_QUIT_MENU);
	new_menu[7].nm_CommKey	= GetString(MSG_QUIT_MENU_KEY);

	this->menu = CreateMenusA(new_menu, NULL);
	if ( this->menu == NULL )
		return(FALSE);

	result = LayoutMenus(this->menu, this->visual_info,
		GTMN_NewLookMenus, TRUE,
		TAG_END);

	return(result);
}


/*
 * get_type_string -- Get docket item type string
 *
 * This private function gets the docket item type string.  A string is
 * always returned to the caller.
 */
STATIC STRPTR get_type_string(DocketItem docket_item)
{
	STRPTR string;

	switch ( getDocketItemType(docket_item) )  {
		case YEARLY:
			string = GetString(MSG_YEARLY);
			break;
		case MONTHLY:
			string = GetString(MSG_MONTHLY);
			break;
		case WEEKLY:
			string = GetString(MSG_WEEKLY);
			break;
		case DAILY:
			string = GetString(MSG_DAILY);
			break;
		default:
			string = GetString(MSG_UNKNOWN);
	}

	return(string);
}


/*
 * get_when_string -- Get docket item when string
 *
 * This private function gets the docket item when string.  A string is
 * always returned to the caller.
 */
STATIC STRPTR get_when_string(DocketItem docket_item)
{
	STATIC TEXT buffer[STRING_BUFFER_SIZE];
	STRPTR string;

	switch ( getDocketItemType(docket_item) )  {
		case YEARLY:
			switch ( getDocketItemMonth(docket_item) )  {
				case JANUARY:	string = GetString(MSG_JANUARY);	break;
				case FEBRUARY:	string = GetString(MSG_FEBRUARY);	break;
				case MARCH:		string = GetString(MSG_MARCH);		break;
				case APRIL:		string = GetString(MSG_APRIL);		break;
				case MAY:		string = GetString(MSG_MAY);		break;
				case JUNE:		string = GetString(MSG_JUNE);		break;
				case JULY:		string = GetString(MSG_JULY);		break;
				case AUGUST:	string = GetString(MSG_AUGUST);		break;
				case SEPTEMBER:	string = GetString(MSG_SEPTEMBER);	break;
				case OCTOBER:	string = GetString(MSG_OCTOBER);	break;
				case NOVEMBER:	string = GetString(MSG_NOVEMBER);	break;
				case DECEMBER:	string = GetString(MSG_DECEMBER);	break;
				default:		string = GetString(MSG_UNKNOWN);
			}

			sprintf(buffer, "%s %ld %02ld:%02ld:%02ld",
				string,
				getDocketItemMonthDay(docket_item),
				getDocketItemHour(docket_item),
				getDocketItemMinute(docket_item),
				getDocketItemSecond(docket_item));
			break;
		case MONTHLY:
			sprintf(buffer, "%s %ld %02ld:%02ld:%02ld",
				GetString(MSG_DAY),
				getDocketItemMonthDay(docket_item),
				getDocketItemHour(docket_item),
				getDocketItemMinute(docket_item),
				getDocketItemSecond(docket_item));
			break;
		case WEEKLY:
			switch ( getDocketItemWeekDay(docket_item) )  {
				case SUNDAY:	string = GetString(MSG_SUNDAY);		break;
				case MONDAY:	string = GetString(MSG_MONDAY);		break;
				case TUESDAY:	string = GetString(MSG_TUESDAY);	break;
				case WEDNESDAY:	string = GetString(MSG_WEDNESDAY);	break;
				case THURSDAY:	string = GetString(MSG_THURSDAY);	break;
				case FRIDAY:	string = GetString(MSG_FRIDAY);		break;
				case SATURDAY:	string = GetString(MSG_SATURDAY);	break;
				default:		string = GetString(MSG_UNKNOWN);	break;
			}

			sprintf(buffer, "%s %02ld:%02ld:%02ld",
				string,
				getDocketItemHour(docket_item),
				getDocketItemMinute(docket_item),
				getDocketItemSecond(docket_item));
			break;
		case DAILY:
			sprintf(buffer, "%02ld:%02ld:%02ld",
				getDocketItemHour(docket_item),
				getDocketItemMinute(docket_item),
				getDocketItemSecond(docket_item));
			break;
		default:
			strcpy(buffer, GetString(MSG_UNKNOWN));
	}

	return(buffer);
}


/*
 * get_command_string -- Get docket item command string
 *
 * This private function gets the docket item command string.  A string is
 * always returned to the caller.
 */
STATIC STRPTR get_command_string(DocketItem docket_item)
{
	STRPTR string;

	string = getDocketItemCommand(docket_item);
	if ( string == NULL )
		string = GetString(MSG_UNKNOWN);

	return(string);
}


/*
 * process_gadget_event -- Process docket editor gadget event
 *
 * This private function processes a gadget event and takes the appropriate
 * action.
 */
STATIC VOID process_gadget_event(DocketEditor this, WORD gadget_id)
{
	struct Node *node;
	ULONG rel_event;

	if ( this->edited_item != NULL )
		return;

	switch ( gadget_id )  {
		case GADGET_ITEMS:
			GetAttr(LISTBROWSER_RelEvent, this->items_browser, &rel_event);
			if ( rel_event == LBRE_DOUBLECLICK )
				edit_item(this);
			break;
		case GADGET_NEW:
			new_item(this);
			break;
		case GADGET_EDIT:
			edit_item(this);
			break;
		case GADGET_REMOVE:
			remove_item(this);
			break;
		default:
			D2(bug(" bad gadget_id=%ld\n", gadget_id));
	}

	GetAttr(LISTBROWSER_SelectedNode, this->items_browser, (ULONG*)&node);
	if ( node == NULL )  {
		disableGadget(this->window, (struct Gadget*)this->edit_button);
		disableGadget(this->window, (struct Gadget*)this->remove_button);
	}
	else  {
		enableGadget(this->window, (struct Gadget*)this->edit_button);
		enableGadget(this->window, (struct Gadget*)this->remove_button);
	}
}


/*
 * process_menu_event -- Process docket editor menu event
 *
 * This private function processes a menu event and takes the appropriate
 * action.
 */
STATIC VOID process_menu_event(DocketEditor this, UWORD menu_num)
{
	struct MenuItem *menu_item;

	while ( menu_num != MENUNULL && !this->hide && !this->quit )  {
		menu_item = ItemAddress(this->menu, (ULONG)menu_num);
		if ( menu_item == NULL )
			return;

		switch ( MENUNUM(menu_num) )  {
			case MENU_PROJECT:
				switch ( ITEMNUM(menu_num) )  {
					case MENU_SAVE:
						saveDocket(this->docket, DEF_DOCKET_FILE_NAME);
						break;
					case MENU_HIDE:
						this->hide = TRUE;
						break;
					case MENU_ABOUT:
						if ( this->about_req == NULL )  {
							this->about_req = newAboutReq(this->screen,
								this->draw_info, this->window->UserPort);
						}
						break;
					case MENU_QUIT:
						this->quit = TRUE;
						break;
					default:
						D2(bug(" bad menu item=%ld\n", ITEMNUM(menu_num)));
				}
				break;
			default:
				D2(bug(" bad menu=%ld\n", MENUNUM(menu_num)));
		}

		menu_num = menu_item->NextSelect;
	}
}


/*
 * new_item -- New docket item
 *
 * Adds a new item to the docket and automatically opens the item editor.
 */
STATIC VOID new_item(DocketEditor this)
{
	DocketItem item;
	struct Node *node;

	/*** Create new docket item and row for the GUI ***/
	item = addNewDocketItem(this->docket);
	if ( item == NULL )
		return;

	SetGadgetAttrs((struct Gadget*)this->items_browser, this->window, NULL,
		LISTBROWSER_Labels, NULL,
		TAG_END);

	node = AllocListBrowserNode(COLUMN_COUNT,
		LBNA_Column, COLUMN_TYPE,
		LBNCA_CopyText, TRUE,
		LBNCA_Text, get_type_string(item),
		LBNA_Column, COLUMN_WHEN,
		LBNCA_CopyText, TRUE,
		LBNCA_Text, get_when_string(item),
		LBNA_Column, COLUMN_COMMAND,
		LBNCA_CopyText, TRUE,
		LBNCA_Text, get_command_string(item),
		LBNA_UserData, item,
		TAG_END);
	if ( node == NULL )  {
		removeDocketItem(this->docket, item);
		return;
	}

	AddHead(&this->browser_list, node);

	SetGadgetAttrs((struct Gadget*)this->items_browser, this->window, NULL,
		LISTBROWSER_Labels, &this->browser_list,
		LISTBROWSER_AutoFit, TRUE,
		TAG_END);

	/*** Open the item editor for the user ***/
	SetAttrs(this->editor_window, WA_BusyPointer, TRUE, TAG_END);
	openItemEditor(this->item_editor, item);
	this->edited_node = node;
	this->edited_item = item;
}


/*
 * edit_item -- Edit docket item
 *
 * Allows the user to edit a docket item using the docket item editor.
 */
STATIC VOID edit_item(DocketEditor this)
{
	DocketItem docket_item;
	struct Node *node;

	GetAttr(LISTBROWSER_SelectedNode, this->items_browser, (ULONG*)&node);
	if ( node != NULL )  {
		GetListBrowserNodeAttrs(node, LBNA_UserData, &docket_item, TAG_END);
		SetAttrs(this->editor_window, WA_BusyPointer, TRUE, TAG_END);
		openItemEditor(this->item_editor, docket_item);
		this->edited_node = node;
		this->edited_item = docket_item;
	}
}


/*
 * remove_item -- Remove docket item
 *
 * Allows the user to remove a docket item.
 */
STATIC VOID remove_item(DocketEditor this)
{
	DocketItem docket_item;
	struct Node *node;

	GetAttr(LISTBROWSER_SelectedNode, this->items_browser, (ULONG*)&node);
	if ( node != NULL )  {
		GetListBrowserNodeAttrs(node, LBNA_UserData, &docket_item, TAG_END);
		removeDocketItem(this->docket, docket_item);
		DoGadgetMethod((struct Gadget*)this->items_browser, this->window,
			NULL, LBM_REMNODE, NULL, node);
	}
}


/*
 * refresh_item -- Refresh edited docket item
 *
 * Refreshes the docket item which has been edited.  The item imagery will
 * be updated and the item's expiration will be reset.
 */
STATIC VOID refresh_item(DocketEditor this)
{
	ULONG seconds, micros;

	SetGadgetAttrs((struct Gadget*)this->items_browser, this->window, NULL,
		LISTBROWSER_Labels, NULL,
		TAG_END);

	SetListBrowserNodeAttrs(this->edited_node,
		LBNA_Column, COLUMN_TYPE,
		LBNCA_CopyText, TRUE,
		LBNCA_Text, get_type_string(this->edited_item),
		LBNA_Column, COLUMN_WHEN,
		LBNCA_CopyText, TRUE,
		LBNCA_Text, get_when_string(this->edited_item),
		LBNA_Column, COLUMN_COMMAND,
		LBNCA_CopyText, TRUE,
		LBNCA_Text, get_command_string(this->edited_item),
		TAG_END);

	SetGadgetAttrs((struct Gadget*)this->items_browser, this->window, NULL,
		LISTBROWSER_Labels, &this->browser_list,
		LISTBROWSER_AutoFit, TRUE,
		TAG_END);

	/*** Set the expiration on the item to activate it ***/
	CurrentTime(&seconds, &micros);
	setDocketItemExpiration(this->edited_item, seconds);
}
