var serverHost = '127.0.0.1',
    serverPort = 6668,
    serverPass = '*',
    botNick = 'lousybot',
    joinChannels = [ '#test' ],
    pluginDir = './plugins',
    commandPrefix = '!',

    IRC_MESSAGE_END = '\r\n',

    fs = require('fs'),
    net = require('net'),
    spawn = require('child_process').spawn;

function formatIrcMessage(command, text) {
    return command + ' ' + text + IRC_MESSAGE_END;
}

function parseIrcMessage(s) {
    console.log('parse ' + s);

    var match = s.match(/(?::(.+?) )?(.+?) (.*)/),
        parsed = {
            prefix  : match[1],
            command : match[2],
            params  : match[3].split(' ')
        },
        hostmaskMatch;
      
    if (parsed.prefix !== undefined) {
        hostmaskMatch = parsed.prefix.match(/(.+)!(.+)@(.+)/);

        if (hostmaskMatch) {
            parsed.from = {
                nick : hostmaskMatch[1],
                user : hostmaskMatch[2],
                host : hostmaskMatch[3]
            };
        }
    }

    console.log(parsed);

    return parsed;
}

function loadPlugins(path) {
    var exp,
        plugin,
        pluginPath;

    fs.readdirSync(path).forEach(function (file) {
        if (file.match(/\.js$/)) {
            pluginPath = path + '/' + file;
            console.log('require ' + pluginPath);
            plugin = require(pluginPath);

            for (exp in plugin) {
                conn.addListener(exp, plugin[exp]);
            }
        }
    });
}

function parseBotCommand(s) {
    var argSep,
        command,
        result = {
            botCommand : '',
            botCommandArgs : '',
        };

    if (s.substr(0, commandPrefix.length) === commandPrefix) {
        command = s.substr(commandPrefix.length);
        argSep = command.indexOf(' ');
        if (argSep !== -1) {
            result.botCommand = command.substr(0, argSep),
            result.botCommandArgs = command.substr(argSep + 1, command.length);
        } else {
            result.botCommand = command;
        }
    }

    return result;
}

var conn = net.createConnection(serverPort, host=serverHost);
conn.botNick = botNick;
conn.messageBuffer = '';

conn.sendMessage = function (command, text) {
    var formatted = formatIrcMessage(command, text);

    console.log('send ' + formatted);
    this.write(formatted);
};

conn.privmsg = function (to, message) {
    this.sendMessage('PRIVMSG', to + ' :' + message);
};

conn.addListener('connect', function () {
    this.sendMessage('PASS', serverPass);
    this.sendMessage('NICK', botNick);
    this.sendMessage('USER', botNick + ' * * ' + botNick);
});

conn.addListener('data', function (buffer) {
    var connection;

    console.log('receive ' + buffer.toString());
    this.messageBuffer += buffer.toString();

    if (this.messageBuffer.match(new RegExp(IRC_MESSAGE_END + '$'))) {
        connection = this;
        this.messageBuffer.split(IRC_MESSAGE_END).forEach(function (message) {
            var parsedMessage;
            if (message !== '') {
                parsedMessage = parseIrcMessage(message);
                connection.emit(parsedMessage.command, parsedMessage);
            }
        });
        this.messageBuffer = '';
    }
});

// spawn a child process and call lineCallback for each line of its stdout
conn.spawn = function (command, args, lineCallback) {
    var child = spawn(command, args),
        buffer = '',
        lines;

    child.stdout.on('data', function (data) {
        lines = (buffer + data).split('\n');
        buffer = lines.pop();
        lines.forEach(lineCallback);
    });

    return child;
};

// IRC command listeners

// welcome
conn.addListener('001', function () {
    var connection = this;

    joinChannels.forEach(function (channel) {
        connection.sendMessage('JOIN', channel);
    });
});

conn.addListener('PING', function (m) {
    this.sendMessage('PONG', m.params[0]);
});

conn.addListener('PRIVMSG', function (m) {
    var botCommand,
        x;

    m.to = m.params[0];
    m.text = m.params.slice(1).join(' ').substr(1);

    botCommand = parseBotCommand(m.text);
    for (x in botCommand) {
        m[x] = botCommand[x];
    }

    if (m.to.match(/^#/)) {
        m.channel = m.to;
        this.emit('channelMessage', m);
    } else {
        this.emit('privateMessage', m);
    }
});

loadPlugins(pluginDir);

@@ -184,86 +184,229 @@
 !',%0A
-%0A    IRC_MESSAGE_END = '%5Cr%5Cn',%0A%0A    fs = require('fs'),%0A    net = require('net
+    enableHttp = true,%0A    httpPort = 31337,%0A    httpHost = 'localhost',%0A%0A    IRC_MESSAGE_END = '%5Cr%5Cn',%0A%0A    fs = require('fs'),%0A    http = require('http'),%0A    net = require('net'),%0A    queryString = require('querystring
 '),%0A
@@ -447,16 +447,42 @@
 ').spawn
+,%0A    url = require('url')
 ;%0A%0Afunct
@@ -1775,25 +1775,24 @@
 andArgs : ''
-,
 %0A        %7D;%0A
@@ -2030,17 +2030,17 @@
  argSep)
-,
+;
 %0A       
@@ -4510,8 +4510,634 @@
 inDir);%0A
+%0Aif (enableHttp) %7B%0A    http.createServer(function (req, resp) %7B%0A        var query,%0A            urlParsed;%0A%0A        urlParsed = url.parse(req.url);%0A%0A        console.log(req.method + ' ' + urlParsed.href);%0A%0A        query = queryString.parse(urlParsed.query);%0A%0A        if (query.to && query.message) %7B%0A            conn.privmsg(query.to, query.message);%0A        %7D%0A%0A        resp.writeHead(200, %7B  'Content-Type' : 'text/html' %7D);%0A        resp.end(conn.botNick + ' %3Cform method=%22get%22 action=%22%22%3E%3Cinput type=%22text%22 name=%22to%22 /%3E%3Cinput type=%22text%22 name=%22message%22 /%3E%3Cinput type=%22submit%22 /%3E%3C/form%3E');%0A    %7D).listen(httpPort, httpHost);%0A%7D%0A

add http interface to write messages to users and channels