#include    <intuition/intuition.h>
#include    <devices/load.h>
#include    "execdef.h"
#include    "intuidef.h"
#include    "error.h"
#include    "windownode.h"
#include    "windowinfo.h"
#include    "loadrecord.h"

#include    "Init.proto"

#include    <exec/proto.h>

#include    "OpenLoadWindow.proto"
#include    "NewLoadRecord.proto"

#define LINEWIDTH   1
#define DEFAULT_LEFTEDGE    screenWidth-DEFAULT_WIDTH
#define DEFAULT_TOPEDGE     10
#define DEFAULT_WIDTH	    100
#define DEFAULT_HEIGHT	    100
#define MINWIDTH    BORDERWIDTH * 2 + LINEWIDTH
#define MINHEIGHT   BORDERHEIGHT * 2 + LINEWIDTH
#define MAXWIDTH    -1
#define MAXHEIGHT   -1
#define DEFAULT_DETAIL_PEN   -1
#define DEFAULT_BLOCK_PEN    -1
#define DEFAULT_DATA_PEN 1
#define DEFAULT_REF_PEN  1
#define DEFAULT_BACK_PEN 0

static NewWindow newWindow =
{ 0, 0, 0, 0,
  0, 0,
  0,
  WINDOWSIZING | WINDOWDEPTH | WINDOWCLOSE | WINDOWDRAG | SIMPLE_REFRESH | RMBTRAP,
  0, 0, 0, 0, 0,
  MINWIDTH, MINHEIGHT, MAXWIDTH, MAXHEIGHT,
  WBENCHSCREEN
};

extern Library *GfxBase;
extern struct IntuitionBase *IntuitionBase;
extern MinList windowList;
extern MsgPort *loadPort;
extern MsgPort *windowPort;
extern loadrequest *loadRequest;

static short atoi(char **);
static void GetScreenDimensions();
static void ParseGeometry(char **);

long   maxTicks;
long   maxChip;
long   maxFast;
long   maxMem;

static char *default_argstr = "{[d3]}";
static short screenWidth, screenHeight;

long
Init(argstr)
    char *argstr;
{
    WindowNode *node;
    struct LoadBase *load_base;
    Bool getting_record, getting_window;
    short try_again;
    unsigned char data_pen_num, ref_pen_num, back_pen_num, record_type;
    char c;
    struct Screen screen;

    if (!(GfxBase = OpenLibrary("graphics.library", 0)))
	return ENOGFX;
    if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0)))
	return ENOINTUITION;
    if (!(windowPort = CreatePort(0,0)))
	return ENOPORT;
    NewList(&windowList);
    if (!(loadPort = CreatePort(0,0)))
	return ENOPORT;
    if (!(loadRequest = (loadrequest *)CreateExtIO(loadPort, sizeof(loadrequest))))
	return ENOIOREQUEST;
    if (OpenDevice("load.device",0,(IORequest *)loadRequest,0))
	return ENODEVICE;
    load_base = (struct LoadBase *)loadRequest->lr_node.io_Device;
    maxTicks = load_base->ld_ticks;
    maxChip  = load_base->ld_max_chip;
    maxFast  = load_base->ld_max_fast;
    maxMem   = maxChip + maxFast;
    GetScreenDimensions();
    while ((c = *argstr) && (c != ' '))
	argstr++;
    node = NULL;
    for (try_again = 2; try_again--;)
    {
	while ((c = *argstr++) && (c != '\n'))
	{
	    switch(c)
	    {
	    case 'i':
		loadRequest->lr_interval = atoi(&argstr);
		break;
	    case 't':
		loadRequest->lr_ticks = atoi(&argstr);
		break;
	    case 'p':
		loadRequest->lr_pri = atoi(&argstr);
		break;
	    case '{':
		node = NULL;
		newWindow.LeftEdge = DEFAULT_LEFTEDGE;
		newWindow.TopEdge = DEFAULT_TOPEDGE;
		newWindow.Width = DEFAULT_WIDTH;
		newWindow.Height = DEFAULT_HEIGHT;
		newWindow.DetailPen = DEFAULT_DETAIL_PEN;
		newWindow.BlockPen = DEFAULT_BLOCK_PEN;
		back_pen_num = DEFAULT_BACK_PEN;
		for (getting_window = TRUE; getting_window;)
		{
		    c = *argstr++;
		    switch(c)
		    {
		    case '=':
			ParseGeometry(&argstr);
			break;
		    case 'd':
			newWindow.DetailPen = atoi(&argstr);
			break;
		    case 'b':
			newWindow.BlockPen = atoi(&argstr);
			break;
		    case 'g':
			back_pen_num = atoi(&argstr);
			break;
		    case '[':
			if (!node && !(node = OpenLoadWindow(&newWindow, back_pen_num)))
			    return ENOWINDOW;
			record_type = CPU;
			ref_pen_num = DEFAULT_REF_PEN;
			data_pen_num = DEFAULT_DATA_PEN;
			for (getting_record = TRUE; getting_record; )
			{
			    c = *argstr++;
			    switch(c)
			    {
			    case 'C':
				record_type = CPU;
				break;
			    case 'b':
				record_type = BLITTER;
				break;
			    case 'm':
				record_type = ALLMEM;
				break;
			    case 'c':
				record_type = CHIPMEM;
				break;
			    case 'f':
				record_type = FASTMEM;
				break;
			    case 'd':
				data_pen_num = atoi(&argstr);
				break;
			    case 'r':
				ref_pen_num = atoi(&argstr);
				break;
			    case ' ':
				break;
			    case ']':
				getting_record = FALSE;
				break;
			    case '\n':
			    case '\0':
				/* Error: Unexpected end of record. */
				return EUNXEOR;
			    default:
				/* Error: Unknown record flag. */
				return EBADRFLAG;
			    }
			}
			if (!(NewLoadRecord(WINDOWINFO(node->window), record_type, data_pen_num, ref_pen_num)))
			    return ENORECORD;
			break;
		    case ' ':
			break;
		    case '}':
			getting_window = FALSE;
			break;
		    case '\n':
		    case '\0':
			/* Error: Unexpected end of window. */
			return EUNXEOW;
		    default:
			/* Error: Unknown window flag. */
			return EBADWFLAG;
		    }
		}
		break;
	    case ' ':
		break;
	    default:
		/* Error: Unknown global flag. */
		return EBADGFLAG;
	    }
	}
	if (!node)
	    argstr = default_argstr;
	else
	    break;
    }
    loadRequest->lr_node.io_Command = LD_SET;
    DoIO(loadRequest);
    return 0;
}

static
short atoi(s)
    register char **s;
{
    register short num;

    for (num = 0; isdigit(**s); (*s)++)
	num = num * (short)10 + **s - '0';
    return num;
}

static
void
GetScreenDimensions()
{
    struct Screen screen;

    GetScreenData(&screen,  sizeof(struct Screen), WBENCHSCREEN, NULL);
    screenWidth = screen.Width;
    screenHeight = screen.Height;
}

static
void
ParseGeometry(string)
    register char **string;
{
    register char c;

    c = **string;
    if (c != 'x' && c != '+' && c != '-')
	newWindow.Width = atoi(string);
    c = *((*string)++);
    if (c == 'x')
    {
	newWindow.Height = atoi(string);
	c = *((*string)++);
    }
    if (c == '+')
    {
	newWindow.LeftEdge = atoi(string);
	c = *((*string)++);
    }
    else if (c == '-')
    {
	newWindow.LeftEdge = screenWidth - atoi(string) - newWindow.Width;
	c = *((*string)++);
    }
    else
	return;
    if (c == '+')
	newWindow.TopEdge = atoi(string);
    else if (c == '-')
	newWindow.TopEdge = screenHeight - atoi(string) - newWindow.Height;
}
