public async Task<Session> Login (LoginOptions options, string [] scope, CancellationToken token)
        {
            List<AccountProvider> providers = GetProviderChain (options, scope).ToList ();
            options.TryReportProgress (LoginProgress.Authorizing);

            var providerExceptions = new List<Exception> ();

            // Try each provider in turn
            foreach (var pi in providers.Select ((p, i) => new { Provider = p, Index = i })) {
                bool isLast = (pi.Index == providers.Count - 1);
                AccountProvider provider = pi.Provider;

                token.ThrowIfCancellationRequested ();

                try {
                    return await GetSession (provider, isLast, options, token);
                } catch (TaskCanceledException) {
                    throw;
                } catch (Exception ex) {
                    providerExceptions.Add (ex);
                }
            }

            // Neither provider worked
            throw new AggregateException ("Could not obtain session via either provider.", providerExceptions);
        }
        public async Task <Session> Login(LoginOptions options, string [] scope, CancellationToken token)
        {
            List <AccountProvider> providers = GetProviderChain(options, scope).ToList();

            options.TryReportProgress(LoginProgress.Authorizing);

            var providerExceptions = new List <Exception> ();

            // Try each provider in turn
            foreach (var pi in providers.Select((p, i) => new { Provider = p, Index = i }))
            {
                bool            isLast   = (pi.Index == providers.Count - 1);
                AccountProvider provider = pi.Provider;

                token.ThrowIfCancellationRequested();

                try {
                    return(await GetSession(provider, isLast, options, token));
                } catch (TaskCanceledException) {
                    throw;
                } catch (Exception ex) {
                    providerExceptions.Add(ex);
                }
            }

            // Neither provider worked
            throw new AggregateException("Could not obtain session via either provider.", providerExceptions);
        }
        async Task <Account> GetAccount(AccountProvider provider, bool allowFallback, LoginOptions options)
        {
            List <Account> accounts;

            options.TryReportProgress(provider.ProgressWhileAuthenticating);
            try {
                // Now, let's get accounts for current provider.
                // For different services and login methods, this may launch Safari, show iOS 6 prompt or just query ACAccounts.
                accounts = (await provider.GetAccounts()).ToList();
            } finally {
                options.TryReportProgress(LoginProgress.Authorizing);
            }

            if (accounts.Count == 0)
            {
                throw new InvalidOperationException("No accounts found for this service.");
            }

            if (accounts.Count == 1)
            {
                return(accounts [0]);
            }

            // If there is more than a single account, present an interface to choose one.
            // If fallback is available, add it to the list of options with null value.

            var choiceUI = options.AccountChoiceProvider;

            if (choiceUI == null)
            {
                throw new InvalidOperationException("There is more than one account, but no accountChoiceProvider was specified.");
            }

            // Add "Other" option that falls back to next provider
            if (allowFallback)
            {
                accounts.Add(null);
            }

            // Show chooser interface
            options.TryReportProgress(LoginProgress.PresentingAccountChoice);
            try {
                return(await choiceUI.ChooseAsync(accounts, a => (a != null)?a.Username : "******"));
            } finally {
                options.TryReportProgress(LoginProgress.Authorizing);
            }
        }
        async Task<Account> GetAccount (AccountProvider provider, bool allowFallback, LoginOptions options)
        {
            List<Account> accounts;

            options.TryReportProgress (provider.ProgressWhileAuthenticating);
            try {
                // Now, let's get accounts for current provider.
                // For different services and login methods, this may launch Safari, show iOS 6 prompt or just query ACAccounts.
                accounts = (await provider.GetAccounts ()).ToList ();
            } finally {
                options.TryReportProgress (LoginProgress.Authorizing);
            }

            if (accounts.Count == 0)
                throw new InvalidOperationException ("No accounts found for this service.");

            if (accounts.Count == 1)
                return accounts [0];

            // If there is more than a single account, present an interface to choose one.
            // If fallback is available, add it to the list of options with null value.

            var choiceUI = options.AccountChoiceProvider;
            if (choiceUI == null)
                throw new InvalidOperationException ("There is more than one account, but no accountChoiceProvider was specified.");

            // Add "Other" option that falls back to next provider
            if (allowFallback)
                accounts.Add (null);

            // Show chooser interface
            options.TryReportProgress (LoginProgress.PresentingAccountChoice);
            try {
                return await choiceUI.ChooseAsync (accounts, a => (a != null) ? a.Username : "******");
            } finally {
                options.TryReportProgress (LoginProgress.Authorizing);
            }
        }