/*
 * Routines to copy task list to another list.
 * For TaskY and xDataPrefs.
 * Many specific changes for TaskY.
 * 
 * Martin W. Scott, 23 March 1993.
 */
#include <exec/types.h>
#include <exec/tasks.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <string.h>
#include "sprintf.h"
extern struct ExecBase *SysBase;

#include "ptask.h"
static LIST tmplist;
LIST ptlist;
LONG num_ptasks;


void
InitPTaskList()
{
    NewList(&ptlist);
}

/* clear list, freeing memory */
void
DeletePTaskList()
{
    PTASK *pt;

    Forbid();
    while (pt = (PTASK *)RemHead(&ptlist))
    {
	FreeVec(pt->pt_Node.ln_Name);
	FreeVec(pt->pt_OrigName);
	FreeVec(pt);
    }
    Permit();
}

/* allocate memory region of size len+1, copy string to it */
/* tasky specific: pad string out with spaces and priority at end */
#define WIDTH 27		/* name width */
#define FULLWIDTH (WIDTH+4)	/* total width -- 4 chars for priority */
char *
AllocStr(UBYTE len, BYTE pri, UBYTE *str)
{
    char *newstr;
    UWORD i;
    BOOL trunc = FALSE;

    if (len > WIDTH)			/* truncate length? */
	len = WIDTH, trunc = TRUE;

    if (newstr = AllocVec(FULLWIDTH+1,0L))
    {
	CopyMem(str,newstr,len);
	for (i = len; i < WIDTH; i++)
	    newstr[i]=' ';
	if (trunc)
		newstr[WIDTH-1] = '$';
	SPrintf(&newstr[WIDTH], "%4ld", (long)pri);
    }
    return newstr;
}
#define FreeStr(s)	FreeVec(s)

/* insert node in sorted position in list (sort by name) */
void
InsertInPlace(LIST *list, NODE *new)
{
    NODE *n;

    for (n = list->lh_Head; n->ln_Succ; n = n->ln_Succ)
    {
	if (stricmp(n->ln_Name, new->ln_Name) >= 0)
	{
	    Insert(list,new,n->ln_Pred);
	    return;
	}
    }
    /* got here - must be last node */
    AddTail(list, new);
}

/* create a sorted list from a list */
void
SortList(LIST *from, LIST *to)
{
    NODE *n;

    while (n = RemHead(from))
    	InsertInPlace(to, n);
}

/* set up pnode from given task-node */
BOOL
InitNode(PTASK *pt, NODE *n, char *name, UBYTE len)
{
    UWORD i;

    if (pt->pt_OrigName = AllocVec(i=(strlen(n->ln_Name)+1), 0L))
    {
	CopyMem(n->ln_Name, pt->pt_OrigName, i);
	if (pt->pt_Node.ln_Name = AllocStr(len, n->ln_Pri, name))
	{
	    AddHead(&tmplist, pt);
	    pt->pt_Task = (TASK *)n;
	    pt->pt_TaskPri = n->ln_Pri;
	    return TRUE;
	}
	FreeVec(pt->pt_OrigName);
    }
    return FALSE;
}

/* add a new task to our list */
BOOL
AddTaskToPTaskList(TASK *t)
{
    UBYTE cmdname[300];
    PTASK *pt;

    num_ptasks++;			/* increment count */
    if (pt = AllocPTask())		/* get a new PTask */
    {
	PROC *proc = (PROC *)t;	/* proc from task */

	/* task or non-cli process */
	if (t->tc_Node.ln_Type != NT_PROCESS || proc->pr_TaskNum == 0)
	{
	    char *name = t->tc_Node.ln_Name;
	    if (InitNode(pt, t, name, strlen(name)))
		return TRUE;
	}
	else	/* cli-process...fun and games */
	{
	    struct CommandLineInterface *cli = BADDR(proc->pr_CLI);
	    UBYTE *bstr = BADDR(cli->cli_CommandName);
	    UBYTE len;

	    if (bstr && bstr[0]) {	/* a command is loaded */
		len = bstr[0];
		bstr = &bstr[1];
	    } else {
		bstr = "No command loaded";
		len = 17;
	    }

	    CopyMem(bstr, cmdname, len);
	    SPrintf(&cmdname[len]," [CLI %ld]", proc->pr_TaskNum);

	    if (InitNode(pt, t, cmdname, len+strlen(&cmdname[len])))
		return TRUE;
	}

	FreePTask(pt);	/* memory allocation failure... */
    }
    return FALSE;
}

/* add tasks from supplied task list to our list */
/* return TRUE if okay, FALSE if memory allocation failed */
BOOL
AddListToPTaskList(LIST *tl)
{
    TASK *t;

    /* scan the list, adding processes to the plist */
    for (t = (TASK *)tl->lh_Head; t->tc_Node.ln_Succ; t = (TASK *)t->tc_Node.ln_Succ)
    {
	if (!AddTaskToPTaskList(t))
	{
	    Permit();
	    return FALSE;
	}
    } /* for */

    return TRUE;
}

/* re-read PTask list, deleting old one if required */
/* return success */
BOOL
RefreshPTaskList()
{
    static BOOL firsttime = TRUE;
    BOOL rc = FALSE;

    if (firsttime)
    {
	InitPTaskList();
	NewList(&tmplist);
	firsttime = FALSE;
    }
    else
	DeletePTaskList();

    num_ptasks = 0;	/* reset count */

    /* want to be disabled for as short a period as possible, so
       build a tmp list, then copy to another in order */

    Disable();
    if (AddListToPTaskList(&SysBase->TaskReady) &&
        AddListToPTaskList(&SysBase->TaskWait) &&
	AddTaskToPTaskList(SysBase->ThisTask))
	rc = TRUE;
    Enable();

    SortList(&tmplist, &ptlist);

    if (!rc)
	DeletePTaskList();
    return rc;
}

/* check list for given task - assumes forbidden */
TASK *
ScanList(LIST *list, PTASK *pt)
{
    TASK *t;

    for (t = (TASK *)FindName(list, pt->pt_OrigName);
    	 t && t != pt->pt_Task;
	 t = (TASK *)FindName((LIST *)t, pt->pt_OrigName))
    	 ;

    return t;
}

/* check task lists for given task */
TASK *
GetOrigTask(PTASK *pt)
{
    TASK *t;

    Disable();
    t = ScanList(&SysBase->TaskReady, pt);
    if (!t)
        t = ScanList(&SysBase->TaskWait, pt);
    Enable();
    if (!t) /* is it us? */
        if (pt->pt_Task == SysBase->ThisTask)
	    t = SysBase->ThisTask;

    return t;
}
