/// <summary>
        /// This is the main configuration method. Call this in the Constructor of your app. This registers an error handler for unhandled errors.
        /// </summary>
        /// <param name="this"></param>
        /// <param name="appIdentifier">Your unique app id from HockeyApp.</param>
        /// <returns>Configurable Hockey client. Configure additional settings by calling methods on the returned IHockeyClientConfigurable</returns>
        public static IHockeyClientConfigurable Configure(this IHockeyClient @this, string appIdentifier)
        {
            @this.AsInternal().PlatformHelper = new HockeyPlatformHelper81();
            @this.AsInternal().AppIdentifier = appIdentifier;

            TaskScheduler.UnobservedTaskException += async (sender, e) =>
            {
                e.SetObserved();
                await HockeyClient.Current.AsInternal().HandleExceptionAsync(e.Exception);
                if (customUnobservedTaskExceptionFunc == null || customUnobservedTaskExceptionFunc(e))
                {
                    Application.Current.Exit();
                }
            };

            Application.Current.UnhandledException += async (sender, e) =>
            {
                e.Handled = true;
                await HockeyClient.Current.AsInternal().HandleExceptionAsync(e.Exception);
                if (customUnhandledExceptionFunc == null || customUnhandledExceptionFunc(e))
                {
                    Application.Current.Exit();
                }
            };

            
            return @this as IHockeyClientConfigurable;
        }
        public static IHockeyClientConfigurable Configure(this IHockeyClient @this, string identifier)
        {
            @this.AsInternal().AppIdentifier = identifier;
            @this.AsInternal().PlatformHelper = new HockeyPlatformHelperWPF();

            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
            Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
            TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;

            return (IHockeyClientConfigurable)@this;
        }
        /// <summary>
        /// Configures the client.
        /// </summary>
        /// <param name="this">This object.</param>
        /// <param name="identifier">Identifier.</param>
        /// <returns>HockeyClient configurable.</returns>
        public static IHockeyClientConfigurable Configure(this IHockeyClient @this, string identifier)
        {
            @this.AsInternal().AppIdentifier = identifier;
            @this.AsInternal().PlatformHelper = new HockeyPlatformHelperWPF();

            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
            Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
            ServiceLocator.AddService<IPlatformService>(new PlatformService());
            TelemetryConfiguration.Active.InstrumentationKey = identifier;
            
            return (IHockeyClientConfigurable)@this;
        }
        /// <summary>
        /// This is the main configuration method. Call this in the Constructor of your app. This registers an error handler for unhandled errors.
        /// </summary>
        /// <param name="this"></param>
        /// <param name="appIdentifier">Your unique app id from HockeyApp.</param>
        /// <param name="endpointAddress">The HTTP address where the telemetry is sent.</param>
        /// <param name="configuration">Telemetry configuration.</param>
        /// <returns>Configurable Hockey client. Configure additional settings by calling methods on the returned IHockeyClientConfigurable</returns>
        public static IHockeyClientConfigurable Configure(this IHockeyClient @this, string appIdentifier, TelemetryConfiguration configuration = null)
        {
            @this.AsInternal().PlatformHelper = new HockeyPlatformHelper81();
            @this.AsInternal().AppIdentifier = appIdentifier;

            ServiceLocator.AddService<BaseStorageService>(new StorageService());
            ServiceLocator.AddService<IApplicationService>(new ApplicationService());
            ServiceLocator.AddService<IDeviceService>(new DeviceService());
            ServiceLocator.AddService<Services.IPlatformService>(new PlatformService());
            ServiceLocator.AddService<IUnhandledExceptionTelemetryModule>(new UnhandledExceptionTelemetryModule());
            WindowsAppInitializer.InitializeAsync(appIdentifier, configuration);
            return @this as IHockeyClientConfigurable;
        }
        /// <summary>
        /// Configures HockeyClient.
        /// </summary>
        /// <param name="this">HockeyClient object.</param>
        /// <param name="identifier">Identfier.</param>
        /// <param name="keepRunningAfterException">Keep running after exception.</param>
        /// <returns>Instance object.</returns>
        public static IHockeyClientConfigurable Configure(this IHockeyClient @this, string identifier, bool keepRunningAfterException)
        {
            @this.AsInternal().PlatformHelper = new HockeyPlatformHelperWinForms();
            @this.AsInternal().AppIdentifier = identifier;

            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
            if (keepRunningAfterException)
            {
                Application.ThreadException += Current_ThreadException;
                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
            }

            TelemetryConfiguration.Active.InstrumentationKey = identifier;
            return (IHockeyClientConfigurable)@this;
        }
        public static IHockeyClientConfigurable Configure(this IHockeyClient @this, string identifier, bool keepRunningAfterException)
        {
            @this.AsInternal().PlatformHelper = new HockeyPlatformHelperWinForms();
            @this.AsInternal().AppIdentifier = identifier;

            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
            if (keepRunningAfterException)
            {
                Application.ThreadException += Current_ThreadException;
                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
            }
            TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;

            return (IHockeyClientConfigurable)@this;
        }
        /// <summary>
        /// main configuration method. call in app constructor
        /// </summary>
        /// <param name="this"></param>
        /// <param name="appId"></param>
        /// <param name="rootFrame"></param>
        /// <returns></returns>
        public static IHockeyClientConfigurable Configure(this IHockeyClient @this, string appId, TelemetryConfiguration telemetryConfiguration = null, Frame rootFrame = null)
        {
            @this.AsInternal().PlatformHelper = new HockeyPlatformHelperWP8SL();
            @this.AsInternal().AppIdentifier = appId;
            CrashHandler.Current.Application = Application.Current;
                
            ServiceLocator.AddService<BaseStorageService>(new StorageService());
            ServiceLocator.AddService<Services.IApplicationService>(new ApplicationService());
            ServiceLocator.AddService<Services.IPlatformService>(new PlatformService());
            ServiceLocator.AddService<IDeviceService>(new DeviceService());
            var exceptionModule = new UnhandledExceptionTelemetryModule(rootFrame);

            // we need to initialize in Configure method and not in WindowsAppInitializer.InitializeAsync 
            // to prevent UnauthorizedAccessException with Invalid cross-thread access message
            exceptionModule.Initialize();
            ServiceLocator.AddService<IUnhandledExceptionTelemetryModule>(exceptionModule);
            WindowsAppInitializer.InitializeAsync(appId, telemetryConfiguration);
            return @this as IHockeyClientConfigurable;
        }
 /// <summary>
 /// Inititate user identification and define a action to perform when authorization is successfull
 /// </summary>
 /// <param name="this">The this.</param>
 /// <param name="appSecret">The application secret from HockeyApp.</param>
 /// <param name="successAction">Action to perform when login is successfull</param>
 /// <param name="eMail">[Optional] E-Mail adress to prefill form</param>
 /// <param name="tokenValidationPolicy">[Optional] Default is EveryLogin</param>
 /// <param name="authValidationMode">[Optional] Default is Graceful</param>
 public static void IdentifyUser(this IHockeyClient @this, string appSecret,
     Action successAction, string eMail = null,
     TokenValidationPolicy tokenValidationPolicy = TokenValidationPolicy.EveryLogin,
     AuthValidationMode authValidationMode = AuthValidationMode.Graceful)
 {
     @this.AsInternal().CheckForInitialization();
     var authMan = AuthManager.Current;
     authMan.SuccessAction = successAction;
     authMan.AuthenticateUser(AuthenticationMode.Identify,
         tokenValidationPolicy, authValidationMode, eMail, appSecret);
 }
        /// <summary>
        /// main configuration method. call in app constructor
        /// </summary>
        /// <param name="this"></param>
        /// <param name="appId"></param>
        /// <param name="rootFrame"></param>
        /// <returns></returns>
        public static IHockeyClientConfigurable Configure(this IHockeyClient @this, string appId, Frame rootFrame = null)
        {
            @this.AsInternal().PlatformHelper = new HockeyPlatformHelperWP8SL();
            @this.AsInternal().AppIdentifier = appId;
            CrashHandler.Current.Application = Application.Current;
            CrashHandler.Current.Application.UnhandledException += (sender, args) => { 
                CrashHandler.Current.HandleException(args.ExceptionObject);
                if (customUnhandledExceptionAction != null)
                {
                    customUnhandledExceptionAction(args);
                }
            };

            if (rootFrame != null)
            {
                //Idea based on http://www.markermetro.com/2013/01/technical/handling-unhandled-exceptions-with-asyncawait-on-windows-8-and-windows-phone-8/
                //catch async void Exceptions
                AsyncSynchronizationContext.RegisterForFrame(rootFrame, CrashHandler.Current);
            }

            return @this as IHockeyClientConfigurable;
        }
 /// <summary>
 /// Send crashes to the HockeyApp server
 /// </summary>
 /// <param name="this"></param>
 /// <returns></returns>
 public static async Task<bool> SendCrashesAsync(this IHockeyClient @this)
 {
     @this.AsInternal().CheckForInitialization();
     bool result = await @this.AsInternal().SendCrashesAndDeleteAfterwardsAsync().ConfigureAwait(false);
     return result;
 }
 public static async Task<bool> HandleCrashesAsync(this IHockeyClient @this, Boolean sendAutomatically = false)
 {
     @this.AsInternal().CheckForInitialization();
     return await CrashHandler.Current.HandleCrashesAsync(sendAutomatically).ConfigureAwait(false);
 }
 /// <summary>
 /// Check for available updates
 /// </summary>
 /// <param name="this"></param>
 /// <param name="settings"><see cref="UpdateCheckSettings"/></param>
 public static void CheckForUpdates(this IHockeyClient @this, UpdateCheckSettings settings = null)
 {
     @this.AsInternal().CheckForInitialization();
     UpdateManager.Instance.RunUpdateCheck(settings);
 }
 /// <summary>
 /// Open the feedback UI
 /// </summary>
 /// <param name="this"></param>
 public static void ShowFeedback(this IHockeyClient @this)
 {
     @this.AsInternal().CheckForInitialization();
     FeedbackManager.Instance.NavigateToFeedbackUI();
 }
        /// <summary>
        /// Identify user with hockeaypp auth. Opening a login page to require valid email address for app if needed
        /// </summary>
        /// <param name="this"></param>
        /// <param name="appSecret">Your app's app secret (see HockeyApp app page)</param>
        /// <param name="successRedirect">Page-URI to redirect to after successful login</param>
        /// <param name="navigationService">[optional] obsolete - not needed</param>
        /// <param name="eMail">[Optional] initial email</param>
        /// <param name="tokenValidationPolicy"><see cref="TokenValidationPolicy"/></param>
        /// <param name="authValidationMode"><see cref="AuthValidationMode"/></param>
        public static void IdentifyUser(this IHockeyClient @this, string appSecret,
            Uri successRedirect, NavigationService navigationService = null,
            string eMail = null,
            TokenValidationPolicy tokenValidationPolicy = TokenValidationPolicy.EveryLogin,
            AuthValidationMode authValidationMode = AuthValidationMode.Graceful)

        {
            @this.AsInternal().CheckForInitialization();
            AuthManager.Instance.AuthenticateUser(successRedirect, AuthenticationMode.Identify, 
                tokenValidationPolicy, authValidationMode, eMail, appSecret);
        }
 /// <summary>
 /// Set the user Id and emal/contact information of the current user if known. This is sent to HockeyApp with crashes.
 /// </summary>
 /// <param name="this"></param>
 /// <param name="user"></param>
 /// <param name="email"></param>
 /// <returns></returns>
 public static IHockeyClient UpdateContactInfo(this IHockeyClient @this, string user, string email)
 {
     @this.AsInternal().UserID = user;
     @this.AsInternal().ContactInformation = email;
     return @this;
 }
 /// <summary>
 /// The provided func is called in case of an exception and the returned string is added as additional description of the exception.
 /// </summary>
 /// <param name="this"></param>
 /// <param name="descriptionLoader"></param>
 /// <returns></returns>
 public static IHockeyClientConfigurable SetExceptionDescriptionLoader(this IHockeyClientConfigurable @this, Func<Exception, string> descriptionLoader)
 {
     @this.AsInternal().DescriptionLoader = descriptionLoader;
     return @this;
 }
 /// <summary>
 /// Check for available updates asynchronously.
 /// </summary>
 /// <param name="this">The this.</param>
 /// <param name="autoShowUi">Use the default update dialogs</param>
 /// <param name="shutdownActions">Callback to gracefully stop your application. If using default-ui, call has to be provided.</param>
 /// <param name="updateAvailableAction">Callback for available versions, if you want to provide own update dialogs</param>
 /// <returns></returns>
 public static async Task<bool> CheckForUpdatesAsync(this IHockeyClient @this, bool autoShowUi, Func<bool> shutdownActions = null, Action<IAppVersion> updateAvailableAction = null)
 {
     @this.AsInternal().CheckForInitialization();
     //TODO refactor for next version
     return await HockeyClientWPF.Instance.UpdateManager.CheckForUpdatesAsync(autoShowUi, shutdownActions, updateAvailableAction);
 }
 /// <summary>
 /// Invoke this method to open the feedback UI where a user can send you a message including image attachments over the HockeyApp feedback system.
 /// </summary>
 /// <param name="this"></param>
 /// <param name="initialUserName">[Optional] Username to prefill the name field</param>
 /// <param name="initialEMail">[Optional] Email to prefill the email field</param>
 public static void ShowFeedback(this IHockeyClient @this, string initialUserName = null, string initialEMail = null)
 {
     @this.AsInternal().CheckForInitialization();
     var flyout = new FeedbackFlyout();
     FeedbackManager.Current.InitialEmail = initialEMail;
     FeedbackManager.Current.InitialUsername = initialUserName;
     flyout.ShowIndependent();
     
 }
 /// <summary>
 /// Creates a new Feedback-Thread. Thread is stored on the server with the first message.
 /// </summary>
 /// <returns></returns>
 public static IFeedbackThread CreateFeedbackThread(this IHockeyClient @this)
 {
     return @this.AsInternal().CreateNewFeedbackThread();
 }
 /// <summary>
 /// Opens a Feedback-Thread on the server.
 /// </summary>
 /// <param name="this">The this.</param>
 /// <param name="feedbackToken">A guid which identifies the Feedback-Thread</param>
 /// <returns>
 /// The Feedback-Thread or, if not found or delete, null.
 /// </returns>
 public static async Task<IFeedbackThread> OpenFeedbackThreadAsync(this IHockeyClient @this,string feedbackToken)
 {
     return await @this.AsInternal().OpenFeedbackThreadAsync(feedbackToken);
 }
        /// <summary>
        /// Send crashes to the HockeyApp server. If crashes are available a messagebox will popoup to ask the user if he wants to send crashes.
        /// </summary>
        /// <param name="this"></param>
        /// <param name="sendAutomatically">if true crashes will be sent without asking</param>
        /// <returns></returns>
        public static async Task<bool> SendCrashesAsync(this IHockeyClient @this, Boolean sendAutomatically = false)
        {
            @this.AsInternal().CheckForInitialization();

            if (sendAutomatically)
            {
                return await @this.AsInternal().SendCrashesAndDeleteAfterwardsAsync().ConfigureAwait(false);
            }
            else
            {
                if (await @this.AsInternal().AnyCrashesAvailableAsync())
                {
                    MessageBoxResult result = MessageBox.Show(LocalizedStrings.LocalizedResources.CrashLogQuestion, LocalizedStrings.LocalizedResources.CrashLogMessageBox, MessageBoxButton.YesNo);
                    if (result.Equals(MessageBoxResult.Yes))
                    {
                        return await @this.AsInternal().SendCrashesAndDeleteAfterwardsAsync().ConfigureAwait(false);
                    }
                    else
                    {
                        await @this.AsInternal().DeleteAllCrashesAsync().ConfigureAwait(false);
                    }
                }
                return false;
            }
        }
 /// <summary>
 /// Send any collected crashes to the HockeyApp server. You should normally call this during startup of your app. 
 /// </summary>
 /// <param name="this"></param>
 /// <param name="sendWithoutAsking">configures if available crashes are sent immediately or if the user should be asked if the crashes should be sent or discarded</param>
 /// <returns>true if crashes where sent successfully</returns>
 public static async Task<bool> SendCrashesAsync(this IHockeyClient @this, bool sendWithoutAsking = false)
 {
     @this.AsInternal().CheckForInitialization();
     return await CrashHandler.Current.HandleCrashesAsync(sendWithoutAsking);
 }
 /// <summary>
 /// Configures the client with a platform helper
 /// </summary>
 /// <param name="this">The this.</param>
 /// <param name="platformHelper">The platform helper.</param>
 /// <returns></returns>
 public static IHockeyClientConfigurable Configure(this IHockeyClient @this, IHockeyPlatformHelper platformHelper)
 {
     @this.AsInternal().PlatformHelper = platformHelper;
     return @this as IHockeyClientConfigurable;
 }
 /// <summary>
 /// Inititate user authorization and define a page navigate to when authorization is successfull
 /// </summary>
 /// <param name="this"></param>
 /// <param name="pageTypeForSuccessRedirect">Pagetype to navigate when login is successfull</param>
 /// <param name="eMail">[Optional] E-Mail adress to prefill form</param>
 /// <param name="tokenValidationPolicy">[Optional] Default is EveryLogin</param>
 /// <param name="authValidationMode">[Optional] Default is Graceful</param>
 public static void AuthorizeUser(this IHockeyClient @this,
    Type pageTypeForSuccessRedirect, string eMail = null,
    TokenValidationPolicy tokenValidationPolicy = TokenValidationPolicy.EveryLogin,
    AuthValidationMode authValidationMode = AuthValidationMode.Graceful)
 {
     @this.AsInternal().CheckForInitialization();
     var authMan = AuthManager.Current;
     authMan.SuccessRedirectPageType = pageTypeForSuccessRedirect;
     AuthManager.Current.AuthenticateUser(AuthenticationMode.Authorize,
         tokenValidationPolicy, authValidationMode, eMail, null);
 }
 /// <summary>
 /// Use this if you're using an on-premise version of HockeyApp. Default is: https://rink.hockeyapp.net
 /// </summary>
 /// <param name="this"></param>
 /// <param name="hockeyApiDomain"></param>
 /// <returns></returns>
 public static IHockeyClientConfigurable SetApiDomain(this IHockeyClientConfigurable @this, string hockeyApiDomain)
 {
     @this.AsInternal().ApiDomain = hockeyApiDomain;
     return @this;
 }