jQuery.user = (function($) {
    var _deferredUser,
        _deferredUserWithoutLogin,
        _options,
        _deferredInit = $.Deferred(),
        self,
        _latestProfile,

        profileWasUpdated = function (profileData) {
            if (!_deferredUser || _deferredUser.done()) {
                _deferredUser = $.Deferred();
            }

            _latestProfile = fromData(profileData)
            _deferredUser.resolve(_latestProfile);
        },
        
        userLoggedOut = function () {
            if (_deferredUser && !_deferredUser.done()) {
                throw 'userLoggedOut, but there is an active _deferredUser';
            }

            _deferredUser = null;
            _latestProfile = null;
        },

        requestData = function () {
            var performGetRequest = function () {
                return $.ajax({
                    url: _options.dataHref,
                    dataType: 'json'
                });
            };


            if (_deferredInit.isResolved()) {
                return performGetRequest();
            }


            return _deferredInit.pipe(performGetRequest);
        },

        fromData = function (userData) {
            var u = $.extend({}, userData);

            if (u.artist) {
                u.artist = $.artist.fromData(userData.artist);
            }

            return u;
        };


    self = {
        init: function (options) {
            _options = options;

            $('#page').bind('loggedIn.loginManager', function(event, profile) {
                profileWasUpdated(profile);
            })
            .bind('loggedOut.loginManager', function() {
                userLoggedOut();
            });

            _deferredInit.resolve();
        },

        login: function () {
            return $('#page').loginManager('login');
        },

        update: function () {
            function onError(xhr) {
                switch (xhr.status) {
                    case 401:
                        self.login();
                        break;
                    default:
                        _deferredUser.reject(xhr);
                }
            }

            if (!_deferredUser || _deferredUser.done()) {
                _deferredUser = $.Deferred();

                requestData().then(profileWasUpdated, onError);
            }

            return _deferredUser.promise();
        },

        updateWithoutLogin: function () {
            if (!_deferredUserWithoutLogin) {
                _deferredUserWithoutLogin = $.Deferred();
                requestData().then(
                    function (data) {
                        _deferredUserWithoutLogin.resolve(fromData(data));
                        _deferredUserWithoutLogin = null;
                        profileWasUpdated(data);
                    },
                    function onError(xhr) {
                        _deferredUserWithoutLogin.reject(xhr);
                        _deferredUserWithoutLogin = null;
                        userLoggedOut();
                    }
                );
            }

            return _deferredUserWithoutLogin.promise();
        },

        fromData: fromData,

        currentIfAny: function () {
            if (_latestProfile === undefined) {
                return this.updateWithoutLogin();
            }
            else if (_latestProfile === null) {
                return $.Deferred().reject();
            }
            else {
                return $.Deferred().resolve(_latestProfile);
            }
        },

        current: function () {
            if (!_deferredUser) {
                this.update();
            }

            return _deferredUser.promise();
        }
    };

    return self;
})(jQuery);

