using Elwig.Dialogs; using Elwig.Helpers; using Elwig.Models.Entities; using Elwig.Services; using Elwig.ViewModels; using Microsoft.EntityFrameworkCore; using System; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace Elwig.Windows { public partial class AreaComAdminWindow : AdministrationWindow { public AreaComAdminViewModel ViewModel => (AreaComAdminViewModel)DataContext; private readonly RoutedCommand CtrlF = new("CtrlF", typeof(AreaComAdminWindow), [new KeyGesture(Key.F, ModifierKeys.Control)]); public AreaComAdminWindow(int mgnr) { InitializeComponent(); CommandBindings.Add(new CommandBinding(CtrlF, FocusSearchInput)); using var ctx = new AppDbContext(); ViewModel.FilterMember = ctx.Members.Find(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value"); ViewModel.Title = $"Flächenbindungen - {ViewModel.FilterMember.AdministrativeName} - Elwig"; ExemptInputs = [ AreaCommitmentList, RevisionList, NewAreaCommitmentButton, EditAreaCommitmentButton, DeleteAreaCommitmentButton, SaveButton, ResetButton, CancelButton, SearchInput, SeasonInput ]; RequiredInputs = [ FbNrInput, MgNrInput, MemberInput, YearFromInput, KgInput, RdInput, GstNrInput, AreaInput, AreaComTypeInput, WineCultivationInput ]; ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged); SearchInput.TextChanged -= SearchInput_TextChanged; ViewModel.FilterSeason = Utils.CurrentYear; } private void FocusSearchInput(object sender, RoutedEventArgs evt) { if (!IsEditing && !IsCreating) { SearchInput.Focus(); SearchInput.SelectAll(); } } private async Task RefreshList(bool updateSort = false) { var vm = ViewModel; var cursor = Mouse.OverrideCursor != null; if (!cursor) Mouse.OverrideCursor = Cursors.Wait; var query = (vm.SearchQuery, vm.FilterSeason); var (filter, contracts, areaComs, areaComCount, stat) = await Task.Run(async () => { using var ctx = new AppDbContext(); var (_, contractQuery, areaComQuery, filter) = await vm.GetFilters(ctx); var contracts = await contractQuery .Include(c => c.Revisions).ThenInclude(a => a.Member) .ToListAsync(); var areaComs = await areaComQuery.ToListAsync(); if (filter.Count > 0 && contracts.Count > 0) { var dict = contracts.AsParallel() .ToDictionary(d => d, d => d.SearchScore(vm.TextFilter)) .OrderByDescending(c => c.Value); var threshold = dict.Max(a => a.Value) * 3 / 4; contracts = [.. dict .Where(a => a.Value > threshold) .Select(a => a.Key)]; } var areaComCount = await areaComQuery.CountAsync(); var season = await ctx.FetchSeasons().FirstOrDefaultAsync(); var stat = await AreaComService.GenerateToolTipData(areaComQuery, season?.MaxKgPerHa ?? 10_000); return (filter, contracts, areaComs, areaComCount, stat); }); if (!cursor) Mouse.OverrideCursor = null; if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason)) return; ControlUtils.RenewItemsSource(AreaCommitmentList, contracts, AreaCommitmentList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort); RefreshInputs(); if (filter.Count == 0) { ViewModel.StatusAreaCommitments = $"{areaComCount:N0}"; var (text, gridData) = stat; ViewModel.StatusArea = text; ViewModel.StatusAreaToolTip = AreaComService.GenerateToolTip(gridData); } else { ViewModel.StatusAreaCommitments = $"{contracts.Count:N0}"; ViewModel.StatusArea = $"{areaComs.Sum(a => a.Area):N0} m²"; ViewModel.StatusAreaToolTip = null; } var groups = areaComs.GroupBy(a => $"{a.AreaComType.SortId}{a.AreaComType.AttrId}").Select(a => (a.Key, a.Sum(b => b.Area))).OrderByDescending(a => a.Item2).ToList(); ViewModel.StatusContracts = $"{groups.Count:N0}"; if (groups.Count > 0) ViewModel.StatusContracts += $" ({string.Join(", ", groups.Select(g => g.Key))})"; } private async Task RefreshRevisions() { using var ctx = new AppDbContext(); if (AreaCommitmentList.SelectedItem is AreaComContract c) { ControlUtils.RenewItemsSource(RevisionList, c.Revisions.OrderByDescending(p => p.RevNr).ToList(), RevisionList_SelectionChanged, ControlUtils.RenewSourceDefault.First); } else { RevisionList.ItemsSource = null; } } private void RefreshInputs(bool validate = false) { ClearInputStates(); if (RevisionList.SelectedItem is AreaCom a) { EditAreaCommitmentButton.IsEnabled = true; DeleteAreaCommitmentButton.IsEnabled = true; FillInputs(a); } else if (AreaCommitmentList.SelectedItem is AreaComContract c) { EditAreaCommitmentButton.IsEnabled = true; DeleteAreaCommitmentButton.IsEnabled = true; FillInputs(c); } else { EditAreaCommitmentButton.IsEnabled = false; DeleteAreaCommitmentButton.IsEnabled = false; ClearOriginalValues(); ClearDefaultValues(); ClearInputs(validate); ClearInputStates(); } GC.Collect(); } private void FillInputs(AreaComContract c) { ClearOriginalValues(); ClearDefaultValues(); ViewModel.FillInputs(c); FinishInputFilling(); } private void FillInputs(AreaCom a) { FillInputs(a.Contract); ClearOriginalValues(); ClearDefaultValues(); ViewModel.FillInputs(a); FinishInputFilling(); } private async Task InitInputs() { ClearOriginalValues(); ClearDefaultValues(); await ViewModel.InitInputs(); SetDefaultValue(FbNrInput); ValidateRequiredInputs(); } new protected void ClearInputs(bool validate = false) { ViewModel.ClearInputs(); base.ClearInputs(validate); } protected override async Task OnRenewContext(AppDbContext ctx) { await base.OnRenewContext(ctx); if (await ctx.FetchMembers(ViewModel.FilterMember.MgNr).SingleOrDefaultAsync() is not Member m) { Close(); return; } ViewModel.FilterMember = m; ViewModel.Title = $"Flächenbindungen - {ViewModel.FilterMember.AdministrativeName} - Elwig"; ControlUtils.RenewItemsSource(KgInput, await ctx.WbKgs .Include(k => k.AtKg.WbKg!.Rds) .Select(k => k.AtKg) .OrderBy(k => k.Name) .ToListAsync()); ControlUtils.RenewItemsSource(AreaComTypeInput, await ctx.AreaCommitmentTypes .Include(c => c.WineVar) .Include(c => c.WineAttr) .OrderBy(v => v.VtrgId) .ToListAsync()); ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: true).ToListAsync()); var cultList = await ctx.FetchWineCultivations().Cast().ToListAsync(); cultList.Insert(0, new NullItem()); ControlUtils.RenewItemsSource(WineCultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First); await RefreshList(); } protected override void ShortcutNew() { if (!NewAreaCommitmentButton.IsEnabled || NewAreaCommitmentButton.Visibility != Visibility.Visible) return; NewAreaCommitmentButton_Click(null, null); } private async void NewAreaCommitmentButton_Click(object? sender, RoutedEventArgs? evt) { IsCreating = true; AreaCommitmentList.IsEnabled = false; AreaCommitmentList.SelectedItem = null; RevisionList.IsEnabled = false; HideNewEditDeleteButtons(); ShowSaveResetCancelButtons(); UnlockInputs(); await InitInputs(); LockSearchInputs(); } protected override void ShortcutEdit() { if (!EditAreaCommitmentButton.IsEnabled || EditAreaCommitmentButton.Visibility != Visibility.Visible) return; EditAreaCommitmentButton_Click(null, null); } private void EditAreaCommitmentButton_Click(object? sender, RoutedEventArgs? evt) { if (AreaCommitmentList.SelectedItem == null) return; IsEditing = true; AreaCommitmentList.IsEnabled = false; RevisionList.IsEnabled = false; HideNewEditDeleteButtons(); ShowSaveResetCancelButtons(); UnlockInputs(); LockSearchInputs(); } protected override void ShortcutDelete() { if (!DeleteAreaCommitmentButton.IsEnabled || DeleteAreaCommitmentButton.Visibility != Visibility.Visible) return; DeleteAreaCommitmentButton_Click(null, null); } private async void DeleteAreaCommitmentButton_Click(object? sender, RoutedEventArgs? evt) { if (RevisionList.SelectedItem is not AreaCom a) return; var d = new AreaComModifyDialog(a.YearFrom, a.YearTo, a.Area, true, RevisionList.ItemsSource.Cast().FirstOrDefault() != a); if (d.ShowDialog() != true) return; Mouse.OverrideCursor = Cursors.Wait; try { if (d.YearTo is int yearTo) { ViewModel.YearTo = yearTo; await ViewModel.UpdateAreaCommitment(a.FbNr, a.RevNr); } else { await AreaComService.DeleteAreaCom(a.FbNr); } App.HintContextChange(); } catch (Exception exc) { var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message; MessageBox.Show(str, "Flächenbindung löschen", MessageBoxButton.OK, MessageBoxImage.Error); } Mouse.OverrideCursor = null; } protected override void ShortcutSave() { if (!SaveButton.IsEnabled || SaveButton.Visibility != Visibility.Visible) return; SaveButton_Click(null, null); } private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) { SaveButton.IsEnabled = false; int? yearTo = null; if (InputHasChanged(AreaInput) || InputHasChanged(AreaComTypeInput) || InputHasChanged(MgNrInput)) { var a = (RevisionList.SelectedItem as AreaCom)!; var d = new AreaComModifyDialog(a.YearFrom, a.YearTo, a.Area, false, RevisionList.ItemsSource.Cast().FirstOrDefault() != a); if (d.ShowDialog() != true) { SaveButton.IsEnabled = true; return; } yearTo = d.YearTo; } int fbnr, revnr; Mouse.OverrideCursor = Cursors.Wait; try { AreaCom? temp = null; if (yearTo != null && (!ViewModel.YearTo.HasValue || yearTo < ViewModel.YearTo)) { temp = new AreaCom { MgNr = ViewModel.MgNr!.Value, YearFrom = ViewModel.YearFrom, YearTo = ViewModel.YearTo, VtrgId = ViewModel.AreaComType!.VtrgId, CultId = ViewModel.WineCult?.CultId, GstNr = ViewModel.GstNr?.Trim() ?? "-", Area = ViewModel.Area!.Value, }; RefreshInputs(); ViewModel.YearTo = yearTo; } (fbnr, revnr) = await ViewModel.UpdateAreaCommitment((AreaCommitmentList.SelectedItem as AreaComContract)?.FbNr, (RevisionList.SelectedItem as AreaCom)?.RevNr); if (temp is AreaCom t) { t.YearFrom = yearTo + 1; ViewModel.FillInputs(t); (fbnr, revnr) = await ViewModel.UpdateAreaCommitment((AreaCommitmentList.SelectedItem as AreaComContract)?.FbNr, null); } App.HintContextChange(); } catch (Exception exc) { var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message; MessageBox.Show(str, "Flächenbindung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error); SaveButton.IsEnabled = true; Mouse.OverrideCursor = null; return; } IsEditing = false; IsCreating = false; AreaCommitmentList.IsEnabled = true; RevisionList.IsEnabled = true; HideSaveResetCancelButtons(); ShowNewEditDeleteButtons(); LockInputs(); UnlockSearchInputs(); FinishInputFilling(); await EnsureContextRenewed(); Mouse.OverrideCursor = null; ViewModel.SearchQuery = ""; ViewModel.FilterSeason = ViewModel.YearTo ?? ViewModel.YearFrom ?? ViewModel.FilterSeason; ControlUtils.SelectItemWithPk(AreaCommitmentList, fbnr); ControlUtils.SelectItemWithPk(RevisionList, fbnr, revnr); } protected override void ShortcutReset() { if (!ResetButton.IsEnabled || ResetButton.Visibility != Visibility.Visible) return; ResetButton_Click(null, null); } private async void ResetButton_Click(object? sender, RoutedEventArgs? evt) { if (IsEditing) { RefreshInputs(); } else if (IsCreating) { await InitInputs(); } UpdateButtons(); } private void CancelButton_Click(object sender, RoutedEventArgs evt) { IsEditing = false; IsCreating = false; AreaCommitmentList.IsEnabled = true; RevisionList.IsEnabled = true; HideSaveResetCancelButtons(); ShowNewEditDeleteButtons(); RefreshInputs(); ClearInputStates(); LockInputs(); UnlockSearchInputs(); } override protected void UpdateButtons() { if (!IsEditing && !IsCreating) return; bool ch = HasChanged, v = IsValid; ResetButton.IsEnabled = (ch); SaveButton.IsEnabled = (ch && v); } private void DisableNewEditDeleteButtons() { NewAreaCommitmentButton.IsEnabled = false; EditAreaCommitmentButton.IsEnabled = false; DeleteAreaCommitmentButton.IsEnabled = false; } private void EnableNewEditDeleteButtons() { NewAreaCommitmentButton.IsEnabled = true; EditAreaCommitmentButton.IsEnabled = AreaCommitmentList.SelectedItem != null; DeleteAreaCommitmentButton.IsEnabled = AreaCommitmentList.SelectedItem != null; } private void ShowSaveResetCancelButtons() { SaveButton.IsEnabled = false; ResetButton.IsEnabled = false; CancelButton.IsEnabled = true; SaveButton.Visibility = Visibility.Visible; ResetButton.Visibility = Visibility.Visible; CancelButton.Visibility = Visibility.Visible; } private void HideSaveResetCancelButtons() { SaveButton.IsEnabled = false; ResetButton.IsEnabled = false; CancelButton.IsEnabled = false; SaveButton.Visibility = Visibility.Hidden; ResetButton.Visibility = Visibility.Hidden; CancelButton.Visibility = Visibility.Hidden; } private void ShowNewEditDeleteButtons() { EnableNewEditDeleteButtons(); NewAreaCommitmentButton.Visibility = Visibility.Visible; EditAreaCommitmentButton.Visibility = Visibility.Visible; DeleteAreaCommitmentButton.Visibility = Visibility.Visible; } private void HideNewEditDeleteButtons() { DisableNewEditDeleteButtons(); NewAreaCommitmentButton.Visibility = Visibility.Hidden; EditAreaCommitmentButton.Visibility = Visibility.Hidden; DeleteAreaCommitmentButton.Visibility = Visibility.Hidden; } private void LockSearchInputs() { SearchInput.IsEnabled = false; SeasonInput.IsEnabled = false; } private void UnlockSearchInputs() { SearchInput.IsEnabled = true; SeasonInput.IsEnabled = true; } private async void AreaCommitmentList_SelectionChanged(object sender, SelectionChangedEventArgs evt) { if (AreaCommitmentList.SelectedItem != null) AreaCommitmentList.ScrollIntoView(AreaCommitmentList.SelectedItem); await RefreshRevisions(); } private void RevisionList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) { RefreshInputs(); if (RevisionList.SelectedItem is AreaCom c) { EditAreaCommitmentButton.IsEnabled = true; } else { EditAreaCommitmentButton.IsEnabled = false; } } private void MgNrInput_TextChanged(object sender, TextChangedEventArgs evt) { var valid = InputTextChanged((TextBox)sender, Validator.CheckMgNr); var text = MgNrInput.Text; var caret = MgNrInput.CaretIndex; ControlUtils.SelectItemWithPk(MemberInput, valid ? ViewModel.MgNr : null); MgNrInput.Text = text; MgNrInput.CaretIndex = caret; } private void MgNrInput_LostFocus(object sender, RoutedEventArgs evt) { var valid = InputLostFocus((TextBox)sender, Validator.CheckMgNr); ControlUtils.SelectItemWithPk(MemberInput, valid ? ViewModel.MgNr : null); } private void MemberInput_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) { var m = MemberInput.SelectedItem as Member; ViewModel.MgNr = m?.MgNr; } private async void ActiveAreaCommitmentInput_Changed(object sender, RoutedEventArgs evt) { if (!HasContextLoaded) return; await RefreshList(); } private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) { if (!HasContextLoaded) return; var binding = ((TextBox)sender).GetBindingExpression(TextBox.TextProperty); binding?.UpdateSource(); await RefreshList(true); } private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) { if (!HasContextLoaded || ViewModel.FilterSeason == null) return; await RefreshList(); } private void KgInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) { if (KgInput.SelectedItem is AT_Kg kg) { var rdList = kg.WbKg!.Rds.OrderBy(r => r.Name).Cast().ToList(); rdList.Insert(0, new NullItem()); ControlUtils.RenewItemsSource(RdInput, rdList, null, ControlUtils.RenewSourceDefault.First); } else { var rdList = new object[] { new NullItem() }; ControlUtils.RenewItemsSource(RdInput, rdList, null, ControlUtils.RenewSourceDefault.First); } ComboBox_SelectionChanged(sender, evt); } private void KgDetailsButton_Click(object sender, RoutedEventArgs evt) { if (KgInput.SelectedItem is AT_Kg kg) { App.FocusOriginHierarchyKg(kg.KgNr); } else { App.FocusOriginHierarchy(); } } private void RdInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) { RdAddButton.IsEnabled = RdInput.SelectedIndex == -1; } private void RdAddButton_Click(object sender, RoutedEventArgs evt) { if (KgInput.SelectedItem is not AT_Kg kg) return; string name = RdInput.Text.Trim(); if (name.Length == 0) return; var s = RdInput.ItemsSource.Cast(); RdInput.ItemsSource = s.Append(new WbRd { KgNr = kg.KgNr, RdNr = 0, Name = name, }); RdInput.SelectedIndex = s.Count(); } protected void InputTextChanged(TextBox input, Func checker) { InputTextChanged(input, checker(input, SenderIsRequired(input), (AreaComContract)AreaCommitmentList.SelectedItem)); } protected void InputLostFocus(TextBox input, Func checker, string? msg = null) { InputLostFocus(input, checker(input, SenderIsRequired(input), (AreaComContract)AreaCommitmentList.SelectedItem), msg); } private void FbNrInput_TextChanged(object sender, RoutedEventArgs evt) { InputTextChanged((TextBox)sender, Validator.CheckFbNr); } private void FbNrInput_LostFocus(object sender, RoutedEventArgs evt) { InputLostFocus((TextBox)sender, Validator.CheckFbNr); } private void MemberReferenceButton_Click(object sender, RoutedEventArgs evt) { if (MemberInput.SelectedItem is not Member m) return; App.FocusMember(m.MgNr); } } }