using System; using System.Data; using System.Linq; using System.Windows; using System.IO; using Elwig.Helpers; using Elwig.Helpers.Weighing; using System.Collections.Generic; using System.Windows.Threading; using System.Globalization; using System.Threading; using System.Windows.Markup; using System.Reflection; using Elwig.Helpers.Printing; using Elwig.Windows; using Elwig.Dialogs; using System.Threading.Tasks; using Elwig.Helpers.Billing; using Elwig.Models.Entities; using System.Text; namespace Elwig { public partial class App : Application { protected static App CurrentApp; public static int NumWindows => CurrentApp.Windows.Count; public static bool ForceShutdown { get; private set; } = false; private readonly DispatcherTimer _autoUpdateTimer = new() { Interval = TimeSpan.FromHours(1) }; public static readonly string DataPath = @"C:\ProgramData\Elwig\"; public static readonly string ExePath = @"C:\Program Files\Elwig\"; public static readonly string TempPath = Path.Combine(Path.GetTempPath(), "Elwig"); public static Config Config { get; private set; } = new(Path.Combine(DataPath, "config.ini")); public static int VersionMajor { get; private set; } public static int VersionMinor { get; private set; } public static int VersionPatch { get; private set; } public static string Version { get => $"{VersionMajor}.{VersionMinor}.{VersionPatch}"; private set { var p = value.Split(".").Select(p => int.Parse(p.Trim())).ToArray(); VersionMajor = p.ElementAtOrDefault(0); VersionMinor = p.ElementAtOrDefault(1); VersionPatch = p.ElementAtOrDefault(2); } } public static int BranchNum { get; private set; } public static string ZwstId { get; private set; } public static string BranchName { get; private set; } public static int? BranchPlz { get; private set; } public static string? BranchLocation { get; private set; } public static string? BranchAddress { get; private set; } public static string? BranchPhoneNr { get; private set; } public static string? BranchFaxNr { get; private set; } public static string? BranchMobileNr { get; private set; } public static IList Scales { get; private set; } public static IList CommandScales => Scales.Where(s => s is ICommandScale).Cast().ToList(); public static IList EventScales => Scales.Where(s => s is IEventScale).Cast().ToList(); public static ClientParameters Client { get; set; } public static Dispatcher MainDispatcher { get; private set; } private DateTime LastChanged; private static DateTime CurrentLastWrite => File.GetLastWriteTime(Config.DatabaseFile); private readonly DispatcherTimer ContextTimer = new() { Interval = TimeSpan.FromSeconds(2) }; public App() : base() { Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); Directory.CreateDirectory(TempPath); Directory.CreateDirectory(DataPath); MainDispatcher = Dispatcher; Scales = []; CurrentApp = this; OverrideCulture(); var args = Environment.GetCommandLineArgs(); if (args.Length >= 2) { Config = new(Path.GetFullPath(args[1])); } ContextTimer.Tick += (object? sender, EventArgs evt) => { if (CurrentLastWrite > LastChanged) { LastChanged = CurrentLastWrite; OnContextChanged(); } }; } private static void OnContextChanged() { MainDispatcher.BeginInvoke(async () => await HintContextChange()); } private static void OverrideCulture() { var locale = new CultureInfo("de-AT", false); locale.NumberFormat.CurrencyGroupSeparator = Utils.GroupSeparator; locale.NumberFormat.NumberGroupSeparator = Utils.GroupSeparator; locale.NumberFormat.PercentGroupSeparator = Utils.GroupSeparator; CultureInfo.CurrentCulture = locale; CultureInfo.CurrentUICulture = locale; Thread.CurrentThread.CurrentCulture = locale; Thread.CurrentThread.CurrentUICulture = locale; CultureInfo.DefaultThreadCurrentCulture = locale; CultureInfo.DefaultThreadCurrentUICulture = locale; FrameworkElement.LanguageProperty.OverrideMetadata( typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.Name)) ); } protected override async void OnStartup(StartupEventArgs evt) { Version = typeof(App).GetTypeInfo().Assembly.GetCustomAttribute()?.InformationalVersion.Split('+')[0] ?? "0.0.0"; try { await AppDbUpdater.CheckDb(); } catch (Exception e) { if (Config.UpdateUrl != null && Utils.HasInternetConnectivity()) { await CheckForUpdates(); } MessageBox.Show($"Invalid Database:\n\n{e.Message}", "Invalid Database", MessageBoxButton.OK, MessageBoxImage.Error); Shutdown(); return; } LastChanged = CurrentLastWrite; ContextTimer.Start(); Dictionary branches = []; using (var ctx = new AppDbContext()) { branches = ctx.Branches.ToDictionary(b => b.Name.ToLower(), b => (b.ZwstId, b.Name, b.PostalDest?.AtPlz?.Plz, b.PostalDest?.AtPlz?.Ort.Name, b.Address, b.PhoneNr, b.FaxNr, b.MobileNr)); try { Client = new(ctx); } catch (Exception e) { MessageBox.Show($"Fehler beim Laden der Mandantendaten:\n\n{e.Message}", "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); Shutdown(); return; } BranchNum = branches.Count; } Utils.RunBackground("Temp File Cleanup", () => { Utils.CleanupTempFiles(); return Task.CompletedTask; }); Utils.RunBackground("HTML Initialization", () => Html.Init()); Utils.RunBackground("PDF Initialization", () => Pdf.Init()); Utils.RunBackground("JSON Schema Initialization", BillingData.Init); if (Config.UpdateAuto && Config.UpdateUrl != null) { if (Utils.HasInternetConnectivity()) { Utils.RunBackground("Auto Updater", async () => { await Task.Delay(500); await CheckForUpdates(); }); } _autoUpdateTimer.Tick += new EventHandler(OnAutoUpdateTimer); _autoUpdateTimer.Start(); } var list = new List(); foreach (var s in Config.Scales) { try { list.Add(Scale.FromConfig(s)); } catch (Exception e) { list.Add(new InvalidScale(s.Id)); if (s.Required) MessageBox.Show($"Unable to create scale {s.Id}:\n\n{e.Message}", "Scale Error", MessageBoxButton.OK, MessageBoxImage.Error); } } Scales = list; if (Config.Branch != null) { if (!branches.ContainsKey(Config.Branch.ToLower())) { MessageBox.Show("Invalid branch name in config!", "Invalid Branch Config", MessageBoxButton.OK, MessageBoxImage.Error); Shutdown(); } else { SetBranch(branches[Config.Branch.ToLower()]); } } else if (branches.Count == 1) { SetBranch(branches.First().Value); } else { MessageBox.Show("Unable to determine local branch!", "Invalid Branch Config", MessageBoxButton.OK, MessageBoxImage.Error); Shutdown(); } base.OnStartup(evt); var window = new MainWindow(); window.Show(); } private async void Application_Exit(object sender, ExitEventArgs evt) { await Pdf.Cleanup(); } public static void SetBranch(Branch b) { SetBranch((b.ZwstId, b.Name, b.PostalDest?.AtPlz?.Plz, b.PostalDest?.AtPlz?.Ort.Name, b.Address, b.PhoneNr, b.FaxNr, b.MobileNr)); } private static void SetBranch((string, string, int?, string?, string?, string?, string?, string?) entry) { ZwstId = entry.Item1; BranchName = entry.Item2; BranchPlz = entry.Item3; BranchLocation = entry.Item4?.Split(" im ")[0].Split(" an ")[0].Split(" bei ")[0]; // FIXME BranchAddress = entry.Item5; BranchPhoneNr = entry.Item6; BranchFaxNr = entry.Item7; BranchMobileNr = entry.Item8; } public static async Task HintContextChange() { CurrentApp.LastChanged = CurrentLastWrite; foreach (Window w in CurrentApp.Windows) { if (w is not ContextWindow c) continue; await c.HintContextChange(); } } private void OnAutoUpdateTimer(object? sender, EventArgs? evt) { foreach (Window w in CurrentApp.Windows) { if (w is UpdateDialog) return; } if (Utils.HasInternetConnectivity()) { Utils.RunBackground("Auto Updater", async () => await CheckForUpdates()); } } public static async Task CheckForUpdates(bool showAlert = false) { if (Config.UpdateUrl == null) return; var latest = await Utils.GetLatestInstallerUrl(Config.UpdateUrl); if (latest != null && new Version(latest.Value.Version) > new Version(Version)) { await MainDispatcher.BeginInvoke(() => { var d = new UpdateDialog(latest.Value.Version, latest.Value.Url, latest.Value.Size); if (d.ShowDialog() == true) { ForceShutdown = true; Current.Shutdown(); } }); } else if (showAlert) { if (latest == null) { MessageBox.Show("Informationen konnten nicht abgerufen werden!", "Nach Updates suchen", MessageBoxButton.OK, MessageBoxImage.Error); } else { MessageBox.Show($"Elwig ist auf dem aktuellsten Stand! (Version: {latest.Value.Version})", "Nach Updates suchen", MessageBoxButton.OK, MessageBoxImage.Information); } } } private static T FocusWindow(Func constructor, Predicate? selector = null) where T : Window { foreach (Window w in CurrentApp.Windows) { if (w is T t && (selector == null || selector(t))) { if (t.WindowState == WindowState.Minimized) t.WindowState = WindowState.Normal; t.Activate(); return t; } } var n = constructor(); n.Show(); return n; } public static DeliveryAdminWindow FocusReceipt() { return FocusWindow(() => new(true), w => w.ViewModel.IsReceipt); } public static DeliveryAdminWindow FocusMemberDeliveries(int mgnr) { return FocusWindow(() => new(mgnr), w => w.ViewModel.FilterMgNr == mgnr); } public static AreaComAdminWindow FocusMemberAreaComs(int mgnr) { return FocusWindow(() => new(mgnr), w => w.ViewModel.Member.MgNr == mgnr); } public static BaseDataWindow FocusBaseData() { return FocusWindow(() => new()); } public static BaseDataWindow FocusBaseDataAreaComType() { var w = FocusBaseData(); w.AreaCommitmentTypes.Focus(); return w; } public static BaseDataWindow FocusBaseDataSeason(int year) { var w = FocusBaseData(); w.Seasons.Focus(); ControlUtils.SelectItemWithPk(w.SeasonList, year); return w; } public static OriginHierarchyWindow FocusOriginHierarchy() { return FocusWindow(() => new()); } public static OriginHierarchyWindow FocusOriginHierarchyKg(int kgnr) { var w = FocusOriginHierarchy(); w.FocusKgNr(kgnr); return w; } public static PaymentVariantsWindow FocusPaymentVariants(int year) { return FocusWindow(() => new(year), w => w.Year == year); } public static PaymentAdjustmentWindow FocusPaymentAdjustment(int year) { return FocusWindow(() => new(year), w => w.Year == year); } public static ChartWindow FocusChartWindow(int year, int avnr) { return FocusWindow(() => new(year, avnr), w => w.Year == year && w.AvNr == avnr); } public static MemberAdminWindow FocusMember(int mgnr) { var w = FocusWindow(() => new()); w.FocusMember(mgnr); return w; } public static MailWindow FocusMailWindow(int? year = null) { return FocusWindow(() => new(year), w => year == null || w.Year == year); } } }