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