/*
** Amster - Messenger
** Copyright © 1999-2000 by Gürer Özen
** Copyright © 2000-2001 by Jacob Laursen
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "amster.h"

#include <proto/dos.h>
#include <proto/utility.h>
#include <MUI/NListview_mcc.h>
#include <MUI/textinput_mcc.h>

#include "chatline.h"
#include "amster_Cat.h"

ULONG msg_new(struct IClass *cl, Object *obj, struct opSet *msg);
MUI_LIST_DISP_DECL(MessageDisplay, struct ChatMessage *m);
void msg_say(struct msgdata *data);
void msg_whois(struct msgdata *data, char *info);
void msg_whowas(struct msgdata *data, char *user, char *level, u_long lastseen);
void InsertMsgEntry(struct msgdata *data, char *Desc, char *Msg);


MUI_DISPATCH(msg_dispatch)
{
	switch(msg->MethodID) {
		case OM_NEW:
			return(msg_new(cl, obj, (APTR)msg));
		case MSG_OPEN:
			set(obj, MUIA_Window_Open, TRUE);
			return(NULL);
		case MSG_GOT:
			{
			struct msgdata *data = INST_DATA(cl, obj);
			long winopen;

			get(obj, MUIA_Window_Open, &winopen);
			if (!winopen) set(obj, MUIA_Window_Open, TRUE);
			/* Open the window if it's not already opened, when receiving a message */

			msg_got(data, (char *)((muimsg)msg)->arg1, (char *)((muimsg)msg)->arg2);
			return(NULL);
			}
		case MSG_SAY:
			{
			struct msgdata *data = INST_DATA(cl,obj);
			msg_say(data);
			return(NULL);
			}
		case MSG_WHOIS:
			{
			struct msgdata *data = INST_DATA(cl,obj);
			msg_whois(data, (char *)(((muimsg)msg)->arg1));
			return(NULL);
			}
		case MSG_WHOWAS:
			{
			struct msgdata *data = INST_DATA(cl,obj);
			msg_whowas(data, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (u_long)(((muimsg)msg)->arg3));
			return(NULL);
			}

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


ULONG msg_new(struct IClass *cl, Object *obj, struct opSet *msg)
{
	static struct Hook MessageDispHook = { {NULL, NULL}, &MessageDisplay, NULL, NULL };

	struct msgdata *data;
	Object *msglist, *msgstr;

	if (obj = (Object *)DoSuperNew(cl, obj,
		MUIA_HelpNode, "messenger",
		WindowContents, VGroup,
			Child, NListviewObject,
				MUIA_NListview_NList, msglist = NListObject,
					ReadListFrame,
					MUIA_NList_Input, FALSE,
					MUIA_NList_DefaultObjectOnClick, FALSE,
					MUIA_NList_DisplayHook, &MessageDispHook,
					MUIA_NList_Format, "BAR,BAR,",
					MUIA_NList_AutoCopyToClip, TRUE,
					MUIA_NList_TypeSelect, MUIV_NList_TypeSelect_Char,
					MUIA_NList_AutoVisible, TRUE,
				End,
			End,
			Child, msgstr = NewObject(gui->chatline_mcc->mcc_Class, NULL,
				StringFrame,
				MUIA_CycleChain, 1,
				MUIA_String_MaxLen, 256,
			TAG_DONE),
		End,
		TAG_MORE, msg->ops_AttrList))
	{
		data = INST_DATA(cl, obj);
		data->msglist = msglist;
		data->msgstr = msgstr;

		set(obj, MUIA_Window_ID, MAKE_ID('M','E','S','G'));
		set(obj, MUIA_Window_Title, MSG_USER_TITLE),

		DoMethod(msgstr, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, obj,    1, MSG_SAY);
		DoMethod(msgstr, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, obj,    3, MUIM_Set, MUIA_Window_ActiveObject, msgstr);
		DoMethod(msgstr, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, msgstr, 3, MUIM_Set, MUIA_String_Contents,     NULL);

		DoMethod(obj, MUIM_Notify, MUIA_Window_Activate,     TRUE, obj, 3, MUIM_Set, MUIA_Window_ActiveObject, msgstr);
		DoMethod(obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, obj, 3, MUIM_Set, MUIA_Window_Open,         FALSE);

		return((ULONG)obj);
	}
	return(0);
}


MUI_LIST_DISP(MessageDisplay, struct ChatMessage *m)
{
	*array++ = m->TStamp;
	*array++ = m->Nick;
	*array = m->Msg;

	return 0;
}


void msg_say(struct msgdata *data)
{
	u_long tmp;
	char *cmd, *args, *nick, *msg;
	char buf[128];

	GetAttr(MUIA_String_Contents, data->msgstr, &tmp);
	if (!((char *)tmp) || (((char *)tmp)[0]) == '\0') return;

	DoMethod(data->msgstr, CHATLINE_ADD, tmp);
	if (gui_onlinestate < ONLINE) {
		InsertMsgEntry(data, (char *)MSG_MESSAGE_INFO, (char *)MSG_USER_NOTCONN);
		return;
	}
	cmd = strtok((char *)tmp, " ");
	args = strtok(NULL, "");
	if (!cmd) return;

	if (stricmp(cmd, "/whois") == 0) {
		if (!args) InsertMsgEntry(data, (char *)MSG_MESSAGE_ERROR, (char *)MSG_MESSAGE_HELP_WHOIS);
		else nap_sendbuf(NAPC_WHOIS, args);
	}
	else if (stricmp(cmd, "/msg") == 0) {
		if (!args) {
			InsertMsgEntry(data, (char *)MSG_MESSAGE_ERROR, (char *)MSG_MESSAGE_HELP_MSG);
			return;
		}
		nick = strtok(args, " ");
		msg = strtok(NULL, "");
		if (!nick || !msg) {
			InsertMsgEntry(data, (char *)MSG_MESSAGE_ERROR, (char *)MSG_MESSAGE_HELP_MSG);
			return;
		}

		if (strlen(msg) > 179) {
			InsertMsgEntry(data, (char *)MSG_MESSAGE_ERROR, (char *)MSG_MESSAGE_TOOLONG);
			return;
		}
		else {
			sprintf(nap_buf, "%s %s", nick, msg);
			nap_send(NAPC_PRIVATEMSG);

			sprintf(buf, ">%s<", nick);
			InsertMsgEntry(data, buf, msg);
		}
	}
	else {
		sprintf(buf, (char *)MSG_MESSAGE_UNKNOWNCOMMAND, cmd);
		InsertMsgEntry(data, (char *)MSG_MESSAGE_ERROR, buf);
	}
}


void msg_whois(struct msgdata *data, char *info)
{
	char buf[1024], buf2[32];
	char *nick, *level, *channels, *status, *client;
	int time, shared, downloads, uploads, link;
	struct RexxMsg *m;
	u_long tmp;

	nick =      nap_token(&info);
	level =     nap_token(&info);
	time =      nap_ltoken(&info);
	channels =  nap_token(&info);
	status =    nap_token(&info);
	shared =    nap_itoken(&info);
	downloads = nap_itoken(&info);
	uploads =   nap_itoken(&info);
	link =      nap_itoken(&info);
	client =    nap_token(&info);

	if (gRexxCommand == WHOIS) {
		GetAttr(MUIA_Application_RexxMsg, gui->app, &tmp);
		m = (struct RexxMsg *)tmp;

		sprintf(buf, "%s.NICK", gSTEM);
		SetRexxVar(m, buf, nick, strlen(nick));

		sprintf(buf, "%s.LEVEL", gSTEM);
		SetRexxVar(m, buf, level, strlen(level));

		sprintf(buf, "%s.TIME", gSTEM);
		sprintf(buf2, "%ld", time);
		SetRexxVar(m, buf, buf2, strlen(buf2));

		sprintf(buf, "%s.CHANNELS", gSTEM);
		if (channels != NULL) SetRexxVar(m, buf, channels, strlen(channels));
		else SetRexxVar(m, buf, "", 0);

		sprintf(buf, "%s.STATUS", gSTEM);
		SetRexxVar(m, buf, status, strlen(status));

		sprintf(buf, "%s.SHARES", gSTEM);
		sprintf(buf2, "%ld", shared);
		SetRexxVar(m, buf, buf2, strlen(buf2));

		sprintf(buf, "%s.DOWNLOADS", gSTEM);
		sprintf(buf2, "%ld", downloads);
		SetRexxVar(m, buf, buf2, strlen(buf2));

		sprintf(buf, "%s.UPLOADS", gSTEM);
		sprintf(buf2, "%ld", uploads);
		SetRexxVar(m, buf, buf2, strlen(buf2));

		sprintf(buf, "%s.LINK", gSTEM);
		sprintf(buf2, "%ld", link);
		SetRexxVar(m, buf, buf2, strlen(buf2));

		sprintf(buf, "%s.CLIENT", gSTEM);
		SetRexxVar(m, buf, client, strlen(client));

		gRexxCommand = NONE;
	}
	else {
		sprintf(buf, (char *)MSG_MESSAGE_WHOIS1, nick, level, time/360, (time/60)%60, time%60, status);
		InsertMsgEntry(data, (char *)MSG_MESSAGE_WHOIS_DESC, buf);

		if (channels != NULL) {
			sprintf(buf, (char *)MSG_MESSAGE_WHOIS2, channels);
			InsertMsgEntry(data, (char *)MSG_MESSAGE_WHOIS_DESC, buf);
		}

		sprintf(buf, (char *)MSG_MESSAGE_WHOIS3,
			shared, downloads, uploads);
		InsertMsgEntry(data, (char *)MSG_MESSAGE_WHOIS_DESC, buf);

		sprintf(buf, (char *)MSG_MESSAGE_WHOIS4, client, nap_linktype[link]);
		InsertMsgEntry(data, (char *)MSG_MESSAGE_WHOIS_DESC, buf);
	}

	set(data->msglist, MUIA_NList_First, MUIV_NList_Active_Bottom);
}


void msg_whowas(struct msgdata *data, char *user, char *level, u_long lastseen)
{
	struct ClockData *cd;
	char buf[1024], buf2[32];
	struct RexxMsg *m;
	u_long tmp;

	lastseen -= (8*365+2)*24*60*60;
	/* Number of seconds between January 1st/0:00, 1970 and January 1st/0:00, 1978 */

	if (gRexxCommand == WHOIS) {
		GetAttr(MUIA_Application_RexxMsg, gui->app, &tmp);
		m = (struct RexxMsg *)tmp;

		sprintf(buf, "%s.NICK", gSTEM);
		SetRexxVar(m, buf, user, strlen(user));

		sprintf(buf, "%s.LEVEL", gSTEM);
		SetRexxVar(m, buf, level, strlen(level));

		sprintf(buf, "%s.LASTSEEN", gSTEM);
		sprintf(buf2, "%ld", lastseen);
		SetRexxVar(m, buf, buf2, strlen(buf2));

		gRexxCommand = NONE;
		gRC = 1;
	}
	else if (cd = malloc(sizeof(struct ClockData))) {
		Amiga2Date(lastseen, cd);
		sprintf(buf, (char *)MSG_MESSAGE_WHOWAS, user, level, cd->month, cd->mday, cd->year, cd->hour, cd->min, cd->sec);
		free(cd);
		InsertMsgEntry(data, (char *)MSG_MESSAGE_WHOWAS_DESC, buf);
	}
#ifdef AMSTER_DEBUG
	else gui_debug("Out of memory: msg_whowas()");
#endif
}


void msg_got(struct msgdata *data, char *nick, char *msg)
{
	char buf[32];

	prf_event(PRFE_INMSG, nick, msg);
	sprintf(buf, "<%s>", nick);
	InsertMsgEntry(data, buf, msg);
}


void msg_gotwhois(char *buf)
{
	DoMethod(gui->mwin, MSG_WHOIS, buf);
}


void InsertMsgEntry(struct msgdata *data, char *Desc, char *Msg)
{
	struct ClockData cd;
	struct ChatMessage *m;

	m = malloc(sizeof(struct ChatMessage));
	if (!m) return;

	Amiga2Date(GetDateStamp(), &cd);
	sprintf(m->TStamp, "%02d:%02d:%02d", cd.hour, cd.min, cd.sec);

	m->Nick = strdup(Desc);
	m->Msg = strdup(Msg);
	DoMethod(data->msglist, MUIM_NList_InsertSingleWrap, m, MUIV_NList_Insert_Bottom, WRAPCOL2, ALIGN_LEFT);
	set(data->msglist, MUIA_NList_First, MUIV_NList_Active_Bottom);
}
