var Net = require('net');

var Socket = exports.Socket = function (port, host) {
    this._data = [];
    this._listeners = ['connect', 'data', 'end', 'timeout', 'drain', 'error', 'close'];
    this._hasReconnected = false;
    this._drained = true;
    this._connected = false;

    this._c = null;

    this._port = port;
    this._host = host;
    this._socket = Net.createConnection(port, host);
};

Socket.prototype.on = Socket.prototype.addEventListener = function (eventName, eventCallback) {
    return this._socket.on(eventName, eventCallback);
};

Socket.prototype.write = function (data, encoding, callback) {
    if (this._drained && this._socket.writable) {
        this._write(data, encoding, callback);
    } else {
        this._data.push({data: data, encoding: encoding, callback: callback});
    }
};

Socket.prototype._write = function (data, encoding, callback) {
    this._drained = this._socket.write(data, encoding, function () {
        callback();
    });
};

Socket.prototype.bufferSize = function () {
    return this._socket.bufferSize;
};

Socket.prototype._executeWrites = function () {
    if (this._data[0]) {
        this._write(this._data[0].data, this._data[0].encoding, this._data[0].callback);
    }
};

Socket.prototype._refineHandlers = function () {
    var self = this;
    var i = null;
    var l = null;

    this._listeners.push('sClose');

    for (i = 0, l = this._listeners.length; i < l; i += 1) {
        this._socket.removeAllListeners(this._listeners[i]);
    }

    this._hasReconnected = false;

    this._socket.on('connect', function () {
        self._connected = true;

        if (self._hasReconnected) {
            console.info('Socket: reconnected! ' + self._host + ':' + self._port);
            self._executeWrites();
        } else {
            console.info('Socket: connected! ' + self._host + ':' + self._port);
        }
    });

    this._socket.on('drain', function () {
        if (self._data.length > 0) {
            do {
                var tmp = self._data.shift();

                if (!tmp) {
                    break;
                }

                self._write(tmp.data, tmp.encoding, tmp.callback);
            } while (self._drained);
        } else {
            self._drained = true;
        }
    });

    this._socket.on('close', function (byError) {
        self._connected = false;

        if (byError) {
            console.error('Socket: closed! (on error)');
        } else {
            console.info('Socket: closed! (NOT on error)');
        }
        self._onClose(this);
    });

    this._socket.on('error', function (error) {
        console.error('Socket: error! -> ' + error.message);
    });
};

Socket.prototype._onClose = function (socket) {
    var that = this;
    setTimeout(function () {
        console.info('Socket: trying to reconnect socket: ' + that._host + ':' + that._port);
        that._hasReconnected = true;
        socket.connect(that._port, that._host);
    }, 100);
};

Socket.prototype.destroy = function () {
    this._socket.destroy();
};

Socket.prototype.clearWriteQueue = function () {
    this._data = [];
};
