/**
 * api:
 *      IRC([required options])
 *          required options - {name, pass, channel}
 *
 *      IRC.connect()
 *          connects to the twitch irc server
 *
 *      IRC.on('command', callback)
 *          allows custom commands
 *
 *      IRC.on('data', callback)
 *          event when data is recieved / sent
 *
 *      IRC.msg(message, [options])
 *          options - {caller, auth[0/1]}
 *
 *      IRC.caller(data[0])
 *          parse out user name from socket data,
 *          mainly for plugin use when working with commands
 *
 * example:
 *      require:
 *          var irc = require('./lib/core/irc.js')({
 *              name    : 'TwitchBot',
 *              pass    : 'twitch!twitch!twitch!',
 *              channel : '#awesomebroadcaster'
 *          });
 *
 *      connect:
 *          irc.connect();
 *
 *      custom commands:
 *          irc.on('command' function (data) {
 *              if (data[3] == ':!command') {
 *                  // do something
 *              }
 *          });
 *
 *      irc data:
 *          irc.on('data', function (data) {
 *              //do something with data
 *          });
 *
 *      irc logging:
 *          irc.on('data', function (data) {
 *              irc.realtime(data);
 *          }
 *
 *      send a message to chat:
 *          irc.msg('Hi chat!');
 *          irc.msg('Hi chat!', {caller: 'SupremoRTD', auth: 1});
 *
 *      get user name:
 *          irc.caller(data[0]);
 */

var net = require('net'),
    events = require('events'),
    file = require('fs'),
    https = require('https'),
    utils = require('./utils.js');

//-------- Construct ---------
function IRC(options) {
    var __self = this;

    __self.options = options || {pass: 'irc_bot', name: 'irc_bot', channel: 'irc_bot'};

    __self.config = {
        // twitch bot info
        pass        : __self.options.pass,
        name        : __self.options.name,
        nick        : 'irc_bot',
        broadcaster : __self.options.channel.slice(1).charAt(0).toUpperCase() + __self.options.channel.slice(2).toLowerCase(),
        // twitch server
        addr        : 'irc.twitch.tv', //__self.options.name.toLowerCase() + '.jtvirc.com',
        port        : 6667,
        channel     : __self.options.channel.toLowerCase(),
        encoding    : 'ascii'
    };

    __self.mods = [];
    __self.buffer = [];

    // message queue
    __self.queue_timer = 2000;
    __self.queue_messages = [];
    __self.previous_message = '';

    // irc logging
    __self.check_streaming = 4;//minutes
    __self.streaming = false;
    __self.new_file = false;
    __self.log = '';
}

IRC.prototype = new events.EventEmitter();

//-------- Methods --------
IRC.prototype.start = function () {
    var __self = this;

    // check stream status
    function stream_status() {
        var time = utils.make_interval(__self.check_streaming);
        if (time === 0) {
            https.get('https://api.twitch.tv/kraken/streams/' + __self.config.channel.slice(1), function (response) {
                var body = '';

                // put together response
                response.on('data', function (chunk) {
                    body += chunk;
                });

                // log file creation
                response.on('end', function () {
                    var json = null;
                    try {
                        json = JSON.parse(body);
                        __self.streaming = json.stream !== null;
                    } catch (err) {
                        __self.streaming = false;
                    }
                    if (__self.streaming && !__self.new_file) {
                        // prevent another file from being created while streaming
                        __self.new_file = true;

                        // set stream time for file
                        var date = new Date(),
                            hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours(),
                            min = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes(),
                            sec = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds(),
                            streaming_time = '';

                        // create start time string
                        streaming_time += (date.getMonth().toString() + 1) + date.getDate().toString() + date.getFullYear().toString();
                        streaming_time += hours.toString() + min.toString() + sec.toString();

                        // create new log file
                        __self.log = './../logs/' + __self.config.channel.slice(1) + '_' + streaming_time.toString() + '.txt';
                        file.open(__self.log, 'w');
                    } else if (!__self.streaming) {
                        __self.new_file = false;
                        __self.log = '';
                    }
                    setTimeout(stream_status, 1000);
                });
            });
        } else {
            setTimeout(stream_status, time);
        }
    }

    stream_status();
    __self.connect();
    debugger;
    __self.monitor_queue();
};

IRC.prototype.realtime = function (data){
    var __self = this;

    // only log irc data if streaming
    if (__self.streaming) {
        // check if file exists, if it does append
        file.exists(__self.log, function (exists) {
            if (exists) {
                file.appendFile(__self.log, data + '\r\n', 'utf-8', function (err) {
                    if (err) {
                        throw err;
                    }
                });
            }
        });
    }
};

IRC.prototype.connect = function () {
    var __self = this;

    // create new socket
    __self.socket = new net.Socket();
    __self.socket.setEncoding(__self.config.encoding);
    __self.socket.setNoDelay();
    __self.socket.connect(__self.config.port, __self.config.addr);

    // connect to twitch irc via socket
    __self.socket.on('connect', function () {
        __self.emit('data', 'RECV - Established connection to Twitch IRC, registering user...');
        __self.raw('PASS ' + __self.config.pass, true);
        __self.raw('NICK ' + __self.config.name);
        __self.raw('USER ' + __self.config.nick + ' ' + __self.config.nick + '.com ' + __self.config.nick + ' :' + __self.config.name);
    });

    // handle incoming socket data
    __self.socket.on('data', function (data) {
        var prepack, lines, line, word;
        prepack = data.replace('\r\n', '\n');
        __self.buffer += prepack;
        lines = __self.buffer.split('\n');
        __self.buffer = '';

        if (lines[lines.length - 1] !== '') {
            __self.buffer = lines[lines.length - 1];
        }

        lines = lines.splice(0, lines.length - 1);
        for (var i = 0; i < lines.length; i++) {
            line = lines[i].replace('\r','');
            word = line.replace('\r', '').split(' ');
            __self.emit('data', 'RECV - ' + line);
            __self.join(word);
            __self.pingpong(word);
            __self.moderators(word);
            if (word[3] !== undefined) {
                __self.emit('command', word);
            }
        }
    });

    __self.socket.on('error', function(){
        __self.reconnect();
    });
};

// reconnect to socket
IRC.prototype.reconnect = function () {
    var __self = this;

    // send quit to server, destroy socket connection,
    // clear socket variable and then reconnect
    __self.socket.end('QUIT\r\n');
    __self.socket.destroy();
    __self.socket = null;
    __self.connect();
};

// join channel
IRC.prototype.join = function (data) {
    var __self = this;

    if (data[3] === ':>' || data[3] === ':End') {
        __self.raw('JOIN ' + __self.config.channel);
    }
};

// ping / pong
IRC.prototype.pingpong = function (data) {
    var __self = this;

    if (data[0] === 'PING') {
        __self.raw('PONG ' + data[1]);
    }
};

// store / remove mods
IRC.prototype.moderators = function (data) {
    var __self = this;

    if (data[1] === 'MODE') {
        if (data[4] !== undefined) {
            var user = data[4].charAt(0).toUpperCase() + data[4].slice(1);
            switch (data[3]) {
            case '+o':
                if (__self.mods.indexOf(user) < 0) {
                    __self.mods.push(user);
                }
                break;
            case '-o':
                if (__self.mods.indexOf(user) >= 0) {
                    __self.mods.splice(__self.mods.indexOf(user), 1);
                }
                break;
            }
        }
    }
};

// output to socket / console
IRC.prototype.raw = function (data, hide) {
    var __self = this;

    __self.socket.write(data + '\r\n', __self.config.encoding, function (){
        if (!hide) {
            // monitor commands sent by the bot
            // and push them to command action
            var parse = data.split(' ');
            if (parse[0] === 'PRIVMSG') {
                parse = __self.options.name + ' ' + data;
                __self.emit('command', parse.split(' '));
                __self.emit('data', 'SENT - ' + __self.options.name + ' ' + data);
            } else {
                // output response
                __self.emit('data', 'SENT - ' + data);
            }
        }
    });
};

// who sent message
IRC.prototype.caller = function (data) {
    var caller = data.split('!');

    return caller[0].charAt(1).toUpperCase() + caller[0].slice(2);
};

// send message to twitch chat
IRC.prototype.msg = function (msg, options) {
    var __self = this, opts = options || {caller:null, auth:0};

    switch (opts.auth) {
    case 0:
        __self.raw('PRIVMSG ' + __self.config.channel + ' :' + msg);
        break;
    case 1:
        if (__self.mods.indexOf(opts.caller) >= 0) {
            __self.raw('PRIVMSG ' + __self.config.channel + ' :' + msg);
        }
        break;
    }
};

// message queue
IRC.prototype.queue = function(msg) {
    var __self = this;
    __self.queue_messages.push(msg);
};

IRC.prototype.monitor_queue = function() {
    var __self = this, prepend_text = ['>', '+'];

    // handle messages in queue
    function handle_queue() {
        if (__self.queue_messages.length > 0) {
            var message = __self.queue_messages[0].message,
                options = __self.queue_messages[0].options,
                timer   = __self.queue_messages[0].timer || __self.queue_timer;

            // change message if it's the same as the previous message
            if (message === __self.previous_message) {
                for (var i = 0; i < prepend_text.length; i++) {
                    if (prepend_text[i] !== message.charAt(0)) {
                        message = prepend_text[i] + message.slice(1);
                        __self.previous_message = message;
                        break;
                    }
                }
            } else {
                __self.previous_message = __self.queue_messages[0].message;
            }

            // remove message from queue
            __self.queue_messages.splice(0, 1);

            // output message to chat
            setTimeout(function() {
                if (options === null) {
                    __self.msg(message);
                } else {
                    __self.msg(message, options);
                }
                // recheck the queue
                setTimeout(handle_queue, 500);
            }, timer);
        } else {
            setTimeout(handle_queue, 500);
        }
    }
    handle_queue();
};

module.exports = function (options) {
    return new IRC(options);
};
