var Class = require("../class/Class.js").Class;
var ConnectionPool = require("./ConnectionPool.js").ConnectionPool;
var CredentialsManager = require("../credentials/Manager.js").CredentialsManager;
var Crypto = require("../common/Crypto.js");

var CredentialConnectionPool = function () {
    this.Extends = ConnectionPool;

    this.initialize = function (credentialKey, appName) {
        this.parent({});

        this._cm = null;
        this._throttleDisconnects = false;
        this._credentialKey;
        this._concurrentDisconnects = 0;
        this._maxConcurrentDisconnects = 50;
        this._concurrentDisconnectsRatio = 0.1;
        this._options = null;

        var self = this;

        setInterval(function () {
            console.info('CredentialConnectionPool: listeners waiting: ' + self._callbacks.length + ' sockets available: ' + self._sockets.length );
        }, 10 * 1000);

        this._credentialKey = credentialKey;

        this._cm = CredentialsManager.factory(appName);
        this._cm.addEventListener(CredentialsManager.Event.LOADED, credentialKey, function (data) {
            var index = Math.round(Math.random() * (data.data.hosts.length - 1));
            self._options = {
                host: data.data.hosts[index].host,
                port: data.data.hosts[index].port,
                connections: data.data.connectionPool || 10
            };

            console.info('CredentialConnectionPool: Received Credentials', JSON.stringify(self._options));

            // to zachodzi tylko podczas startowania (gdy tworzone sa nowe polaczenia)
            if (self._sockets.length == 0 && self._knownSockets.length == 0) {
                self._connect();
            } else {
                self._reconnect();
            }
        }).addEventListener(CredentialsManager.Event.ERROR, credentialKey, function (data) {
            console.error('CredentialConnectionPool/CREDENTIAL ERROR: ' + credentialKey + '. Error while receiving credential data for CredentialConnectionPool', JSON.stringify(data.data));
            setTimeout(function () {
                console.info('CredentialConnectionPool/CREDENTIAL INFO: getting credential -> ' + credentialKey);
                self._cm.renewCredential(credentialKey);
            }, 500);
        });
        this._cm.getCredential(credentialKey);
    };

    this._connect = function () {
        console.info('CredentialConnectionPool: Connecting');
        this.parent();
    };

    this._reconnect = function () {
        console.warn('CredentialConnectionPool: Reconnecting');
        for (var i = 0, l = this._knownSockets.length; i < l; i++) {
            //console.log('Destroying and reconnecting to socket:', i, this._options);
            this._knownSockets[i]._socket.destroy();
            //to sie dzieje w zdarzeniu close ktore jest wywolywane przy .destroy()
            this._knownSockets[i]._socket.connect(this._options.port, this._options.host);
            if(this._sockets.indexOf(this._knownSockets[i]) == -1) {
                this._sockets.push(this._knownSockets[i]);
            }
        }

        this._throttleDisconnects = false;
    };

    this._refineSocketHandlers = function (socket) {
        this.parent(socket);

        var self = this;

        socket.on('connect', function () {
            socket._disconnects = 0;
            self._concurrentDisconnects--;
        });

        if (socket.__onClose == undefined) {
            socket.__onClose = socket._onClose;
        }

        socket._onClose = function (sck) {
            (socket._disconnects) ? socket._disconnects++ : socket._disconnects = 1;
            self._concurrentDisconnects++;
            
            if (!self._throttleDisconnects) {
                console.info('CredentialConnectionPool: Disconnects: ' + socket._disconnects + ' | Concurrent Disconnects: ' + self._concurrentDisconnects);
                if (socket._disconnects >= 5 || self._concurrentDisconnects >= self._maxConcurrentDisconnects) {
                    self._throttleDisconnects = true;
                    
                    setTimeout(function () {
                        self._cm.renewCredential(self._credentialKey);
                    }, 500);
                } else {
                    socket.__onClose(sck);
                }
            }
        };
    };
};

CredentialConnectionPool = new Class(new CredentialConnectionPool());

exports.CredentialConnectionPool = CredentialConnectionPool;
