git_bsmd/AIS/bsmd.AIS2Service/AISZoneMonitor.cs

162 lines
5.8 KiB
C#

// 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<int, AIS_Target> _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<int, AIS_Target> sitRepDict, AIS_SQLiteStorage sqliteStorage)
{
_sitRepDict = sitRepDict;
_storage = sqliteStorage;
}
#endregion
#region private methods
private void Monitor()
{
// load zones from storage
List<MonitorZone> allZones = _storage.LoadMonitorZones();
Dictionary<int, List<AlarmAssignmentZone>> testDict = new Dictionary<int, List<AlarmAssignmentZone>>();
// letzte Alarme
// Dictionary<int, Alarm> 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<AlarmAssignmentZone>();
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
}
}