using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.BL; using Tango.BL.Entities; using Tango.Settings; using Tango.Core.DI; using Tango.FSE.Common; using System.Windows; using Tango.Core; using System.IO; using Tango.Core.Helpers; using Tango.FSE.Common.Modules; using System.Windows.Threading; using System.Data.SqlClient; using Tango.BL.Builders; using Tango.FSE.Common.Threading; using System.Diagnostics; using Tango.BL.Enumerations; using Tango.FSE.Common.Notifications; using Tango.Core.Threading; using Tango.Core.ExtensionMethods; using Tango.FSE.Common.Navigation; using Tango.FSE.Common.FSEApplication; using Tango.FSE.Common.Authentication; using Tango.FSE.BL; using Tango.FSE.Common.BugReporting; using Tango.FSE.Common.Build; namespace Tango.FSE.UI.FSEApplication { /// /// Represents the default FSE application manager. /// /// /// public class DefaultFSEApplicationManager : ExtendedObject, IFSEApplicationManager { private List _notifiedViewModels; private IDispatcherProvider _dispatcher; private IFSEModuleLoader _moduleLoader; private INotificationProvider _notificationProvider; private IAuthenticationProvider _authenticationProvider; private IBuildProvider _buildProvider; /// /// Occurs when the application has started. /// public event EventHandler ApplicationStarted; /// /// Occurs when all FSE modules are ready and initialized. /// public event EventHandler ModulesInitialized; /// /// Occurs when the application is ready and all modules are views are loaded. /// public event EventHandler ApplicationReady; /// /// Occurs when the main window content has been rendered. /// public event EventHandler ContentRendered; /// /// Occurs when the application has encountered an error when initializing. /// public event EventHandler ApplicationInitializationError; /// /// Gets the application startup arguments. /// public List StartupArgs { get; private set; } /// /// Gets a value indicating whether the application is shutting down. /// public bool IsShuttingDown { get; private set; } /// /// Gets the application version. /// public Version Version { get { return AssemblyHelper.GetCurrentAssemblyVersion(); } } /// /// Gets the application build date. /// public String BuildDate { get { return AssemblyHelper.GetCurrentAssemblyBuildDate().ToShortDateString(); } } /// /// Gets the application startup date. /// public DateTime StartUpDate { get; private set; } /// /// Gets a value indicating whether an update has occurred before the application started. /// public bool IsAfterUpdate { get; private set; } /// /// Gets a value indicating whether the application is past the event. /// public bool IsReady { get; private set; } /// /// Gets or sets the application folder. /// public String StartPath { get; private set; } private bool _displayWindowControls; /// /// Gets or sets a value indicating whether to display the main window controls. /// public bool DisplayWindowControls { get { return _displayWindowControls; } set { _displayWindowControls = value; RaisePropertyChangedAuto(); } } /// /// Gets or sets the state of the application main window. /// public WindowState WindowState { get { return MainWindow.Instance.WindowState; } set { MainWindow.Instance.WindowState = value; } } /// /// Gets a value indicating whether the application is currently debugging machine service via local host. /// public bool IsWebDebugMode { get { return StartupArgs.Contains("-webDebug"); } } /// /// Initializes a new instance of the class. /// public DefaultFSEApplicationManager(IDispatcherProvider dispatcherProvider, IFSEModuleLoader moduleLoader, INotificationProvider notificationProvider, IAuthenticationProvider authenticationProvider, IBuildProvider buildProvider) { DisplayWindowControls = true; StartPath = AssemblyHelper.GetCurrentAssemblyFolder(); StartupArgs = Common.Helpers.StartupArgsHelper.CleanArgsFromWeb(Environment.GetCommandLineArgs().Skip(1).ToArray()).ToList(); _notificationProvider = notificationProvider; _dispatcher = dispatcherProvider; _moduleLoader = moduleLoader; _authenticationProvider = authenticationProvider; _buildProvider = buildProvider; if (!DesignMode) { _notifiedViewModels = new List(); MainWindow.Instance.ContentRendered += (_, __) => { OnMainWindowContentRendered(); }; } } /// /// Called when the main window content has been rendered /// private void OnMainWindowContentRendered() { LogManager.Log("Main window content rendered."); ContentRendered?.Invoke(this, new EventArgs()); StartApplication(); } /// /// Starts the application. /// private async void StartApplication() { bool initialized = false; StartUpDate = DateTime.Now; await Task.Factory.StartNew(() => { try { initialized = true; } catch (Exception ex) { LogManager.Log(ex, "Application Initialization Error!"); ApplicationInitializationError?.Invoke(this, ex); return; } }); if (initialized) { try { PostDbInitialize(); } catch (Exception ex) { LogManager.Log(ex, "Application Post Initialization Error!"); ApplicationInitializationError?.Invoke(this, ex); return; } } } /// /// Called when the database has been initialized /// private void PostDbInitialize() { LogManager.Log($"Raising {nameof(ApplicationStarted)} event..."); ApplicationStarted?.Invoke(this, new EventArgs()); LogManager.Log("Invoking FSE view models OnApplicationStarted methods..."); foreach (var vm in TangoIOC.Default.GetAllInstancesByBase()) { if (!_notifiedViewModels.Contains(vm)) { LogManager.Log($"Invoking {vm.GetType().Name}.OnApplicationStarted..."); vm.OnApplicationStarted(); _notifiedViewModels.Add(vm); } } LogManager.Log("OnApplicationStarted methods for all INotifyApplicationStarted services..."); foreach (var instance in TangoIOC.Default.GetAllInstancesByBase()) { LogManager.Log($"Invoking {instance.GetType().Name}.OnApplicationStarted..."); instance.OnApplicationStarted(this); } var internalModules = this.GetType().Assembly.GetTypes().Where(xx => typeof(FSEModuleBase).IsAssignableFrom(xx)).ToList(); LogManager.Log("Waiting for IFSEModuleLoader instance injection..."); TangoIOC.Default.GetInstanceWhenAvailable((loader) => { LogManager.Log("Module loader instance has been registered. Registering for the ModulesLoaded event..."); loader.ModulesLoaded += (x, y) => { LogManager.Log("Loading modules views"); _dispatcher.InvokeBlock(() => { //Adding internal modules. LogManager.Log("Loading internal modules..."); foreach (var type in internalModules) { var module = _moduleLoader.AllModules.SingleOrDefault(m => m.GetType() == type); if (module == null) { module = Activator.CreateInstance(type) as IFSEModule; LogManager.Log("Loading module view " + module.Name + "..."); FrameworkElement view = Activator.CreateInstance(module.MainViewType) as FrameworkElement; SharedUI.Controls.NavigationControl.SetNavigationName(view, module.Name); Views.LayoutView.Instance.NavigationControl.Elements.Add(view); _moduleLoader.AllModules.Add(module); } else { _moduleLoader.UserModules.Remove(module); } if (_authenticationProvider.CurrentUser.HasAnyPermission(module.Permission)) { _moduleLoader.UserModules.Add(module); } } foreach (var module in TangoIOC.Default.GetInstance().UserModules) { if (!Views.LayoutView.Instance.NavigationControl.Elements.ToList().Exists(m => m.GetType() == module.MainViewType)) { try { LogManager.Log("Loading module view " + module.Name + "..."); FrameworkElement view = Activator.CreateInstance(module.MainViewType) as FrameworkElement; SharedUI.Controls.NavigationControl.SetNavigationName(view, module.Name); Views.LayoutView.Instance.NavigationControl.Elements.Add(view); } catch (Exception ex) { LogManager.Log(ex, $"Error loading module view for module {module.Name}."); } } } }); LogManager.Log($"{loader.UserModules.Count} modules loaded."); LogManager.Log($"Invoking {nameof(ModulesInitialized)} event."); ModulesInitialized?.Invoke(this, new EventArgs()); FinalizeModuleInitialization(); }; }); } /// /// Finalizes the module initialization. /// private void FinalizeModuleInitialization() { var settings = SettingsManager.Default.GetOrCreate(); LogManager.Log("Finalizing application initialization..."); //LogManager.Log("Initializing Machine Provider..."); //_machineProvider.Init(_machine, _machineContext); //LogManager.Log("Starting Machine Data Synchronizer..."); //_machineDataSynchronizer.IsEnabled = true; LogManager.Log("Applications initialization completed!"); LogManager.Log("Checking for un-notified FSE view models..."); foreach (var vm in TangoIOC.Default.GetAllInstancesByBase()) { if (!_notifiedViewModels.Contains(vm)) { LogManager.Log($"Invoking {vm.GetType().Name}.OnApplicationStarted..."); vm.OnApplicationStarted(); _notifiedViewModels.Add(vm); } } _dispatcher.Invoke(() => { DisplayWindowControls = true; LogManager.Log($"Invoking {nameof(ApplicationReady)} event."); ApplicationReady?.Invoke(this, new EventArgs()); LogManager.Log("Notifying view models about application ready..."); foreach (var vm in TangoIOC.Default.GetAllInstancesByBase()) { LogManager.Log($"Invoking {vm.GetType().Name}.OnApplicationReady..."); vm.OnApplicationReady(); } LogManager.Log("OnApplicationReady methods for all INotifyApplicationStarted services..."); foreach (var instance in TangoIOC.Default.GetAllInstancesByBase()) { LogManager.Log($"Invoking {instance.GetType().Name}.OnApplicationReady..."); instance.OnApplicationReady(this); } IsReady = true; //Check if application started after a crash. if (App.IsStartedAfterCrash) { _notificationProvider.PushErrorReportingSnackbar(new ApplicationStartedAfterCrashException(App.StartedAfterCrashError), "Application Terminated Unexpectedly", $"{_buildProvider.BuildName} was terminated unexpectedly in the previous run."); } }); } /// /// Shutdown the application. /// public void ShutDown() { if (IsShuttingDown) return; IsShuttingDown = true; try { LogManager.Log("Shutting down application..."); foreach (var vm in TangoIOC.Default.GetAllInstancesByBase()) { vm.OnApplicationShuttingDown(); } } catch { } try { var settings = SettingsManager.Default.GetOrCreate(); settings.TerminatedExpectedly = true; SettingsManager.Default.Save(); } catch { } LogManager.Log("Disposing disk cache..."); DiskCacheManager.Default.Dispose(); Environment.Exit(0); } /// /// Restarts the application. /// public async void Restart() { if (IsShuttingDown) return; IsShuttingDown = true; try { _dispatcher.Invoke(() => { var nav = TangoIOC.Default.GetInstance(); if (nav != null) { nav.NavigateTo(NavigationView.RestartingView); } }); LogManager.Log("Restarting the application..."); await Task.Delay(8000); foreach (var vm in TangoIOC.Default.GetAllInstancesByBase()) { vm.OnApplicationShuttingDown(); } } catch { } //try //{ // if (_machineProvider.MachineOperator.State == Transport.TransportComponentState.Connected) // { // _machineProvider.MachineOperator.Adapter.Disconnect().Wait(); // } //} //catch { } Process.Start(Application.ResourceAssembly.Location); Environment.Exit(0); } /// /// Gets a value indicating whether the application is currently running in demo mode. /// public bool DemoMode { get { return StartupArgs.Contains("-demo"); } } /// /// Activates the main window if it's not in focus. /// public void ActivateMainWindow() { MainWindow.Instance.Dispatcher.BeginInvoke(new Action(() => { MainWindow.Instance.Activate(); })); } } }