(function (window, $) {
    'use strict';

    function CallsController(user, client, login, password) {
        this._user = user;
        this._client = client;
        this._serverInfo = this._user._config.sgConfiguration.networkProviderConfiguration.restConfig;
        this._login = login;
        this._password = password;

        this._calls = user.getCalls();

        this._callsView = new window.CallsView({
            makeCall: this.makeCall.bind(this),
        }, (this._login && this._password).length > 0);

        this._call = undefined;
        this._callController = undefined;

        this._init();
    }


    CallsController.prototype = {
        /**
         * Init function for Calls service.
         * Registration callbacks related with Calls service.
         */
        _init: function () {
            this._calls.addOnCallsServiceAvailableCallback(function () {
                console.log("Client:addOnCallsServiceAvailableCallback");
            });

            this._calls.removeOnCallCreatedCallback(function () {
                console.log("Client:removeOnCallCreatedCallback");
            });

            this._calls.removeOnCallRemovedCallback(function () {
                console.log("Client:removeOnCallRemovedCallback");
            });
        },

        /**
         * Prepares and starts a call.
         *
         * @param {string} roomId 
         * @param {boolean} hasVideo
         * @param {string} [displayName]
         */
        makeCall: function (roomId, hasVideo, displayName) {
            var createCall = this.onTokenRetrieved(roomId, hasVideo);
            var startCall = this.onCallCreated(this._client, roomId, hasVideo, this._callsView);

            this.authorize(roomId, displayName)
                .then(createCall)
                .then(startCall)
                .catch(this.handleError.bind(this));
        },

        /**
         * @param {string} roomId
         * @param {string} [displayName]
         * @returns {AvayaClientServices.Base.Promise}
         */
        authorize: function (roomId, displayName) {
            if (this._login && this._password) {
                return this.getUserToken(this._login, this._password).then(function (userToken) {
                    return this.getConferenceToken(roomId, undefined, userToken);
                }.bind(this));
            }
            else {
                return this.getConferenceToken(roomId, displayName);
            }
        },

        /**
         * Provides a function to create a call when token is retrieved.
         *
         * @param {string} roomId
         * @param {boolean} hasVideo
         * @returns {(token: string) => void}
         */
        onTokenRetrieved: function (roomId, hasVideo) {
            return function createCall (token) {
                var presentationOnly = false;
                var callCreationInfo = new AvayaClientServices.Services.Call.CallCreationInfo(roomId,
                                                                                              presentationOnly,
                                                                                              'Equinox Conference Call');
                callCreationInfo.setPortalToken(token);
                callCreationInfo.setCallType(AvayaClientServices.Services.Call.CallType.CallTypeHttpMeetMe);

                var call = this._calls.createCall(callCreationInfo);
                if (hasVideo) {
                    call.setVideoMode(AvayaClientServices.Services.Call.VideoMode.SEND_RECEIVE);
                }

                return call;
            }.bind(this);
        },

        /**
         * Provides a function to start a call when created.
         *
         * @param client
         * @param roomId
         * @param hasVideo
         * @param callsView
         * @returns {(call: AvayaClientServices.Services.Call.Call) => void}
         */
        onCallCreated: function (client, roomId, hasVideo, callsView) {
            this._callsView.clearErrors();

            return function startCall (call) {
                this._call = call;
                this._callController = new CallController(call, client, roomId, hasVideo, callsView);

                this._call.start();
            }.bind(this);
        },

        /**
         * Handler to be called if token retrieval has failed for some reason.
         *
         * @param {any} error
         */
        handleError: function (error) {
            this._callsView.unlock();

            if (error) {
                this._callsView.printError('Failed to make a call: ' + error);
            }
        },

        /**
         * Gets information to authorize request for conference token.
         * 
         * @param {string} login
         * @param {string} password
         * @returns {AvayaClientServices.Base.Promise}
         */
        getUserToken: function (login, password) {
            var authenticator = new LoginServiceAuthenticator(this._serverInfo);

            return authenticator.login(login, password);
        },

        /**
         * Gets a token to start a conference.
         *
         * @param {string} roomId
         * @param {string} [displayName]
         * @param {string} [userToken]
         * @returns {AvayaClientServices.Base.Promise}
         */
        getConferenceToken: function (roomId, displayName, userToken) {
            var authenticator = new TokenServiceAuthenticator(this._serverInfo);

            return authenticator.getConferenceToken(roomId, displayName, userToken);
        },
    };

    window.CallsController = CallsController;

})(window, jQuery);
