/* projlist.c
 * Copyright (C) 1990 Commodore-Amiga, Inc.
 * written by David N. Junod
 *
 * maintain a list of projects
 *
 */

#include <libraries/appshell.h>	/* library structure definitions */
#include <clib/appshell_protos.h>
#include "projlist.h"		/* application structure definitions */

extern struct WBStartup *WBenchMsg;

/* Main processing loop */
VOID main (int argc, char **argv)
{

    HandleApp (argc, argv, WBenchMsg, Our_App);
}

VOID ShowProjectIcon (struct AppInfo * ai, STRPTR cmd, struct TagItem * tl)
{
    struct ProjNode *pn;
    struct DiskObject *dob = NULL;
    struct Image *im = NULL;
    struct Gadget *gad;
    struct Window *win;
    STRPTR name = NULL;
    struct List *list;
    struct Project *pi;

    /* default to the AppInfo Project structure */
    pi = &(ai->ai_Project);

    /* see if there was a tag for a project list */
    if (tl)
	pi = (struct Project *) GetTagData (APSH_ProjInfo, (ULONG) pi, tl);

    /* get a pointer to our project list */
    list = &(pi->p_ProjList);

    /* set the appropriate state of the select and remove function */
    if (pi->p_NumProjs > 0L)
    {
	PerfFunc (ai, NULL, "enable select remove", NULL);
    }
    else
    {
	PerfFunc (ai, NULL, "disable select remove", NULL);
    }

    /* are we at the minimum? */
    if (pi->p_CurLine <= 0)
    {
	pi->p_CurLine = 0;

	/* calling a function table entry using a command string */
	PerfFunc (ai, NULL, "disable previous", NULL);
    }
    else
	PerfFunc (ai, NULL, "enable previous", NULL);

    /* are we at the maximum? */
    if (pi->p_CurLine >= (pi->p_NumProjs - 1))
    {
	pi->p_CurLine = (pi->p_NumProjs - 1);
	PerfFunc (ai, NULL, "disable next", NULL);
    }
    else
	PerfFunc (ai, NULL, "enable next", NULL);

    /* get the current project node */
    if (pn = GetProjNode (ai, pi->p_CurLine, tl))
    {
	/* get the name and image for the current project so that we can
	 * display it. */
	dob = pn->pn_DObj;
	if (dob)
	    im = (struct Image *) dob->do_Gadget.GadgetRender;
	name = pn->pn_ProjName;
    }

    /*
     * Always use APSHGetGadgetInfo to get a pointer to a gadget.  If the
     * user closes the window and then reopens it, the gadget and window will
     * have a different address.   OR perhaps the window is really not even
     * open. */
    if (APSHGetGadgetInfo (ai, "MAIN", "LIST", (ULONG *) & win, (ULONG *) & gad))
    {
	/* compute the top line --- shouldn't do when click in list */
	if (pi->p_State == 1)
	{
	    GT_SetGadgetAttrs (gad, win, NULL,
			       GTLV_Selected, pi->p_CurLine,
			       TAG_DONE);
	}
	else if (pi->p_State == 3)
	{
	    pi->p_TopView = MAX ((pi->p_CurLine - 3L), 0L);

	    GT_SetGadgetAttrs (gad, win, NULL,
			       GTLV_Labels, list,
			       GTLV_Selected, pi->p_CurLine,
			       GTLV_Top, pi->p_TopView,
			       TAG_DONE);
	}
	else
	{
	    pi->p_TopView = MAX ((pi->p_CurLine - 3L), 0L);

	    GT_SetGadgetAttrs (gad, win, NULL,
			       GTLV_Selected, pi->p_CurLine,
			       GTLV_Top, pi->p_TopView,
			       TAG_DONE);
	}
    }
}

/* Call before modifying a project list when it's attached to a Scrolling
 * List */
VOID BModListFunc (struct AppInfo * ai, STRPTR cmd, struct TagItem * tl)
{
    struct Gadget *gad;
    struct Window *win;

    if (APSHGetGadgetInfo (ai, "MAIN", "LIST", (ULONG *) & win, (ULONG *) & gad))
    {
	/* You must set a Scrolling List label to ~0 before modifying it */
	GT_SetGadgetAttrs (gad, win, NULL, GTLV_Labels, ~0, TAG_END);
    }
}

/* Call after modifying a project list. */
VOID AModListFunc (struct AppInfo * ai, STRPTR cmd, struct TagItem * tl)
{
    struct Project *pi;

    /* default to the AppInfo Project structure */
    pi = &(ai->ai_Project);

    /* see if there was a tag for a project list */
    if (tl)
	pi = (struct Project *) GetTagData (APSH_ProjInfo, (ULONG) pi, tl);

    /* total refresh */
    pi->p_State = 3;

    /* refresh the view */
    ShowProjectIcon (ai, cmd, tl);
}

VOID NewFunc (struct AppInfo * ai, STRPTR cmd, struct TagItem * tl)
{
    STRPTR clone = NULL, argv[MAXARG], name = NULL;
    ULONG argc = 0L;

    /*
     * Turn off the list view.  How to call a function table entry using a
     * function ID.
     */
    PerfFunc (ai, BModListID, NULL, tl);

    /* parse the command line */
    clone = BuildParseLine (cmd, &argc, argv);

    /* make sure we have some arguments */
    if (argc >= 2L)
    {
	/* get the name from the first argument [ZZZ: ignoring the rest]
	 * look at the remove function to see how to do multiple names */
	name = argv[1];
    }
    else if (tl)
    {
	/* get the name from the name tag */
	name = (STRPTR) GetTagData (APSH_NameTag, NULL, tl);
    }

    /* create a new project */
    NewProject (ai, name, tl);

    /* turn on the list view */
    PerfFunc (ai, AModListID, NULL, tl);

    /* free the parsed line */
    FreeParseLine (clone);
}

VOID QuitFunc (struct AppInfo * ai, STRPTR cmd, struct TagItem * tl)
{

    ai->ai_Done = TRUE;
}

VOID OkayFunc (struct AppInfo * ai, STRPTR cmd, struct TagItem * tl)
{

    ai->ai_Done = TRUE;
}

VOID CancelFunc (struct AppInfo * ai, STRPTR cmd, struct TagItem * tl)
{

    /* we're all done with this requester */
    ai->ai_Done = TRUE;
}

VOID PreviousFunc (struct AppInfo * ai, STRPTR cmd, struct TagItem * tl)
{
    struct Project *pi;

    /* default to the AppInfo Project structure */
    pi = &(ai->ai_Project);

    /* see if there was a tag for a project list */
    if (tl)
	pi = (struct Project *) GetTagData (APSH_ProjInfo, (ULONG) pi, tl);

    /* make sure the current project is in the middle of the view */
    pi->p_State = 2;

    /* move backwards through the list */
    pi->p_CurLine--;

    /* display the project list */
    ShowProjectIcon (ai, cmd, tl);
}

VOID NextFunc (struct AppInfo * ai, STRPTR cmd, struct TagItem * tl)
{
    struct Project *pi;

    /* default to the AppInfo Project structure */
    pi = &(ai->ai_Project);

    /* see if there was a tag for a project list */
    if (tl)
	pi = (struct Project *) GetTagData (APSH_ProjInfo, (ULONG) pi, tl);

    pi->p_State = 2;
    pi->p_CurLine++;
    ShowProjectIcon (ai, cmd, tl);
}

VOID RemoveFunc (struct AppInfo * ai, STRPTR cmd, struct TagItem * tl)
{
    STRPTR clone = NULL, argv[MAXARG], name = NULL;
    ULONG argc = 0L, cntri;

    /* turn off the list view */
    PerfFunc (ai, BModListID, NULL, tl);

    /* parse the command line */
    clone = BuildParseLine (cmd, &argc, argv);

    /* see if anything was passed in the command string */
    if (argc >= 2L)
    {
	/* remove every name that was passed. */
	for (cntri=1; cntri<argc; cntri++)
	    RemoveProject (ai, argv[cntri], tl);
    }
    else
    {
	if (tl)
	{
	    /* see if a name was passed via a tag list */
	    name = (STRPTR) GetTagData (APSH_NameTag, NULL, tl);
	}

	/* remove the current project */
	RemoveProject (ai, name, tl);
    }

    /* turn the list view back on */
    PerfFunc (ai, AModListID, NULL, tl);

    /* free the built parse line */
    FreeParseLine (clone);
}

/* This is the basic SELECT function.  It doesn't incorporate the NEXT,
 * PREVIOUS, TOP and BOTTOM keywords. */
VOID SelectFunc (struct AppInfo * ai, STRPTR cmd, struct TagItem * tl)
{
    struct Project *pi;
    struct Gadget *gad;
    STRPTR name = NULL, clone=NULL, argv[MAXARG];
    ULONG argc = 0L;

    /* default to the AppInfo Project structure */
    pi = &(ai->ai_Project);

    /* parse the command string */
    clone = BuildParseLine (cmd, &argc, argv);

    /* make sure we have some parameters to work with */
    if (argc >= 2L)
    {
	name = argv[1];
    }
    else if (tl)
    {
	/* see if there was a tag for a project list */
	pi = (struct Project *) GetTagData (APSH_ProjInfo, (ULONG) pi, tl);

	if (gad = (struct Gadget *) GetTagData (APSH_MsgIAddress, NULL, tl))
	    name = (STRPTR)(((struct StringInfo *)gad->SpecialInfo)->Buffer);
	else
	    name = (STRPTR) GetTagData (APSH_NameTag, NULL, tl);
    }

    /* make sure we have a name to select before continuing */
    if (name)
    {
	struct ProjNode *pn;
	struct List *list;

	/* get a pointer to our project list */
	list = &(pi->p_ProjList);

	/* See if we can find the name in the project list.  Always use
	 * the case-insensitive FindNameI when searching AppShell lists. */
	if (pn = (struct ProjNode *) FindNameI (list, name))
	{
	    /* set the current project to the requested one */
	    pi->p_CurLine = pn->pn_ID;

	    /* minor update */
	    pi->p_State = 3;

	    /* update the view */
	    ShowProjectIcon (ai, cmd, tl);
	}
    }

    /* free the parsed line */
    FreeParseLine (clone);
}

/* This is the private function that gets called whenever the user selects
 * the Scrolling List gadget */
VOID ListFunc (struct AppInfo * ai, STRPTR cmd, struct TagItem * tl)
{
    struct Project *pi;

    /* default to the AppInfo Project structure */
    pi = &(ai->ai_Project);

    /* see if there was a tag for a project list */
    if (tl)
	pi = (struct Project *) GetTagData (APSH_ProjInfo, (ULONG) pi, tl);

    pi->p_State = 1;

    /* get the current line */
    pi->p_CurLine = GetTagData (APSH_MsgCode, NULL, tl);

    /* update the view */
    ShowProjectIcon (ai, cmd, tl);
}

/* this function is limited in that it only works from a ALT clicking in
 * the Scrolling List gadget.  Should be set up to take its arguments from
 * the command string as well as from a tag array */
VOID SwapFunc (struct AppInfo * ai, STRPTR cmd, struct TagItem * tl)
{
    struct ProjNode *pn1, *pn2;
    struct Project *pi;

    /* turn off the list view */
    PerfFunc (ai, BModListID, NULL, tl);

    /* default to the AppInfo Project structure */
    pi = &(ai->ai_Project);

    if (tl)
    {
	pi = (struct Project *) GetTagData (APSH_ProjInfo, (ULONG) pi, tl);
    }

    /* get the current line */
    pi->p_CurLine = GetTagData (APSH_MsgCode, NULL, tl);

    pn1 = pi->p_CurProj;
    pn2 = GetProjNode (ai, pi->p_CurLine, tl);

    SwapProjNodes (ai, pn1, pn2, tl);

    /* turn on the list view */
    PerfFunc (ai, AModListID, NULL, tl);
}
