using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Forms;
using Core.Common.Base;
using Core.Common.Base.Plugin;
using Core.Common.Controls.Swf;
using Core.Common.Gui;
using Core.Common.Gui.Forms.MainWindow;
using Core.Common.Gui.Properties;
using Core.Common.Utils.Globalization;
using Core.Plugins.CommonTools;
using Core.Plugins.CommonTools.Gui;
using Core.Plugins.ProjectExplorer;
using Core.Plugins.SharpMapGis;
using Core.Plugins.SharpMapGis.Gui;
using log4net;
using Ringtoets.Integration.Plugin;
using Ringtoets.Piping.Plugin;
using MessageBox = System.Windows.MessageBox;
#if INCLUDE_DEMOPROJECT
using Ringtoets.Demo;
#endif
namespace Application.Ringtoets
{
///
/// Interaction logic for App.xaml.
///
public partial class App
{
private delegate void ExceptionDelegate(Exception exception, bool isTerminating);
// Start application after this process will exit (used during restart)
private const string argumentWaitForProcess = "--wait-for-process=";
private static readonly ILog log = LogManager.GetLogger(typeof(App));
private static RingtoetsGui gui;
private static int waitForProcessId = -1;
private static string projectFilePath;
private static Mutex singleInstanceMutex;
private static string previousExceptionsText = "";
private static int previousExceptionsCount;
static App()
{
SetLanguageAndRegionalSettings();
log.Info(Core.Common.Gui.Properties.Resources.App_App_Starting_Ringtoets);
}
public static void RunRingtoets()
{
log.Info(Core.Common.Gui.Properties.Resources.App_RunRingtoets_Starting_Ringtoets_Gui);
var loaderDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var startupDirectory = Directory.GetCurrentDirectory();
if (loaderDirectory != null)
{
Environment.CurrentDirectory = loaderDirectory;
}
//gui.ApplicationCore.ProjectRepositoryFactory.SpeedUpSessionCreationUsingParallelThread = true;
//gui.ApplicationCore.ProjectRepositoryFactory.SpeedUpConfigurationCreationUsingCaching = true;
//gui.ApplicationCore.ProjectRepositoryFactory.ConfigurationCacheDirectory = gui.ApplicationCore.GetUserSettingsDirectoryPath();
System.Windows.Forms.Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException, true);
// handle exception from UI thread
System.Windows.Forms.Application.ThreadException += Application_ThreadException;
// handle exception from all threads except UI
AppDomain.CurrentDomain.UnhandledException += AppDomain_UnhandledException;
if (projectFilePath == null)
{
gui.Run();
}
else
{
var path = File.Exists(projectFilePath)
? projectFilePath
: Path.Combine(startupDirectory, Path.GetFileName(projectFilePath));
if (File.Exists(path))
{
gui.Run(path);
}
else
{
log.ErrorFormat(Core.Common.Gui.Properties.Resources.App_RunRingtoets_Specified_project_0_was_not_found_, projectFilePath);
}
}
// Ringtoets started, clean-up all possible memory
GC.Collect();
GC.WaitForPendingFinalizers();
}
protected override void OnExit(ExitEventArgs e)
{
if (singleInstanceMutex != null)
{
singleInstanceMutex.ReleaseMutex();
}
base.OnExit(e);
}
private void App_Startup(object sender, StartupEventArgs e)
{
ParseArguments(e.Args);
WaitForPreviousInstanceToExit();
if (ShutdownIfNotFirstInstance())
{
return;
}
Resources.Add(SystemParameters.MenuPopupAnimationKey, PopupAnimation.None);
var applicationCore = new ApplicationCore();
applicationCore.AddPlugin(new CommonToolsApplicationPlugin());
#if INCLUDE_DEMOPROJECT
applicationCore.AddPlugin(new SharpMapGisApplicationPlugin());
#endif
applicationCore.AddPlugin(new RingtoetsApplicationPlugin());
applicationCore.AddPlugin(new PipingApplicationPlugin());
var settings = new GuiCoreSettings
{
StartPageUrl = "http://www.helpdeskwater.nl",
SupportEmailAddress = "support@deltaressystems.nl",
SupportPhoneNumber = "+31 (0)88 335 8100",
Copyright = "© Deltares 2015",
LicenseDescription = "Free",
MainWindowTitle = "Ringtoets",
LicenseFilePath = "License.rtf",
ManualFilePath = "Ringtoets_Manual.pdf"
};
gui = new RingtoetsGui(applicationCore, settings)
{
Plugins =
{
new ProjectExplorerGuiPlugin(),
new CommonToolsGuiPlugin(),
new SharpMapGisGuiPlugin(),
new RingtoetsGuiPlugin(),
new PipingGuiPlugin()
#if INCLUDE_DEMOPROJECT
, new DemoProjectGuiPlugin()
#endif
}
};
var mainWindow = new MainWindow(gui);
gui.MainWindow = mainWindow;
RunRingtoets();
mainWindow.Show();
}
private bool ShutdownIfNotFirstInstance()
{
var hasMutex = false;
try
{
if (!Debugger.IsAttached)
{
if (!AcquireSingleInstancePerUserMutex())
{
MessageBox.Show(Core.Common.Gui.Properties.Resources.App_ShutdownIfNotFirstInstance_Cannot_start_multiple_instances_of_Ringtoets_Please_close_the_other_instance_first);
Shutdown(1);
return true; //done here
}
hasMutex = true;
}
}
finally
{
if (!hasMutex)
{
singleInstanceMutex = null;
}
}
return false;
}
///
/// If variable waitForProcessId > -1, the application will hold until
/// the process with that ID has exited.
///
private static void WaitForPreviousInstanceToExit()
{
// Wait until previous version of Ringtoets has exited
if (waitForProcessId == -1)
{
return;
}
try
{
var process = Process.GetProcessById(waitForProcessId);
process.WaitForExit();
}
catch
{
//Ignored, because the process may already be closed
}
}
private static bool AcquireSingleInstancePerUserMutex()
{
var createdNew = false;
try
{
//include the user name in the (global) mutex to ensure we limit only the number of instances per
//user, not per system (essential on for example Citrix systems).
//include the application name in the mutex to ensure we are allowed to start for example 'Sobek'
//and 'Morphan' side by side.
var applicationName = ConfigurationManager.AppSettings.AllKeys.Contains("applicationName")
? ConfigurationManager.AppSettings["applicationName"]
: "";
var mutexName = string.Format("Ringtoets-single-instance-mutex-{0}-{1}", Environment.UserName,
applicationName);
singleInstanceMutex = new Mutex(true, mutexName, out createdNew);
}
catch (AbandonedMutexException) {} //might throw an abandoned mutex exception if the previous DS instance forcefully exited.
return createdNew;
}
private static void AppDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception exception;
exception = e.ExceptionObject as Exception;
if (exception == null)
{
exception = new Exception(Core.Common.Gui.Properties.Resources.App_AppDomain_UnhandledException_Unknown_exception_);
}
HandleExceptionOnMainThread(exception, e.IsTerminating);
}
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
HandleExceptionOnMainThread(e.Exception, false);
}
private static void HandleExceptionOnMainThread(Exception exception, bool isTerminating)
{
var control = (Control) gui.MainWindow.PropertyGrid;
if (control != null && control.InvokeRequired)
{
// Invoke executes a delegate on the thread that owns _MainForms's underlying window handle.
control.Invoke(new ExceptionDelegate(HandleException), new object[]
{
exception,
isTerminating
});
}
else
{
HandleException(exception, isTerminating);
}
}
private static void HandleException(Exception exception, bool isTerminating)
{
var dialog = new ExceptionDialog(exception, previousExceptionsText);
if (isTerminating)
{
dialog.ContinueButton.Visible = false;
}
dialog.RestartClicked += delegate
{
gui.SkipDialogsOnExit = true;
Restart();
};
dialog.ExitClicked += delegate
{
gui.SkipDialogsOnExit = true;
Environment.Exit(1);
};
dialog.ContinueClicked += delegate
{
previousExceptionsCount++;
var s = previousExceptionsText;
previousExceptionsText =
string.Format(Core.Common.Gui.Properties.Resources.App_HandleException_0_,
previousExceptionsCount,
dialog.ExceptionText,
s);
return;
};
dialog.OpenLogClicked += delegate
{
if (gui != null && gui.CommandHandler != null)
{
gui.CommandHandler.OpenLogFileExternal();
}
};
var mainWindow = gui.MainWindow as Form;
if (mainWindow != null && mainWindow.IsHandleCreated)
{
dialog.StartPosition = FormStartPosition.CenterParent;
dialog.ShowDialog(mainWindow); // show dialog at the center of main window
}
else
{
dialog.ShowDialog();
}
}
private static void Restart()
{
Process.Start(typeof(App).Assembly.Location, argumentWaitForProcess + Process.GetCurrentProcess().Id);
Environment.Exit(1);
}
///
/// Parses the process' start-up parameters.
///
/// List of start-up parameters.
private static void ParseArguments(IEnumerable arguments)
{
var argumentWaitForProcessRegex = new Regex("^" + argumentWaitForProcess + @"(?\d+)$", RegexOptions.IgnoreCase);
foreach (var arg in arguments)
{
var match = argumentWaitForProcessRegex.Match(arg);
if (match.Success)
{
var pid = int.Parse(match.Groups["processId"].Value);
if (pid > 0)
{
waitForProcessId = pid;
break;
}
}
}
}
private static void SetLanguageAndRegionalSettings()
{
var language = ConfigurationManager.AppSettings["language"];
if (language != null)
{
RegionalSettingsManager.Language = language;
}
if (Settings.Default.Properties.Count > 0)
{
var realNumberFormat = Settings.Default["realNumberFormat"];
if (realNumberFormat != null)
{
RegionalSettingsManager.RealNumberFormat = (string)realNumberFormat;
}
}
}
}
}