// Copyright (C) Stichting Deltares 2021. All rights reserved. // // This file is part of the application DAM - UI. // // DAM - UI is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // All names, logos, and references to "Deltares" are registered trademarks of // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. using System; using System.Collections.Generic; using System.Drawing; using System.Xml.Serialization; using Deltares.Dam.Data; using Deltares.Standard; using Deltares.Standard.Attributes; using Deltares.Standard.EventPublisher; namespace Deltares.Dam.Forms { [Impact(Impact.None)] public class LocationJobSymbol : Symbol, IVisibleEnabled { private readonly Func bad = (f) => f <= 1.0 && f > 0; private readonly Func warning = (f) => f > 1.0 && f <= 1.05; private readonly Func good = (f) => f > 1.05 && f < 1.17; private readonly Func excellent = (f) => f >= 1.17 && f < DamGlobalConstants.NoRunValue; private readonly Func failed = (f) => double.IsNaN(f) || f <= 0; private readonly Func notCalculated = (f) => f >= DamGlobalConstants.NoRunValue; private int currentView = 0; private DateTime currentDateTime = DateTime.Today; private DateTime minDateTime = DateTime.Today; private DateTime maxDateTime = DateTime.Today; private string currentProfileName; private string currentScenarioName; private string currentCalculation; private DamProjectData damProjectData = null; private LocationJob currentLocationJob = null; public LocationJobSymbol() { RegisterColorAndLabel("f >= 1.17", Color.Lime, this.excellent); RegisterColorAndLabel("1.05 < f < 1.17", Color.Yellow, this.good); RegisterColorAndLabel("1.0 < f <= 1.05", Color.Orange, this.warning); RegisterColorAndLabel("f <= 1.0", Color.Red, this.bad); RegisterColorAndLabel("failed calculation", Color.White, this.failed); RegisterColorAndLabel("not yet calculated", Color.Gray, this.notCalculated); DataEventPublisher.OnAfterChange += DataEventPublisher_OnAfterChange; } private void DataEventPublisher_OnAfterChange(object sender, PublishEventArgs e) { if (sender == this.damProjectData) { DataEventPublisher.AfterChange(this); } } public LocationJob CurrentLocationJob { get { return currentLocationJob; } } public Image GetSymbol(object data, bool selected) { var locationJob = data as LocationJob; currentLocationJob = locationJob; if (locationJob != null) { var damProjectType = this.damProjectData.DamProjectType; if (damProjectType == DamProjectType.Calamity) { if (!locationJob.HasLocationResults) return GetImage(GetColor(DamGlobalConstants.NoRunValue), selected); DateTime dateTime = this.CurrentDateTime; TimeSerie timeSerie = locationJob.LocationResult.StabilityTimeSerie; double value = timeSerie.GetValue(dateTime); return GetImage(GetColor(value), selected); } } return GetImage(Color.Black, selected); } [XmlIgnore] public string CurrentProfileName { get { return this.currentProfileName; } set { DataEventPublisher.BeforeChange(this, "CurrentProfileName"); this.currentProfileName = value; LocationJob.CurrentProfileName = value; DataEventPublisher.DataListModified(this.DamProjectData.LocationJobs); DataEventPublisher.AfterChange(this, "CurrentProfileName"); } } [XmlIgnore] public string CurrentScenarioName { get { return this.currentScenarioName; } set { DataEventPublisher.BeforeChange(this, "CurrentScenarioName"); this.currentScenarioName = value; LocationJob.CurrentScenarioName = value; DataEventPublisher.DataListModified(this.DamProjectData.LocationJobs); DataEventPublisher.AfterChange(this, "CurrentScenarioName"); } } [XmlIgnore] public string CurrentCalculation { get { return this.currentCalculation; } set { DataEventPublisher.BeforeChange(this, "CurrentCalculation"); this.currentCalculation = value; LocationJob.CurrentCalculation = value; DataEventPublisher.DataListModified(this.DamProjectData.LocationJobs); DataEventPublisher.AfterChange(this, "CurrentCalculation"); } } [XmlIgnore] public DateTime CurrentDateTime { get { return currentDateTime; } set { DataEventPublisher.BeforeChange(this, "CurrentDateTime"); this.currentDateTime = value; this.UpdateView(); LocationJob.CurrentTime = value; DataEventPublisher.DataListModified(this.DamProjectData.LocationJobs); DataEventPublisher.AfterChange(this, "CurrentDateTime"); } } [XmlIgnore] public int CurrentView { get { return currentView; } set { DataEventPublisher.BeforeChange(this, "CurrentView"); currentView = value; this.UpdateCurrentDateTime(); DataEventPublisher.AfterChange(this, "CurrentView"); } } public DamProjectData DamProjectData { get { return damProjectData; } set { damProjectData = value; DataEventPublisher.AfterChange(this, "DamProjectData"); } } private void UpdateCurrentDateTime() { TimeSpan span = maxDateTime - minDateTime; if (span.TotalSeconds >= 0) { CurrentDateTime = minDateTime.AddSeconds(this.currentView * span.TotalSeconds / 100); } } private void UpdateView() { TimeSpan span = maxDateTime - minDateTime; TimeSpan spanUntilView = currentDateTime - minDateTime; if (span.TotalSeconds == 0) { this.currentView = 0; } else { this.currentView = Convert.ToInt32(100 * spanUntilView.TotalSeconds / span.TotalSeconds); this.currentView = Math.Max(0, this.currentView); this.currentView = Math.Min(100, this.currentView); } } public void Update(IEnumerable locationJobs) { this.minDateTime = DateTime.MaxValue; this.maxDateTime = DateTime.MinValue; //Todo Why is this timeserie part of ..Symbol and not part of LocationJob itself foreach (LocationJob locationJob in locationJobs) { if (locationJob.LocationResult != null) { foreach (TimeSerieEntry entry in locationJob.LocationResult.StabilityTimeSerie.Entries) { if (entry.DateTime < minDateTime) { minDateTime = entry.DateTime; } if (entry.DateTime > maxDateTime) { maxDateTime = entry.DateTime; } } if (locationJob.LocationResult.StabilityTimeSerie.Entries.Count == 0 && locationJob.WaterLevelTimeSerie != null) { foreach (TimeSerieEntry entry in locationJob.WaterLevelTimeSerie.Entries) { if (entry.DateTime < minDateTime) { minDateTime = entry.DateTime; } if (entry.DateTime > maxDateTime) { maxDateTime = entry.DateTime; } } } } } this.UpdateCurrentDateTime(); } #region IVisibleEnabled Members public bool IsVisible(string property) { if (this.damProjectData != null) { switch (property) { case "CurrentView": case "CurrentDateTime": return this.DamProjectData.DamProjectType == DamProjectType.Calamity; case "CurrentProfileName": return false; case "CurrentScenarioName": return false; case "CurrentCalculation": return false; default: return true; } } return true; } public bool IsEnabled(string property) { if (this.damProjectData != null) { switch (property) { case "CurrentView": case "CurrentDateTime": return this.DamProjectData != null && this.DamProjectData.DamProjectType == DamProjectType.Calamity && this.DamProjectData.LocationJobs != null && this.DamProjectData.LocationJobs.Count > 0; case "CurrentProfileName": return false; case "CurrentScenarioName": return false; case "CurrentCalculation": return false; default: return true; } } return true; } #endregion } }