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;
}
}
}