function LoqUser_SERVER(loq_main, peer, param) // /SERVER <server/groupname> [port] [password]
{
	// get defaults
	var server;
	var port;
	var password;

	// get parameters
	var params = param.split(/ /, 3);
	if (params[0] && params[0] != '')
		server = params[0];
	if (params[1] && params[1] != '')
		port = params[1];
	if (params[2] && params[2] != '')
		password = params[2];

	// check parameters
	if (! server || server == '' || ! port || port == '') {
		loq_main.status_window.WriteLine(htmlSafeString('/server <server/groupname> [port] [password]'), 'CLI');
		return;
	}

	// connected already
	if (loq_main.network.Connected()) {
		loq_main.status_window.WriteLine('<font color="#000000">*** Already connected to server</font>', 'CER');
		return;
	}

	// write message
	loq_main.status_window.WriteLine('<font color="#000080">*** '.concat('Connecting to ', server, ' (' + port + ')</font>'), 'CLI');

	// connect to server
	loq_main.network.Connect(server, port);
}

function LoqUser_QUIT(loq_main, peer, reason) // /QUIT [reason]
{
	if (loq_main.network.Connected()) {
		if (! reason)
			loq_main.network.Send('QUIT');
		else
			loq_main.network.Send('QUIT', ':' + reason);
	}
}

function LoqUser_NICK(loq_main, peer, param) // /NICK nickname
{
	var nick;
	if (param) {
		nick = param.split(/ /)[0];
	}

	if (nick) {
		if (loq_main.network.Connected())
			loq_main.network.Send('NICK', nick);
		else {
			loq_main.chat_status_mgr.IChangeNick(nick);
			loq_main.status_window.WriteLine('<font color="#008000">*** Your nick is now '.concat(nick, '</font>'), 'NIC');
		}
	}
	else {
		errInsuffParams(loq_main, command);
	}
}

function LoqUser_JOIN(loq_main, peer, param) // /JOIN #channel
{
	if (loq_main.network.Connected()) {
		var channels = param.split(/ /);
		if (channels.length > 0 && channels[0]) {
			for (var i = 0; i < channels.length; i++) {
				var channel_status = loq_main.chat_status_mgr.GetChannelStatus(channels[i]);
				if (channel_status) {
					switch (channel_status.channelState) {
					case 'SentJOIN':
						loq_main.status_window.WriteLine('<font color="#000080">* /join joining '.concat(channels[i], ' in progress...</font>'), 'CER');
						loq_main.network.Send('JOIN', channels[i]);
						break;
					case 'SentPART':
						loq_main.status_window.WriteLine('<font color="#000080">* /join parting '.concat(channels[i], ' in progress...</font>'), 'CER');
						break;
					}

					var channel_window = loq_main.chat_window_mgr.GetChannelWindow(channels[i]);
					if (channel_window && channel_window.isOpen()) {
						channel_window.Focus();
					}
				}
				else {
					loq_main.network.Send('JOIN', channels[i]);
					loq_main.chat_status_mgr.ISentJOIN(channels[i]);
				}
			}
		}
		else {
			errInsuffParams(loq_main, command);
		}
	}
}

function LoqUser_PART(loq_main, peer, param) // /PART #channel
{
	if (loq_main.network.Connected()) {
		var channels = param.split(/ /);
		if (! channels[0]) {
			channels[0] = peer;
		}

		if (channels[0]) {
			for (var i = 0; i < channels.length; i++) {
				var channel_status = loq_main.chat_status_mgr.GetChannelStatus(channels[i]);
				if (channel_status) {
					switch (channel_status.channelState) {
					case 'SentJOIN':
						loq_main.status_window.WriteLine('<font color="#000080">* /part joining '.concat(channels[i], ' in progress...</font>'), 'CER');
						break;

					case 'SentPART':
						loq_main.status_window.WriteLine('<font color="#000080">* /part parting '.concat(channels[i], ' in progress...</font>'), 'CER');

					case 'Joined':
						loq_main.chat_status_mgr.ISentPART(channels[i]);
						loq_main.network.Send('PART', channels[i]);
						break;
					}
				}
				else {
					loq_main.network.Send('PART', channels[i]);
				}
			}
		}
		else
			errInsuffParams(loq_main, command);
	}
}

function LoqUser_KICK(loq_main, peer, param) // /KICK [#channel] nickname [comment]
{
	if (loq_main.network.Connected()) {
		var params = param.match(/([#&+!][^ ]*)? *([^ ]*) *(.*)?$/);
		if (params[2]) {
			var channel = params[1] ? params[1] : peer;
			var nick = params[2];
			var comment = params[3] ? ':'+params[3] : '';

			loq_main.network.Send('KICK', channel.concat(' ', nick, ' ', comment));
		}
		else
			errInsuffParams(loq_main, command);
	}
}

function LoqUser_TOPIC(loq_main, peer, param) // /TOPIC [#channel] newtopic
{
	if (loq_main.network.Connected()) {
		var params = param.match(/([#&+!][^ ]*)? *(.*)?$/);
		if (params[2]) {
			if (params.length > 1 && params[1]) {
				loq_main.network.Send('TOPIC', params[1].concat(' :', params[2]));
			}
			else {
				if (isChannelName(peer)) // channel window
					loq_main.network.Send('TOPIC', peer.concat(' :', params[2]));
				else
					errInsuffParams(loq_main, command);
			}
		}
		else {
			errInsuffParams(loq_main, command);
		}
	}
}

function LoqUser_LIST(loq_main, peer, param) // /LIST [#channel] [-MIN #] [-MAX #] [-LIMIT #]
{
	if (loq_main.network.Connected()) {
		var params = param.match(/([#&+!][^ ]*)? *(-min *(\d+))? *(-max *(\d+))? *(-limit *(\d+))?$/i);
		if (params) {
			var channel = params[1];
			var min = params[3];
			var max = params[5];
			var limit = params[7];

			loq_main.channel_list_data = new Object();
			loq_main.channel_list_count = 0;
			loq_main.channel_list_min = min ? new Number(min) : 0;
			loq_main.channel_list_max = max ? new Number(max) : Number.MAX_VALUE;
			loq_main.channel_list_limit = limit ? new Number(limit) : Number.MAX_VALUE;

			/*
			if (! loq_main.channel_list_window.isOpen()) {
				loq_main.channel_list_window.Open();
			}
			loq_main.channel_list_window.Focus();
			*/

			var list_param = channel;
			if (min) {
				if (list_param)
					list_param += ',';
				list_param += '>'+min;
			}
			if (max) {
				if (list_param)
					list_param += ',';
				list_param += '<'+max;
			}
			loq_main.network.Send('LIST', list_param);
			//    Command: LIST
			// Parameters: [ <channel> *( "," <channel> ) [ <target> ] ]
		}
		else {
			errInsuffParams(loq_main, command);
		}
	}
}

function LoqUser_QUERY(loq_main, peer, param) // /QUERY nickname [message]
{
	var params = param.match(/([^ ]*) *(.*)?$/);
	if (params && params[1]) {
		var query_status = loq_main.chat_status_mgr.GetQueryStatus(params[1]);
		if (! query_status)
			query_status = loq_main.chat_status_mgr.OpenQuery(params[1]);

		var query_window = loq_main.chat_window_mgr.GetQueryWindow(params[1]);
		if (! query_window)
			query_window = loq_main.chat_window_mgr.OpenQueryWindow(params[1]);

		if (params[2]) {
			loq_main.network.Send('PRIVMSG', params[1] + ' :' + params[2]);
			query_window.WriteMyMessage(loq_main.chat_status_mgr.myNick, params[2]);
		}
	}
	else {
		errInsuffParams(loq_main, command);
	}
}

function LoqUser_DISCONNECT(loq_main, peer, param)
{
	if (loq_main.network.Connected()) {
		loq_main.network.Disconnect();
	}
}

function LoqUser_QUOTE(loq_main, peer, param)
{
	loq_main.network.Send(param);
}

function LoqUser_DEBUG(loq_main, peer, param)
{
	switch (param) {
	case 'status':
		loq_main.chat_status_mgr.DumpStatus(loq_main.status_window);
		break;

	default:
		if (! top.DebugWindow.isOpen())
			top.DebugWindow.Open();
	}
}

function LoqUser_ME(loq_main, peer, param)
{
	if (peer) {
		if (isChannelName(peer)) {
			var channel_status = loq_main.chat_status_mgr.GetChannelStatus(peer);
			if (channel_status) {
				if (channel_status.channelState == 'Joined') {
					loq_main.network.Send('PRIVMSG', peer.concat(' :\1ACTION ', param, '\1'));
					var channel_window = loq_main.chat_window_mgr.GetChannelWindow(peer);
					if (channel_window)
						channel_window.WriteMyMessage(loq_main.chat_status_mgr.myNick, '\1ACTION '.concat(param, '\1'));
				}
				else {
					loq_main.status_window.WriteLine('<font color="#000080">* joining '.concat(peer, ' in progress...</font>'), 'CER');
				}
			}
		}
		else {
			var query_status = loq_main.chat_status_mgr.GetQueryStatus(peer);
			if (query_status) {
				loq_main.network.Send('PRIVMSG', peer.concat(' :\1ACTION ', param, '\1'));
				var query_window = loq_main.chat_window_mgr.GetQueryWindow(peer);
				if (query_window)
					query_window.WriteMyMessage(loq_main.chat_status_mgr.myNick, '\1ACTION '.concat(param, '\1'));
			}
		}
	}
}

function LoqUser_MSG(loq_main, peer, param)
{
	var params = param.match(/([^ ]*) *(.*)?$/);
	if (params && params[1] && params[2]) {
		loq_main.network.Send('PRIVMSG', params[1] + ' :' + params[2]);
		if (peer) {
			var chat_window;
			if (isChannelName(peer))
				chat_window = loq_main.chat_window_mgr.GetChannelWindow(peer);
			else
				chat_window = loq_main.chat_window_mgr.GetQueryWindow(peer);
			if (chat_window)
				chat_window.WriteLine('chat_f', '-&gt; *'.concat(peer, '* ', Msg2Html(htmlSafeString(params[2]))));
		}
	}
	else {
		errInsuffParams(loq_main, command);
	}
}

function LoqUser_HELP(loq_main, peer, param)
{
	loq_main.status_window.WriteLine('<dl><dt><font color="#000080">* Available commands are</font>', 'HELP');
	for (command in LoqUser_CommandTable) {
		loq_main.status_window.WriteLine('<dd>/'+command, 'HELP');
	}
	loq_main.status_window.WriteLine('</dl>', 'EOH');
}

function LoqUser_CLEAR(loq_main, peer, param)
{
	if (peer) {
		if (isChannelName(peer)) { // channel
			var channel_window = loq_main.chat_window_mgr.GetChannelWindow(peer);
			if (channel_window) {
				channel_window.CloseDocument('chat_f');
				channel_window.OpenDocument('chat_f');
			}
		}
		else { // query
			var query_window = loq_main.chat_window_mgr.GetQueryWindow(peer);
			if (query_window) {
				query_window.CloseDocument('chat_f');
				query_window.OpenDocument('chat_f');
			}
		}
	}
	else { // status
		loq_main.status_window.CloseDocument();
		loq_main.status_window.OpenDocument();
	}
}

function errInsuffParams(loq_main, command)
{
	loq_main.status_window.WriteLine('<font color="#000080">* /'.concat(command, ': insufficient parameters</font>'), 'CER');
}

var LoqUser_CommandTable = {
'clear':{'func':LoqUser_CLEAR, 'usage':''},
'debug':{'func':LoqUser_DEBUG, 'usage':''},
'disconnect':{'func':LoqUser_DISCONNECT, 'usage':''},
'help':{'func':LoqUser_HELP, 'usage':''},
'join':{'func':LoqUser_JOIN, 'usage':''},
'kick':{'func':LoqUser_KICK, 'usage':''},
'list':{'func':LoqUser_LIST, 'usage':''},
'me':{'func':LoqUser_ME, 'usage':''},
'msg':{'func':LoqUser_MSG, 'usage':''},
'nick':{'func':LoqUser_NICK, 'usage':''},
'part':{'func':LoqUser_PART, 'usage':''},
'query':{'func':LoqUser_QUERY, 'usage':''},
'quit':{'func':LoqUser_QUIT, 'usage':''},
'quote':{'func':LoqUser_QUOTE, 'usage':''},
'server':{'func':LoqUser_SERVER, 'usage':''},
'topic':{'func':LoqUser_TOPIC, 'usage':''}
};

function LoqUserInterpreter_Execute(peer, user_input)
{
	//top.DebugWindow.Trace(user_input, 'user -> script');
	//top.DebugWindow.Trace(peer, 'window -> script');

	// command
	if (user_input.charAt(0) == '/') {
		var command, endOfCommand;
		var param;

		var matched = user_input.match(/^\/(\w+) *(.*)?$/);
		if (! (matched && matched[0] && matched[1]))
			return;

		command = matched[1];
		param = matched[2];

		//top.DebugWindow.Trace(command, 'script::command');
		//top.DebugWindow.Trace(param, 'script::param');

		var cmd_item = LoqUser_CommandTable[command];
		if (cmd_item) {
			cmd_item.func(this.loq_main, peer, param);
		}
		else {
			switch (command) {
			default:
				this.loq_main.status_window.WriteLine(command + ' Unknown command', 'CER');
			}
		}
	}
	// message
	else if (user_input != '') {
		if (peer) {
			if (isChannelName(peer)) {
				var channel_status = this.loq_main.chat_status_mgr.GetChannelStatus(peer);
				if (channel_status) {
					if (channel_status.channelState == 'Joined') {
						this.loq_main.network.Send('PRIVMSG', peer.concat(' :', user_input));
						var channel_window = this.loq_main.chat_window_mgr.GetChannelWindow(peer);
						if (channel_window)
							channel_window.WriteMyMessage(this.loq_main.chat_status_mgr.myNick, user_input);
					}
					else {
						this.loq_main.status_window.WriteLine('<font color="#000080">* joining '.concat(peer, ' in progress...</font>'), 'CER');
					}
				}
			}
			else {
				var query_status = this.loq_main.chat_status_mgr.GetQueryStatus(peer);
				if (query_status) {
					this.loq_main.network.Send('PRIVMSG', peer.concat(' :', user_input));
					var query_window = this.loq_main.chat_window_mgr.GetQueryWindow(peer);
					if (query_window)
						query_window.WriteMyMessage(this.loq_main.chat_status_mgr.myNick, user_input);
				}
			}
		}
	}
}

function LoqUserInterpreter(loq_main)
{
	this.Execute = LoqUserInterpreter_Execute;

	this.loq_main = loq_main;
}
