(function (AvayaClientServices, $) {

    /**
     * @class
     * @param {AvayaClientServices.Config.ServerInfo} serverInfo
     */
    function ServiceAuthenticator (serverInfo) {
        this.asyncAuthentication = $.Deferred();

        var scheme = serverInfo.isSecure === true ? 'https' : 'http';

        this.baseUrl = scheme + '://' + serverInfo.hostName + ':' + serverInfo.port;
    }

    /**
     * @param {Object} options
     * @returns {AvayaClientServices.Base.Promise}
     */
    ServiceAuthenticator.prototype.send = function (options) {
        $.ajax(this.getUrl(), options)
            .then(this.onSuccess.bind(this))
            .catch(this.onFailure.bind(this));

        return this.asyncAuthentication;
    };

    /**
     * @returns {string}
     */
    ServiceAuthenticator.prototype.getUrl = function () {
        return this.baseUrl + '/' + this.getPath();
    }

    /**
     * @abstract
     */
    ServiceAuthenticator.prototype.getPath = function () {};

    /**
     * @param {Object} result
     * @param {string} status
     * @param {Object} request
     */
    ServiceAuthenticator.prototype.onSuccess = function (result, status, request) {
        if (result && result.token) {
            this.asyncAuthentication.resolve(result.token);
        }
        else if (request.error) {
            this.asyncAuthentication.reject(request.error.errorMsg);
        }
        else {
            this.onFailure(request);
        }
    };

    /**
     * @param {Object} request
     */
    ServiceAuthenticator.prototype.onFailure = function (request) {
        this.asyncAuthentication.reject(request.status + ' ' + request.statusText);
    };

    /**
     * @class
     * @extends ServiceAuthenticator
     * @param {AvayaClientServices.Config.ServerInfo} serverInfo
     */
    function LoginServiceAuthenticator (serverInfo) {
        ServiceAuthenticator.call(this, serverInfo);
    }

    LoginServiceAuthenticator.prototype = Object.create(ServiceAuthenticator.prototype);

    /**
     * @param {string} login
     * @param {string} password
     * @returns {AvayaClientServices.Base.Promise}
     */
    LoginServiceAuthenticator.prototype.login = function (login, password) {
        var options = this.getOptions(login, password);

        return this.send(options);
    };

    /**
     * @override
     */
    LoginServiceAuthenticator.prototype.getPath = function () {
        return 'ups/resources/authentication/login';
    };

    /**
     * @param {string} login
     * @param {string} password
     * @returns {Object}
     */
    LoginServiceAuthenticator.prototype.getOptions = function (login, password) {
        return {
            method: 'POST',
            headers: {
                'Accept': 'application/vnd.avaya.portal.authentication.login.v1+json, application/vnd.avaya.portal.error.v1+json',
                'Content-Type': 'application/vnd.avaya.portal.authentication.login.v1+json'
            },
            data: JSON.stringify({
                login: login,
                password: password,
            }),
        };
    };

    /**
     * @class
     * @extends ServiceAuthenticator
     * @param {AvayaClientServices.Config.ServerInfo} serverInfo
     */
    function TokenServiceAuthenticator (serverInfo) {
        ServiceAuthenticator.call(this, serverInfo);
    }

    TokenServiceAuthenticator.prototype = Object.create(ServiceAuthenticator.prototype);

    /**
     * @param {string} meeting
     * @param {string} [name]
     * @param {string} [token]
     * @returns {AvayaClientServices.Base.Promise}
     */
    TokenServiceAuthenticator.prototype.getConferenceToken = function (meeting,
                                                                       name,
                                                                       token) {
        var options = this.getOptions(meeting, name, token);

        return this.send(options);
    };
 
    /**
     * @override
     */
    TokenServiceAuthenticator.prototype.getPath = function () {
        return 'ups/resources/middleware/token';
    };

    /**
     * @param {string} meeting
     * @param {string} [name]
     * @param {string} [token]
     * @returns {Object}
     */
    TokenServiceAuthenticator.prototype.getOptions = function (meeting,
                                                               name,
                                                               token) {
        var data = {
            conferenceId: meeting,
            presentationOnly: false,
            passcode: null,
        };
        
        var options = {
            method: 'POST',
            withCredentials: true,
            headers: {
                'Accept': 'application/vnd.avaya.portal.middleware.token.v1+json, application/vnd.avaya.csa.error.v1+json',
                'Content-Type': 'application/vnd.avaya.portal.middleware.token.v1+json',
            },
        };

        if (name) {
            data.userName = name;
        }

        options.data = JSON.stringify(data);
        
        if (token) {
            options.headers.Authorization = AvayaClientServices.Config.Authentication.TokenType.UPTOKEN + ' ' + token;
        }

        return options;
    };

    window.LoginServiceAuthenticator = LoginServiceAuthenticator;
    window.TokenServiceAuthenticator = TokenServiceAuthenticator;

})(AvayaClientServices, jQuery);
