
var CredentialsProvider = require('../credentials/CredentialsProvider.js').CredentialsProvider;

var Event = require('../event/Event.js').Event;
var ErrorEvent = require('../event/ErrorEvent.js').ErrorEvent;

var OpalRequest = require('./OpalRequest.js').OpalRequest;
var OpalLoader = require('./OpalLoader.js').OpalLoader;
var Loader = require('../net/Loader.js').Loader;

//Multiton placeholder
var instances = {};

var OpalCredentialsProvider = function (credentialId, identity) {
    return OpalCredentialsProvider.getInstance(credentialId, identity);
};

/**
 * Multition
 * @static
 */ 
OpalCredentialsProvider.getInstance = function (credentialId, identity) {
    
    if (instances.hasOwnProperty(credentialId) && instances[credentialId].hasOwnProperty(identity) && instances[credentialId][identity]) {
        return instances[credentialId][identity];
    } else {
        
        var obj = Object.create(OpalCredentialsProvider.prototype);
        CredentialsProvider.call(obj);   
        obj._credentialId = credentialId;
        obj._identity = identity;
        obj._currentCredentials = null;
        obj.refreshTime = OpalCredentialsProvider.DEFAULT_REFRESH_TIME;
        obj.request = new OpalRequest({
            "url": "router.opaladmin.onetapi.pl",
            "method": "get_credentials",
            "params": {
                "ds_alias": obj._credentialId
            },
            "application": obj._identity
        });
        obj.loader = null;
        obj._refreshInProgress = false; 
        if (!instances[credentialId]) {
            instances[credentialId] = {};
        }
        instances[credentialId][identity] = obj;
        obj.refresh();
        return obj;
    }
};

OpalCredentialsProvider.prototype = Object.create(CredentialsProvider.prototype);

OpalCredentialsProvider.prototype.getCredentialId = function () {
    return this._credentialId;
}

OpalCredentialsProvider.prototype.get = function (callback) {
    
    if (this._currentCredentials && !this._refreshInProgress) {
        callback(null, this._currentCredentials);   
    } else {
        var that = this;
        var onCredentials = function (e) {
            
            that.removeEventListener(CredentialsProvider.Event.LOAD, onCredentials);
            callback(null, e.data);
        };
        this.addEventListener(CredentialsProvider.Event.LOAD, onCredentials, this);  
        if (!this._refreshInProgress) {
             
            this.refresh();
        }
    }
};
OpalCredentialsProvider.prototype.refresh = function () {
    
    this._refreshInProgress = true;
    this._sheduleRefresh(0);
};
CredentialsProvider.prototype.destroy = function () {
    if (this._refreshTimer) {
        clearTimeout(this._refreshTimer);
    }
    this._clearLoader();
    delete instances[this._credentialId][this._identity];
};


OpalCredentialsProvider.prototype._handleRefresh = function () {
    
    if (!this.loader) {
        this.loader = new OpalLoader(this.request);
        this.loader.addEventListener(OpalLoader.Event.JSON_RESPONSE, this._onLoad, this);
        this.loader.addEventListener(Loader.Event.ERROR, this._onError, this); 
        this.loader.load();
    }
};
OpalCredentialsProvider.prototype._handleError = function (error) {
    this._clearLoader();
    console.error(  
        "Credentials retrieving error.",
        "Credential key:", this._credentialId, 
        "Credentials identity:", this._identity, 
        "Error:", error.toString()
    );
    this.dispatchEvent(new ErrorEvent(CredentialsProvider.Event.ERROR, error));
    //TODO repete on error
    this._sheduleRefresh(this.refreshTime);
};

OpalCredentialsProvider.prototype._onLoad = function (e) {
    
    this._refreshInProgress = false;
    var rpc = e.data.getBody();
    if (rpc.isError()) {
        this._handleError(rpc.getError());
        return;
    }
    this._clearLoader();
    var newCredentials = rpc.getResult();
    
    if (JSON.stringify(newCredentials) != JSON.stringify(this._currentCredentials)) {
        this._currentCredentials = newCredentials;
        this.dispatchEvent(new Event(CredentialsProvider.Event.LOAD, this._currentCredentials));   
    }
    this._sheduleRefresh(this.refreshTime);
};

OpalCredentialsProvider.prototype._onError = function (e) {
    this._handleError(e.data);
};

OpalCredentialsProvider.prototype._clearLoader = function () {
    if (this.loader) {
        this.loader.removeEventListener(OpalLoader.Event.JSON_RESPONSE, this._onLoad);
        this.loader.removeEventListener(Loader.Event.ERROR, this._onError);
        this.loader = null;
    }
};

OpalCredentialsProvider.prototype._sheduleRefresh = function (period) {
    var that = this;
    if (this._refreshTimer) {
        clearTimeout(this._refreshTimer);
    }
    if (period === 0) {
        that._refreshTimer = null;
        that._handleRefresh();
    } else {    
        this._refreshTimer = setTimeout(function () {
            that._refreshTimer = null;
            that._handleRefresh();
        }, period);
    }
};


OpalCredentialsProvider.DEFAULT_REFRESH_TIME = 60000;
//OpalCredentialsProvider.ERROR_REFRESH_TIME = 1000;

exports.OpalCredentialsProvider = OpalCredentialsProvider;