using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using Comal.Classes; using InABox.Core; using InABox.Database; namespace Comal.Stores { public class GPSTrackerLocationStore : BaseStore { private static ConcurrentDictionary _cache; private static ConcurrentBag> _addresses; public override void Init() { Logger.Send(LogType.Information, "", "Initializing GPS Tracker Caches"); _addresses = new ConcurrentBag>( Provider.Query( new Filter(x => x.Location.Address).IsNotEqualTo(""), new Columns( x => x.Location.Address, x => x.Location.Longitude, x => x.Location.Latitude ), null, int.MaxValue, true, true ).Rows.Select(r => new Tuple( r.Get(c => c.Location.Latitude), r.Get(c => c.Location.Longitude), r.Get(c => c.Location.Address) ) )); _cache = new ConcurrentDictionary( Provider.Query( new Filter(x => x.DeviceID).IsNotEqualTo(Guid.Empty), new Columns(x => x.DeviceID).Add(x => x.ID) ).Rows.Select(r => new KeyValuePair(r.Get(c => c.DeviceID), r.Get(c => c.ID))) ); } public string ReverseGeocode(double latitude, double longitude) { var tuple = _addresses.FirstOrDefault(x => Equals(x.Item1, latitude) && Equals(x.Item2, longitude)); if (tuple == null) { var address = StoreUtils.ReverseGeocode(latitude, longitude); if (!string.IsNullOrWhiteSpace(address)) { tuple = new Tuple(latitude, longitude, address); _addresses.Add(tuple); } } return tuple != null ? tuple.Item3 : ""; } protected override void BeforeSave(GPSTrackerLocation entity) { base.BeforeSave(entity); if (Equals(entity.Tracker.ID, Guid.Empty)) { if (!_cache.ContainsKey(entity.DeviceID)) { Logger.Send(LogType.Information, "", string.Format("- Tracker Cache Update Required: {0}", entity.DeviceID)); var row = Provider.Query( new Filter(x => x.DeviceID).IsEqualTo(entity.DeviceID), new Columns(x => x.ID) ).Rows.FirstOrDefault(); if (row != null) { entity.Tracker.ID = row.Get(x => x.ID); _cache[entity.DeviceID] = entity.Tracker.ID; Logger.Send(LogType.Information, "", string.Format("- Adding Tracker to Cache: {0} => {1}", entity.DeviceID, entity.Tracker.ID)); } } else { entity.Tracker.ID = _cache[entity.DeviceID]; } } if (!Equals(entity.Tracker.ID, Guid.Empty) && string.IsNullOrWhiteSpace(entity.Location.Address) && !Equals(entity.Location.Latitude, 0.0D) && !Equals(entity.Location.Longitude, 0.0D) ) entity.Location.Address = ReverseGeocode(entity.Location.Latitude, entity.Location.Longitude); } private void UpdateTrackers(IEnumerable entities, ref string auditnote) { var updates = new List(); foreach (var entity in entities) { if (entity.Tracker.IsValid()) { var tracker = new GPSTracker(); tracker.ID = entity.Tracker.ID; tracker.Location.Longitude = entity.Location.Longitude; tracker.Location.Latitude = entity.Location.Latitude; tracker.Location.Timestamp = entity.Location.Timestamp; tracker.Location.Address = entity.Location.Address; tracker.BatteryLevel = entity.BatteryLevel; tracker.Hours = entity.Hours; tracker.Distance = entity.Distance; tracker.Counter1 = entity.Counter1; tracker.Counter2 = entity.Counter2; tracker.Counter3 = entity.Counter3; tracker.Counter4 = entity.Counter4; updates.Add(tracker); } else { Logger.Send(LogType.Error, "", string.Format("Skipping GPS Tracker Update (Cache Size={0})", _cache.Count)); } } if (updates.Any()) { Provider.Save(updates); AuditTrail(updates, new[] { auditnote }); } auditnote = null; } protected override void OnSave(IEnumerable entities, ref string auditnote) { var updates = entities.Where(x => !Equals(x.Tracker.ID, Guid.Empty)).ToArray(); if (updates.Any()) { UpdateTrackers(updates, ref auditnote); base.OnSave(updates, ref auditnote); } } protected override void OnSave(GPSTrackerLocation entity, ref string auditnote) { if (Equals(entity.Tracker.ID, Guid.Empty)) return; UpdateTrackers(new[] { entity }, ref auditnote); base.OnSave(entity, ref auditnote); } } }