/*
** Chatline (String.mui Subclass with History)
** Copyright (C) 2000 Gurer Ozen <madcat@linuxfan.com>
**
** This code is free software; you can redistribute it and/or
** modify it under the terms of GNU General Public License.
*/

#include "chatline.h"

#include <stdlib.h>
#include <string.h>

#include <proto/exec.h>
#include <exec/memory.h>
#include <intuition/sghooks.h>

static ULONG chatline_new(struct IClass *cl, Object *obj, struct opSet *msg);
static ULONG chatline_dispose(struct IClass *cl,Object *obj,Msg msg);
static MUI_HOOK_DECL(chatline_edit, struct SGWork *sgw, ULONG *msg);
static void chatline_add(struct chatlinedata *data, char *text);


MUI_DISPATCH(chatline_dispatch)
{
	switch(msg->MethodID) {
		case OM_NEW: return(chatline_new(cl, obj, (APTR)msg));
		case OM_DISPOSE: return(chatline_dispose(cl, obj, (APTR)msg));
		case CHATLINE_ADD:
			chatline_add(INST_DATA(cl,obj), (char *)(((muimsg)msg)->arg1));
			return 0;



	}
	return(DoSuperMethodA(cl,obj,msg));
}


static ULONG chatline_new(struct IClass *cl, Object *obj, struct opSet *msg)
{
	static struct Hook editHook = {{0,0}, &chatline_edit, NULL, NULL};
	struct chatlinedata *data;

	obj = (Object *)DoSuperNew(cl,obj,
		StringFrame,
		MUIA_String_EditHook, &editHook,
		TAG_MORE, msg->ops_AttrList);

	if(!obj) return(0);

	data = INST_DATA(cl,obj);

	data->pool = CreatePool(MEMF_PUBLIC, 1024, 900);
	if(!data->pool) {
		CoerceMethod(cl, obj, OM_DISPOSE);
		return 0;
	}

	editHook.h_Data = (void *)data;


	return((ULONG)obj);
}


MUI_HOOK_STATIC(chatline_edit, struct SGWork *sgw, ULONG *msg)
{
	if(*msg == SGH_KEY && sgw->EditOp == EO_NOOP && sgw->IEvent->ie_Class == IECLASS_RAWKEY)
	{
		struct chatlinedata *data = hook->h_Data;
		UWORD code = sgw->IEvent->ie_Code;
		UWORD qual = sgw->IEvent->ie_Qualifier;
		int upd = 0;

		if(code == 0x4c && !(qual&(IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)))
		{
			/* up arrow */

			if(data->cur) {
				if(data->cur->prev) data->cur=data->cur->prev;
			}
			else
				data->cur = data->lastline;

			if(data->cur) upd=1;
		}
		else if(code == 0x4c && qual&(IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
		{
			/* shift + up arrow */

			data->cur = data->lines;
			upd = 1;
		}
		else if(code == 0x4d && !(qual&(IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)))
		{
			/* down arrow */

			if(data->cur) data->cur = data->cur->next;

			if(data->cur) {
				upd = 1;
			} else {
				sgw->WorkBuffer[0] = '\0';
				sgw->NumChars = 0;
				sgw->BufferPos = 0;
				sgw->Actions |= SGA_REDISPLAY;
			}
		}
		else if(code == 0x4d && qual&(IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
		{
			/* shift + down arrow */

			data->cur = NULL;
			sgw->WorkBuffer[0] = '\0';
			sgw->NumChars = 0;
			sgw->BufferPos = 0;
			sgw->Actions |= SGA_REDISPLAY;
		}

		if(upd) {
			strcpy(sgw->WorkBuffer, &data->cur->line[0]);
			sgw->NumChars = data->cur->len;
			sgw->BufferPos = data->cur->len;
			sgw->Actions |= SGA_REDISPLAY;
		}
	}

	return 0;
}


static ULONG chatline_dispose(struct IClass *cl,Object *obj,Msg msg)
{
	struct chatlinedata *data = INST_DATA(cl,obj);

	if(data->pool) DeletePool(data->pool);

	return(DoSuperMethodA(cl, obj, msg));
}


static void chatline_add(struct chatlinedata *data, char *text)
{
	struct chatlinestr *cl;
	int len;

	if(!text) return;

	len = strlen(text);
	cl = AllocPooled(data->pool, sizeof(struct chatlinestr) + len + 1);
	if(!cl) return;
	memset(cl, 0, sizeof(struct chatlinestr));
	cl->len = len;
	strcpy(&cl->line[0], text);

	if(data->lastline) {
		data->lastline->next = cl;
		cl->prev = data->lastline;
	} else {
		data->lines = cl;
	}
	data->lastline = cl;
	data->cur = NULL;
}
