/************************************************************************
 *                                                                      *
 *                            Preliminary                               *
 *                        Amiga AppShell (tm)                           *
 *                                                                      *
 *  Copyright (c) 1990,1991 Commodore-Amiga, Inc. All Rights Reserved.  *
 *                                                                      *
 *   This software and information is proprietary, preliminary, and     *
 *   subject to change without notice.                                  *
 *                                                                      *
 *                            DISCLAIMER                                *
 *                                                                      *
 *   THIS SOFTWARE IS PROVIDED "AS IS".                                 *
 *   NO REPRESENTATIONS OR WARRANTIES ARE MADE WITH RESPECT TO THE      *
 *   ACCURACY, RELIABILITY, PERFORMANCE, CURRENTNESS, OR OPERATION      *
 *   OF THIS SOFTWARE, AND ALL USE IS AT YOUR OWN RISK.                 *
 *   NEITHER COMMODORE NOR THE AUTHORS ASSUME ANY RESPONSIBILITY OR     *
 *   LIABILITY WHATSOEVER WITH RESPECT TO YOUR USE OF THIS SOFTWARE.    *
 *                                                                      *
 *                          Non-Disclosure                              *
 *                                                                      *
 *   This information is not to be disclosed to any other company,      *
 *   individual or party.  Discussion is to be restricted to CBM        *
 *   approved discussion areas, such as the closed conferences on bix;  *
 *   amiga.cert, amiga.com, amiga.beta/appshell.                        *
 *                                                                      *
 ************************************************************************
 * Copyright (C) 1990 Commodore-Amiga, Inc.
 * written by David N. Junod
 */

#include <exec/types.h>
#include <exec/lists.h>
#include <exec/nodes.h>
#include <exec/memory.h>
#include <utility/hooks.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/dosasl.h>
#include <libraries/asl.h>
#include <libraries/appshell.h>
#include <workbench/startup.h>
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/appshell_protos.h>
#include <clib/appobjects_protos.h>
#include <clib/utility_protos.h>
#include <pragmas/exec.h>
#include <pragmas/dos.h>
#include <pragmas/appshell.h>
#include <pragmas/appobjects.h>
#include <pragmas/utility.h>
#include <string.h>

extern struct Library *SysBase, *AppObjectsBase, *UtilityBase, *DOSBase;
extern struct WBStartup *WBenchMsg;
struct Library *AppShellBase;

#if 1
#include "main.c"
#else
/* Main processing loop */
VOID main (int argc, char **argv)
{
    extern struct TagItem Our_App[];

    /* open the AppShell library */
    if (AppShellBase = OpenLibrary ("appshell.library", 36))
    {
	/* Main AppShell entry point */
	HandleApp (argc, argv, WBenchMsg, Our_App);

	/* close the AppShell library */
	CloseLibrary (AppShellBase);
    }
}
#endif

ULONG AddObj (struct ObjectInfo * oi, struct Window * win, ULONG data,...)
{
    return (AddObjList (oi, win, (struct TagItem *) & data));
}

ULONG DelObj (struct ObjectInfo * oi, struct Window * win, ULONG data,...)
{
    return (RemoveObjList (oi, win, (struct TagItem *) & data));
}

/* handle messages between function handlers */
BOOL HandlerFunc (struct AppInfo * ai, ULONG tags,...)
{
    return (HandlerFuncA (ai, (struct TagItem *) & tags));
}

/* get handler data */
APTR HandlerData (struct AppInfo * ai, ULONG tags,...)
{
    return (HandlerDataA (ai, (struct TagItem *) & tags));
}

VOID callfunc (VOID (*func) (), struct AppInfo * ai, STRPTR cmd, ULONG data,...)
{
    (*(func)) (ai, cmd, (struct TagItem *) & data);
}

struct Node *NPrintf (struct List *l, STRPTR buffer, LONG size, VOID *fmt, VOID *data, ...)
{
    struct Node *n = NULL;
    STRPTR buff = buffer;
    LONG msize;

    /* Do we have a buffer to work with? */
    if (!buff)
    {
	/* Allocate our own buffer */
	buff = (STRPTR) AllocVec (512L, MEMF_CLEAR);
    }

    /* Make sure we have a buffer to copy to */
    if (buff)
    {
	/* Build the string */
	sprintf (buff, fmt, data);

	/* How much room do we need */
	msize = sizeof (struct Node) + strlen (buff) + 1L;

	/* Allocate a node to hold the tool type */
	if (n = (struct Node *) AllocVec (msize, MEMF_CLEAR))
	{
	    /* Copy the string into the node */
	    n->ln_Name = MEMORY_FOLLOWING (n);
	    strcpy (n->ln_Name, buff);

	    /* Add the node to the end of the list */
	    AddTail (l, n);
	}
    }

    /* Did we allocate the buffer? */
    if (buff && (buff != buffer))
    {
	/* Free the buffer */
	FreeVec (buff);
    }

    return (n);
}

struct Node *MakeNode (struct List * list, STRPTR name)
{
    struct Node *node = NULL;

    if (list && name)
    {
	LONG msize;

	/* Compute the size of the memory allocation */
	msize = sizeof (struct Node) + strlen (name) + 2L;

	/* Allocate the node */
	if (node = (struct Node *) AllocVec (msize, MEMF_CLEAR))
	{
	    node->ln_Name = MEMORY_FOLLOWING (node);

	    /* Copy the name over */
	    strcpy (node->ln_Name, name);

	    /* Add the node to the list */
	    AddTail (list, node);
	}
    }

    return (node);
}

LONG MakeNodes (struct List * list, STRPTR * text, LONG st, LONG num)
{
    LONG cnt = 0L;

    if (list && text)
    {
	STRPTR name;
	LONG i;

	for (i = 0; i < num; i++)
	{
	    if ((name = text[(st + i)]) && MakeNode (list, name))
	    {
		cnt++;
	    }
	    else
	    {
		i = num;
	    }
	}
    }
    return (cnt);
}

/* All nodes on the list must have been allocated using AllocVec() */
VOID
FreeExecList (struct List * list, ULONG (*func) (), ULONG data,...)
{
    /* Make sure we have a list */
    if (list)
    {
	/* Make sure there are entries in the list */
	if (list->lh_TailPred != (struct Node *) list)
	{
	    struct Node *node, *nxtnode;
	    ULONG cnt = 0L;

	    /* Let's start at the very beginning... */
	    node = list->lh_Head;

	    /* Continue while there are still nodes to remove */
	    while (nxtnode = node->ln_Succ)
	    {
		/* Remove the node from the list */
		Remove (node);

		/* Do we have a special removal hook? */
		if (func)
		{
		    /* Call the special removal routine, passing the node */
		    (*(func)) (node, cnt, (VOID *) & data);
		}

		/* Free the node itself */
		FreeVec ((APTR) node);

		/* Go on to the next node */
		node = nxtnode;
		cnt++;
	    }
	}
    }
}

/* Perform an operation on all members of a list */
VOID HandleList (struct List * list, VOID (*func)(struct Node *, ULONG, void *, ...), void *data,...)
{
    struct Node *node;
    ULONG cnt;

    for (node = list->lh_Head, cnt = 0;
	 node->ln_Succ;
	 node = node->ln_Succ, cnt++)
    {
	(*(func))(node, cnt, (VOID *) &data);
    }
}

struct Node *FindSelected (struct List * list, WORD num)
{
    struct Node *node;

    for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ)
    {
	if (num-- == 0)
	{
	    return (node);
	}
    }

    return (NULL);
}

BOOL CopyImage (struct Image * src, struct Image * dst)
{
    BOOL retval = FALSE;

    if (src && dst)
    {
	int msize;

	/* Copy the Image structure */
	CopyMem (src, dst, sizeof (struct Image));

	/* Don't go pointing off into nowhere land */
	dst->NextImage = NULL;

	/* Compute the size of the image data needed */
	msize = RASSIZE (src->Width, src->Height) * src->Depth;

	/* Allocate the image data */
	if (dst->ImageData = (USHORT *)
	    AllocVec (msize, MEMF_CLEAR | MEMF_CHIP))
	{
	    /* Copy image data */
	    CopyMem (src->ImageData, dst->ImageData, msize);

	    /* Indicate success */
	    retval = TRUE;
	}
    }

    return (retval);
}

VOID FreeImage (struct Image * im)
{

    if (im && im->ImageData)
    {
	FreeVec (im->ImageData);
	im->ImageData = NULL;
    }
}

/* Get the file requester set up properly.  Returns 0 if no file node
 * present, returns > 0 if there is a file node.  */
LONG FixFileAndPath (struct FileRequester *rf, STRPTR name)
{
    LONG count = 0L;

    if (rf)
    {
	if (name)
	{
	    stcgfp (rf->rf_Dir, name);
	    count = (LONG) stcgfn (rf->rf_File, name);
	}
	else
	{
	    WORD dlen = (strlen (rf->rf_Dir) - 1);

	    if ((dlen > 0) && (rf->rf_Dir[dlen] == '/'))
	    {
		rf->rf_Dir[dlen] = 0;
	    }
	}
    }

    return (count);
}

/* Return the protection bits for a file */
LONG GetProtection (STRPTR name)
{
    struct FileInfoBlock __aligned fib;
    LONG ret = (-1L);
    BPTR lock;

    /* Get a lock on the file */
    if (lock = Lock (name, SHARED_LOCK))
    {

	/* Examine the file */
	if (Examine (lock, &fib))
	{
	    /* Get the protection bits */
	    ret = fib.fib_Protection;
	}

	/* Unlock the old lock */
	UnLock (lock);
    }

    return (ret);
}
