// Copyright (c) 2022 - schick Informatik // bsmd.AIS2Service [AISZoneMonitor.cs]: %UserDisplayName% // Description: Background Thread Controller class for comparing AIS Targets // to monitor zones // using log4net; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Security.Policy; using System.Text; using System.Threading; using System.Threading.Tasks; namespace bsmd.AIS2Service { internal class AISZoneMonitor : IAISThread { #region Fields private readonly ConcurrentDictionary _sitRepDict; private readonly AIS_SQLiteStorage _storage; private Thread _thread; private bool _stopFlag = false; private static readonly ILog _log = LogManager.GetLogger(typeof(AISZoneMonitor)); #endregion #region Construction public AISZoneMonitor(ConcurrentDictionary sitRepDict, AIS_SQLiteStorage sqliteStorage) { _sitRepDict = sitRepDict; _storage = sqliteStorage; } #endregion #region private methods private void Monitor() { // load zones from storage List allZones = _storage.LoadMonitorZones(); Dictionary> testDict = new Dictionary>(); // letzte Alarme // Dictionary currentAlarms = _storage.LoadAlarms(); foreach(MonitorZone zone in allZones) { // load up Zone list for all assignment mmsi's (to check) foreach(MonitorAssignment ma in zone.Assignments) { if(!testDict.ContainsKey(ma.MMSI)) testDict[ma.MMSI] = new List(); ma.Alarms.AddRange(_storage.LoadAlarms(ma)); AlarmAssignmentZone aazone = new AlarmAssignmentZone(); aazone.Zone = zone; aazone.Assignment = ma; testDict[ma.MMSI].Add(aazone); } } // loop while(!_stopFlag) { // check all "current" AIS Targets against the zones foreach(int mmsi in _sitRepDict.Keys) { if(testDict.ContainsKey(mmsi)) { if (!_sitRepDict.ContainsKey(mmsi)) continue; AIS_Target target = _sitRepDict[mmsi]; foreach(AlarmAssignmentZone aazone in testDict[mmsi]) { if(aazone.Zone.IsPointInPolygon4(target.Position)) { _log.DebugFormat("{0} is in zone {1}", target.ToString(), aazone.Zone.Name); Alarm alarm; if (aazone.Assignment.Alarms.Count > 0) { alarm = aazone.Assignment.Alarms[0]; if(alarm.Timestamp_Last.HasValue && ((DateTime.Now - alarm.Timestamp_Last.Value).TotalMinutes > Properties.Settings.Default.MinAlarmIntervalMins)) { // this "old" alarm will be triggered again (overwritten) alarm.Acknowledged = null; alarm.Timestamp_Last = null; alarm.Timestamp_First = DateTime.Now; } else { // update the last time the target registered in the zone alarm.Timestamp_Last = DateTime.Now; } } else { // create new alarm alarm = new Alarm(-1, aazone.Assignment); alarm.Timestamp_First = DateTime.Now; alarm.ZoneMonitorType = aazone.Assignment.MonitorType; aazone.Assignment.Alarms.Add(alarm); } _storage.Save(alarm); } } } } int currentSaturationSecs = 0; // (DateTime.Now - alarm.FirstDetected).TotalSeconds; if(currentSaturationSecs > Properties.Settings.Default.MonitorTargetSaturationSecs) { // trigger alarm, this thing was "hot" long enough } Thread.Sleep(Properties.Settings.Default.MonitorTestIntervalSecs * 1000); } } #endregion #region IAISThread implementation public string Name { get { return "Zone monitor"; } } public event EventHandler FatalErrorOccurred; public void Start() { if (_thread != null) return; // may not run twice ThreadStart runReader = new ThreadStart(this.Monitor); _thread = new Thread(runReader); _thread.Start(); } public void Stop() { if (_thread == null) return; _stopFlag = true; _thread.Join(); _thread = null; } #endregion #region class AssignmentZoneAlarm composition private class AlarmAssignmentZone { public MonitorZone Zone { get; set; } public MonitorAssignment Assignment { get; set; } } #endregion } }