var Pool = require('../common/Pool.js').Pool,
    MemcachedSocket = require('./MemcachedSocket.js').MemcachedSocket,
    Socket = require('../net/Socket.js').Socket;
var CredentialsProvider = require('../credentials/CredentialsProvider.js').CredentialsProvider;

var instances = [];

var Memcached = exports.Memcached = function (cp) {
    return Memcached.getInstance(cp);
};

Memcached.prototype = {};

Memcached.getInstance = function (instanceId) {
    var cp = instanceId;
    for (var i = 0, len = instances.length; i < len; i++) {
        if (instances[i][0] === instanceId) {
            return instances[i][1];
        }
    }

    var instance = Object.create(Memcached.prototype);
    instance._pool = new Pool();
    instance._options = {};
    instance._options.__proto__ = {
        poolSize: 10,
        getOptions: {
            chunkSize: 800 * 1024,
            timeout: 1000
        },
        setOptions: {
            chunkSize: 800 * 1024,
            lifetime: 3600,
            waitForReply: false
        },
        deleteOptions: {
            waitForReply: false
        }
    };
    instance._cp = cp;
    instance._cp.addEventListener(CredentialsProvider.Event.LOAD, instance._onCredentialsLoaded, instance);
    instance._cp.addEventListener(CredentialsProvider.Event.ERROR, instance._onCredentialsError, instance);
    instance._cp.addEventListener(CredentialsProvider.Event.TIMEOUT, instance._onCredentialsTimeout, instance);
    instance._cp.get(function (error, data) {
        if (error) {
            instance._cp.refresh();
        } else {
            instance._onCredentialsLoaded({'data': data});
        }
    });
    instance._schedulePoolInfo(10000);
    instances.push([instanceId,instance]);
    return instance;
};

Memcached.prototype._onCredentialsLoaded = function (e) {
    var data = e.data
    /* mam tylko jeden host, jak bedzie wiecej to TODO */
    var connection = data.hosts[0];

    console.log('Memcached credentials loaded', connection);

    var max_connections = data.connectionPool || 10;
    var cur_connections = this._pool.getKnownLength();
    var create_connections = max_connections - cur_connections;
    this._createConnections(connection.host, connection.port, create_connections);
};


Memcached.prototype._onCredentialsError = function (data) {
    console.error('Memcached credentials error', data);
    this._cp.refresh();
};

Memcached.prototype._onCredentialsTimeout = function (data) {
    console.log('Memcached credentials timeout', data);
    this._cp.refresh();
};

Memcached.prototype._createConnections = function (host, port, count) {
    var socket;
    if (count > 0) {
        while(count) {
            socket = new Socket(port, host);
            socket._refineHandlers();
            this._pool.add(socket);
            count--;
        }
    }
};

Memcached.prototype._attachCallback = function (socket, callback) {
    var hasError = null;
    socket.addEventListener(MemcachedSocket.Event.ERROR, function (ev) {
        hasError = ev.message;
    });
    socket.addEventListener(MemcachedSocket.Event.END, function (ev) {
        callback(hasError, ev.data);
    });
};

Memcached.prototype.get = function (key, opts, callback) {
    var s = new MemcachedSocket(), self = this;

    var options = opts || {};
    options.__proto__ = this._options.getOptions;

    s.init(MemcachedSocket.Operation.GET, key, options);

    if (callback) {
        this._attachCallback(s, callback);
    }

    this._pool.get(function (socket) {
        s.setSocket(socket);
    });

    s.addEventListener(MemcachedSocket.Event.END, function () {
        s._socket._refineHandlers();
        self._pool.release(s._socket);
    });

    return s;
};

Memcached.prototype.set = function (key, opts, callback) {
    var s = new MemcachedSocket(), self = this;

    var options = opts;
    options.__proto__ = this._options.setOptions;

    s.init(MemcachedSocket.Operation.SET, key, options);

    if (callback) {
        this._attachCallback(s, callback);
    }

    this._pool.get(function (socket) {
        s.setSocket(socket);
    });

    s.addEventListener(MemcachedSocket.Event.END, function () {
        s._socket._refineHandlers();
        self._pool.release(s._socket);
    });

    return s;
};

Memcached.prototype.delete = function (key, opts, callback) {
    var s = new MemcachedSocket(), self = this;

    var options = opts || {};
    options.__proto__ = this._options.deleteOptions;

    s.init(MemcachedSocket.Operation.DELETE, key, options);

    if (callback) {
        this._attachCallback(s, callback);
    }

    this._pool.get(function (socket) {
        s.setSocket(socket);
    });

    s.addEventListener(MemcachedSocket.Event.END, function () {
        s._socket._refineHandlers();
        self._pool.release(s._socket);
    });

    return s;
};

Memcached.prototype.destroy = function () {
    this._cp.removeEventListener(CredentialsProvider.Event.LOAD, this._onCredentialsLoaded);
    this._cp.removeEventListener(CredentialsProvider.Event.ERROR, this._onCredentialsError);
    this._cp.removeEventListener(CredentialsProvider.Event.TIMEOUT, this._onCredentialsTimeout);
    if (this._poolInfoTimer) {
        clearTimeout(this._poolInfoTimer);
    }
};

Memcached.prototype._schedulePoolInfo = function (timeout) {
    var that = this;
    
    if (this._poolInfoTimer) {
        clearTimeout(this._poolInfoTimer);
    }
    
    this._poolInfoTimer = setTimeout(function () {
        that._poolInfo();
        that._schedulePoolInfo(timeout);
    }, timeout);
};

Memcached.prototype._poolInfo = function () {
    console.info('Memcached/Pool spare:', this._pool.getSpareLength());
};
