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.Integration.Operation; using Tango.Settings; using Tango.PPC.Common.Application; using Tango.Core.DI; using Tango.PPC.Common; using System.Windows; using Tango.Core; using System.IO; using Tango.Core.Helpers; using Tango.PPC.Common.Modules; using System.Windows.Threading; using Tango.Transport.Adapters; using Tango.PMR.Connection; using Tango.PPC.Common.Connection; using Tango.SQLExaminer; using System.Data.SqlClient; using Tango.BL.Builders; using Tango.PPC.Common.Threading; using System.Diagnostics; using Tango.PPC.Common.EventLogging; using Tango.BL.Enumerations; using Tango.PPC.Common.Notifications; using Tango.PPC.Common.WatchDog; using Tango.PPC.UI.Dialogs; using Tango.Core.Threading; using Tango.PPC.Common.Messages; using Tango.Core.ExtensionMethods; namespace Tango.PPC.UI.PPCApplication { /// /// Represents the default PPC application manager. /// /// /// public class DefaultPPCApplicationManager : ExtendedObject, IPPCApplicationManager { private List _notifiedViewModels; private IMachineProvider _machineProvider; private Machine _machine; private IDispatcherProvider _dispatcher; private IEventLogger _eventLogger; private IPPCModuleLoader _moduleLoader; private INotificationProvider _notificationProvider; private WatchDogServer _watchdogServer; private ObservablesContext _machineContext; private ActionTimer _screenLockTimer; /// /// Occurs when a system restart is required. /// public event EventHandler SystemRestartRequired; /// /// Occurs when the application has started. /// public event EventHandler ApplicationStarted; /// /// Occurs when all PPC 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 machine setup is required. /// public event EventHandler SetupRequired; /// /// 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 a value indicating whether the application is shutting down. /// public bool IsShuttingDown { get; private set; } private bool _isInTechnicianMode; /// /// Gets a value indicating whether the application is in technician mode. /// public bool IsInTechnicianMode { get { return _isInTechnicianMode; } set { _isInTechnicianMode = value; RaisePropertyChangedAuto(); } } /// /// 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; } private bool _isScreenLocked; /// /// Gets or sets a value indicating whether the screen is currently locked. /// public bool IsScreenLocked { get { return _isScreenLocked; } set { _isScreenLocked = value; RaisePropertyChangedAuto(); } } /// /// Initializes a new instance of the class. /// public DefaultPPCApplicationManager(IMachineProvider machineProvider, IDispatcherProvider dispatcherProvider, IEventLogger eventLogger, IPPCModuleLoader moduleLoader, INotificationProvider notificationProvider) { _notificationProvider = notificationProvider; _machineProvider = machineProvider; _dispatcher = dispatcherProvider; _eventLogger = eventLogger; _moduleLoader = moduleLoader; 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(); } private async void StartApplication() { PPCSettings settings = null; bool initialized = false; bool isAfterSetup = false; StartUpDate = DateTime.Now; await Task.Factory.StartNew(() => { try { LogManager.Log("Reading PPC settings..."); settings = SettingsManager.Default.GetOrCreate(); LogManager.Log(settings.ToJsonString()); //Start watchdog _watchdogServer = new WatchDogServer(Application.Current.Dispatcher); #if !DEBUG if (settings.EnableWatchDog) { _watchdogServer.Start(); } #endif LogManager.Log("Reading Core settings..."); var coreSettings = SettingsManager.Default.GetOrCreate(); if (!SettingsManager.Default.IsFileExists()) { LogManager.Log("Settings file does not exists. creating..."); settings.Save(); } if (App.StartupArgs.Contains("-update_ok")) { LogManager.Log("Application started with '-update_ok' startup arguments. The application has been successfully updated."); if (settings.ApplicationState == ApplicationStates.PreSetup) { isAfterSetup = true; LogManager.Log("System restart is required."); } settings.ApplicationState = ApplicationStates.Ready; settings.Save(); if (isAfterSetup) { SystemRestartRequired?.Invoke(this, new EventArgs()); return; } } if (settings.ApplicationState == ApplicationStates.Ready) { LogManager.Log("Initializing ObservablesStaticCollections..."); ObservablesStaticCollections.Instance.Initialize(); LogManager.Log("Loading machine from database..."); _machineContext = ObservablesContext.CreateDefault(); _machine = new MachineBuilder(_machineContext).SetFirst().WithVersion().WithSettings().WithOrganization().WithConfiguration().WithSpools().WithCats().Build(); } initialized = true; } catch (Exception ex) { LogManager.Log(ex, "Application Initialization Error!"); ApplicationInitializationError?.Invoke(this, ex); return; } }); if (initialized) { try { if (settings.ApplicationState == ApplicationStates.PreSetup || settings.ApplicationState == ApplicationStates.FactoryRestore) { LogManager.Log($"The application is in {settings.ApplicationState} state. database initialization skipped. Invoking setup required event!"); SetupRequired?.Invoke(this, new EventArgs()); } else { 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..."); _eventLogger.Log(EventTypes.APPLICATION_STARTED, "Application Started!"); ApplicationStarted?.Invoke(this, new EventArgs()); LogManager.Log("Invoking PPC 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("Waiting for IPPCModuleLoader 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(() => { foreach (var module in TangoIOC.Default.GetInstance().UserModules) { if (!Views.LayoutView.Instance.NavigationControl.Elements.ToList().Exists(m => m.GetType() == module.MainViewType)) { 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); } } }); 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("Applications initialization completed!"); LogManager.Log("Checking for un-notified PPC 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(() => { 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(); } if (settings.EnableTechnicianModeByDefault) { EnterTechnicianMode(false); } if (settings.EnableLockScreen) { _screenLockTimer = new ActionTimer(settings.LockScreenTimeout); _screenLockTimer.ResetReplace(ScreenLockTimerAction); } TangoMessenger.Default.Register((msg) => { if (_screenLockTimer != null) { _screenLockTimer.Dispose(); _screenLockTimer = null; } if (settings.EnableLockScreen) { _screenLockTimer = new ActionTimer(settings.LockScreenTimeout); _screenLockTimer.ResetReplace(ScreenLockTimerAction); } }); }); } /// /// Shutdown the application. /// public void ShutDown() { if (IsShuttingDown) return; IsShuttingDown = true; try { LogManager.Log("Shutting down application..."); _watchdogServer.Dispose(); foreach (var vm in TangoIOC.Default.GetAllInstancesByBase()) { vm.OnApplicationShuttingDown(); } } catch { } Environment.Exit(0); } /// /// Restarts the application. /// public void Restart() { if (IsShuttingDown) return; IsShuttingDown = true; try { LogManager.Log("Restarting the application..."); _watchdogServer.Dispose(); 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); } /// /// Runs the updater utility and exits the application. /// public void UpdateApplication(String updaterPath, String arguments) { if (IsShuttingDown) return; IsShuttingDown = true; try { _watchdogServer.Dispose(); foreach (var vm in TangoIOC.Default.GetAllInstancesByBase()) { vm.OnApplicationShuttingDown(); } } catch { } LogManager.Log($"Executing '{updaterPath}' with arguments '{arguments}'..."); Process.Start(updaterPath, arguments); LogManager.Log("Terminating application..."); Environment.Exit(0); } /// /// Enteres the application technician mode. /// public async void EnterTechnicianMode(bool displayNotification = true) { if (displayNotification) { var vm = await _notificationProvider.ShowDialog(); if (vm.DialogResult) { if (vm.Password == "Aa123456") { IsInTechnicianMode = true; _moduleLoader.AllModules.ToList().ForEach(x => x.OnTechnicianEntered()); await _notificationProvider.ShowInfo("Technician mode is now enabled."); } else { await _notificationProvider.ShowError("Invalid technician mode password."); EnterTechnicianMode(); } } } else { IsInTechnicianMode = true; _moduleLoader.AllModules.ToList().ForEach(x => x.OnTechnicianEntered()); } } /// /// Exits the application technician mode. /// public void ExitTechnicianMode() { IsInTechnicianMode = false; _moduleLoader.AllModules.ToList().ForEach(x => x.OnTechnicianExited()); _notificationProvider.ShowInfo("Technician mode is now disabled."); } /// /// Invokes a dialog for entering a password and releasing the screen lock. /// public async void ReleaseScreenLock() { if (IsScreenLocked) { var vm = await _notificationProvider.ShowDialog(); if (vm.DialogResult) { if (vm.Password == SettingsManager.Default.GetOrCreate().LockScreenPassword) { IsScreenLocked = false; ResetScreenLockTimer(); } } } } public void ResetScreenLockTimer() { if (_screenLockTimer != null) { _screenLockTimer.ResetReplace(ScreenLockTimerAction); } } private void ScreenLockTimerAction() { IsScreenLocked = true; } } }