|  | @@ -6,7 +6,6 @@ using System.Linq.Expressions;
 | 
	
		
			
				|  |  |  using System.Windows;
 | 
	
		
			
				|  |  |  using System.Windows.Controls;
 | 
	
		
			
				|  |  |  using System.Windows.Input;
 | 
	
		
			
				|  |  | -using System.Windows.Media;
 | 
	
		
			
				|  |  |  using Comal.Classes;
 | 
	
		
			
				|  |  |  using Comal.Stores;
 | 
	
		
			
				|  |  |  using InABox.Clients;
 | 
	
	
		
			
				|  | @@ -15,74 +14,11 @@ using InABox.Core;
 | 
	
		
			
				|  |  |  using InABox.Wpf;
 | 
	
		
			
				|  |  |  using Syncfusion.UI.Xaml.Maps;
 | 
	
		
			
				|  |  |  using System.ComponentModel;
 | 
	
		
			
				|  |  | +using System.Drawing;
 | 
	
		
			
				|  |  | +using Point = System.Windows.Point;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace PRSDesktop
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    public class MapMarker
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        public Guid ID { get; set; }
 | 
	
		
			
				|  |  | -        public string Latitude { get; set; }
 | 
	
		
			
				|  |  | -        public string Longitude { get; set; }
 | 
	
		
			
				|  |  | -        public string Code { get; set; }
 | 
	
		
			
				|  |  | -        public string Description { get; set; }
 | 
	
		
			
				|  |  | -        public DateTime Updated { get; set; }
 | 
	
		
			
				|  |  | -        public string UpdatedBy { get; set; }
 | 
	
		
			
				|  |  | -        public string DeviceID { get; set; }
 | 
	
		
			
				|  |  | -        public Brush Background { get; internal set; }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    public class ViewModel
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        private readonly List<MapMarker> _markers = new();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        private MapMarker _selected;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        public ViewModel()
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            Markers = new ObservableCollection<MapMarker>();
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        public ObservableCollection<MapMarker> Markers { get; }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        public MapMarker Selected
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            get => _selected;
 | 
	
		
			
				|  |  | -            set
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                _selected = value;
 | 
	
		
			
				|  |  | -                Refresh();
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        public void Add(MapMarker marker, bool refresh = false)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            _markers.Add(marker);
 | 
	
		
			
				|  |  | -            if (refresh)
 | 
	
		
			
				|  |  | -                Refresh();
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        public void Clear()
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            _selected = null;
 | 
	
		
			
				|  |  | -            _markers.Clear();
 | 
	
		
			
				|  |  | -            Refresh();
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        public void Refresh()
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            Markers.Clear();
 | 
	
		
			
				|  |  | -            foreach (var marker in _markers)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                marker.Background = new SolidColorBrush(marker == _selected ? Colors.Yellow : Colors.Orange);
 | 
	
		
			
				|  |  | -                if (marker != _selected)
 | 
	
		
			
				|  |  | -                    Markers.Add(marker);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            if (_selected != null)
 | 
	
		
			
				|  |  | -                Markers.Add(_selected);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      public class ImageryLayerExt : ImageryLayer
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          protected override string GetUri(int X, int Y, int Scale)
 | 
	
	
		
			
				|  | @@ -108,14 +44,12 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |          private LiveMapsSettings _settings;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private bool bFirst = true;
 | 
	
		
			
				|  |  | -        private readonly ViewModel viewmodel = new();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private readonly int ZOOMEDIN = 16;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public MapsPanel()
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              InitializeComponent();
 | 
	
		
			
				|  |  | -            DataContext = viewmodel;
 | 
	
		
			
				|  |  |              //ausgov.Uri = "c:\\development\\maps\\MB_2011_WA.shp";
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -355,7 +289,7 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private void LoadDayMarkers()
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            viewmodel.Markers.Clear();
 | 
	
		
			
				|  |  | +            ViewModel.Markers.Clear();
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private void LoadMarkers<T>(Filter<T> filter, Expression<Func<T, object>> guid, Expression<Func<T, object>> code,
 | 
	
	
		
			
				|  | @@ -363,7 +297,7 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |              Expression<Func<T, object>> longitude, Expression<Func<T, object>> updatedby, Expression<Func<T, object>> timestamp, bool first = true)
 | 
	
		
			
				|  |  |              where T : Entity, IRemotable, IPersistent, new()
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            viewmodel.Clear();
 | 
	
		
			
				|  |  | +            ViewModel.Clear();
 | 
	
		
			
				|  |  |              var columns = new Columns<T>(guid, code, description, latitude, longitude, timestamp, updatedby);
 | 
	
		
			
				|  |  |              if (deviceid != null && !columns.ColumnNames().Contains(CoreUtils.GetFullPropertyName(deviceid, ".")))
 | 
	
		
			
				|  |  |                  columns.Add(deviceid);
 | 
	
	
		
			
				|  | @@ -376,7 +310,7 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  |                      Dispatcher.Invoke(() =>
 | 
	
		
			
				|  |  |                      {
 | 
	
		
			
				|  |  | -                        viewmodel.Markers.Clear();
 | 
	
		
			
				|  |  | +                        ViewModel.Markers.Clear();
 | 
	
		
			
				|  |  |                          if (error != null)
 | 
	
		
			
				|  |  |                          {
 | 
	
		
			
				|  |  |                              MessageBox.Show(error.Message);
 | 
	
	
		
			
				|  | @@ -401,11 +335,11 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |                              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                              foreach (var key in values.Keys)
 | 
	
		
			
				|  |  | -                                viewmodel.Add(
 | 
	
		
			
				|  |  | +                                ViewModel.AddMarker(
 | 
	
		
			
				|  |  |                                      new MapMarker
 | 
	
		
			
				|  |  |                                      {
 | 
	
		
			
				|  |  |                                          ID = key,
 | 
	
		
			
				|  |  | -                                        Code = values[key].Code,
 | 
	
		
			
				|  |  | +                                        Label = values[key].Code,
 | 
	
		
			
				|  |  |                                          Latitude = string.Format("{0:F6}", values[key].Latitude),
 | 
	
		
			
				|  |  |                                          Longitude = string.Format("{0:F6}", values[key].Longitude),
 | 
	
		
			
				|  |  |                                          Description = values[key].Description,
 | 
	
	
		
			
				|  | @@ -414,7 +348,7 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |                                          DeviceID = values[key].DeviceID
 | 
	
		
			
				|  |  |                                      }
 | 
	
		
			
				|  |  |                                  );
 | 
	
		
			
				|  |  | -                            viewmodel.Refresh();
 | 
	
		
			
				|  |  | +                            ViewModel.Refresh();
 | 
	
		
			
				|  |  |                          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                          //if (bFirst)
 | 
	
	
		
			
				|  | @@ -434,7 +368,7 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |              var seLon = double.MinValue;
 | 
	
		
			
				|  |  |              var seLat = double.MaxValue;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            foreach (var marker in viewmodel.Markers)
 | 
	
		
			
				|  |  | +            foreach (var marker in ViewModel.Markers)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  var lat = double.Parse(marker.Latitude);
 | 
	
		
			
				|  |  |                  var lon = double.Parse(marker.Longitude);
 | 
	
	
		
			
				|  | @@ -570,12 +504,17 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |                  return;
 | 
	
		
			
				|  |  |              LoadDeviceHistory(marker.DeviceID);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        private class WayPoint
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            public PointF Location { get; set; }
 | 
	
		
			
				|  |  | +            public DateTime From { get; set; }
 | 
	
		
			
				|  |  | +            public DateTime To { get; set; }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private void LoadDeviceHistory(string deviceID)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            History.ItemsSource = null;
 | 
	
		
			
				|  |  | -            var movements = new ObservableCollection<GPSHistory>();
 | 
	
		
			
				|  |  | -            History.ItemsSource = movements;
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  |              new Client<GPSTrackerLocation>().Query(
 | 
	
		
			
				|  |  |                  new Filter<GPSTrackerLocation>(x => x.DeviceID).IsEqualTo(deviceID)
 | 
	
		
			
				|  |  |                      .And(x => x.Location.Timestamp).IsGreaterThanOrEqualTo(Date.Date.Date)
 | 
	
	
		
			
				|  | @@ -584,6 +523,8 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |                  new SortOrder<GPSTrackerLocation>(x => x.Location.Timestamp, SortDirection.Descending),
 | 
	
		
			
				|  |  |                  (table, error) =>
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | +                    
 | 
	
		
			
				|  |  | +                    var movements = new ObservableCollection<GPSHistory>();
 | 
	
		
			
				|  |  |                      if (table != null)
 | 
	
		
			
				|  |  |                      {
 | 
	
		
			
				|  |  |                          var updates = new List<GPSTrackerLocation>();
 | 
	
	
		
			
				|  | @@ -638,11 +579,49 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |                                  Latitude = 0.0F,
 | 
	
		
			
				|  |  |                                  Longitude = 0.0F
 | 
	
		
			
				|  |  |                              };
 | 
	
		
			
				|  |  | -                            Dispatcher.Invoke(() => { movements.Add(history); });
 | 
	
		
			
				|  |  | +                             movements.Add(history);
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    
 | 
	
		
			
				|  |  | +                    List<WayPoint> waypoints = new List<WayPoint>();
 | 
	
		
			
				|  |  | +                    WayPoint? previous = null;
 | 
	
		
			
				|  |  | +                    foreach (var movement in movements.OrderBy(x=>x.Date))
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        var current = new PointF((float)movement.Longitude, (float)movement.Latitude);
 | 
	
		
			
				|  |  | +                        
 | 
	
		
			
				|  |  | +                        if (previous == null || Location.DistanceBetween(previous.Location, current, UnitOfLength.Kilometers) >= 0.05)
 | 
	
		
			
				|  |  | +                        {
 | 
	
		
			
				|  |  | +                            previous = new WayPoint()
 | 
	
		
			
				|  |  | +                            {
 | 
	
		
			
				|  |  | +                                Location = new PointF((float)movement.Longitude, (float)movement.Latitude),
 | 
	
		
			
				|  |  | +                                From = movement.Date,
 | 
	
		
			
				|  |  | +                                To = movement.Date
 | 
	
		
			
				|  |  | +                            };
 | 
	
		
			
				|  |  | +                            waypoints.Add(previous);
 | 
	
		
			
				|  |  |                          }
 | 
	
		
			
				|  |  | +                        else
 | 
	
		
			
				|  |  | +                            previous.To = movement.Date;
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    Dispatcher.BeginInvoke(() =>
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        foreach (var waypoint in waypoints.Where(x=>x.To - x.From >= TimeSpan.FromMinutes(15)))
 | 
	
		
			
				|  |  | +                        {
 | 
	
		
			
				|  |  | +                            ViewModel.AddWayPoint(new MapMarker()
 | 
	
		
			
				|  |  | +                            {
 | 
	
		
			
				|  |  | +                                Label = $"{waypoint.From:h:mm}-{waypoint.To:h:mm}",
 | 
	
		
			
				|  |  | +                                Latitude = string.Format("{0:F6}", waypoint.Location.Y),
 | 
	
		
			
				|  |  | +                                Longitude = string.Format("{0:F6}", waypoint.Location.X),
 | 
	
		
			
				|  |  | +                            });
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                        ViewModel.Refresh();
 | 
	
		
			
				|  |  | +                        History.ItemsSource = null;
 | 
	
		
			
				|  |  | +                        History.ItemsSource = movements;
 | 
	
		
			
				|  |  | +                    });
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              );
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private bool Moved(List<CoreRow> rows, int row1, int row2)
 | 
	
	
		
			
				|  | @@ -716,12 +695,12 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |              //timer.Tick += ((t,e) => 
 | 
	
		
			
				|  |  |              //{
 | 
	
		
			
				|  |  |              //timer.IsEnabled = false;
 | 
	
		
			
				|  |  | -            viewmodel.Refresh();
 | 
	
		
			
				|  |  | +            ViewModel.Refresh();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              var layer = Map.Layers[0] as ImageryLayer;
 | 
	
		
			
				|  |  |              var nw = layer.GetLatLonFromPoint(new Point(0F, 0F));
 | 
	
		
			
				|  |  |              var se = layer.GetLatLonFromPoint(new Point(Map.ActualWidth, Map.ActualHeight));
 | 
	
		
			
				|  |  | -            var markers = viewmodel.Markers.Where(marker => ShowAll.IsChecked == true ? true : IsMarkerVisible(marker, nw, se))
 | 
	
		
			
				|  |  | +            var markers = ViewModel.Markers.Where(marker => ShowAll.IsChecked == true ? true : IsMarkerVisible(marker, nw, se))
 | 
	
		
			
				|  |  |                  .OrderBy(x => x.Description);
 | 
	
		
			
				|  |  |              Markers.ItemsSource = markers.ToArray();
 | 
	
		
			
				|  |  |              //});
 | 
	
	
		
			
				|  | @@ -741,6 +720,9 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private void ZoomToMarker(MapMarker marker)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | +            if (marker == null)
 | 
	
		
			
				|  |  | +                return;
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  |              if (double.Parse(marker.Latitude) != 0.0F && double.Parse(marker.Longitude) != 0.0F)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  var layer = Map.Layers[0] as ImageryLayer;
 | 
	
	
		
			
				|  | @@ -752,7 +734,7 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |          private void Markers_SelectionChanged(object sender, SelectionChangedEventArgs e)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              var marker = Markers.SelectedItem as MapMarker;
 | 
	
		
			
				|  |  | -            viewmodel.Selected = Markers.SelectedItem as MapMarker;
 | 
	
		
			
				|  |  | +            ViewModel.Selected = Markers.SelectedItem as MapMarker;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              if (marker != null)
 | 
	
		
			
				|  |  |              {
 | 
	
	
		
			
				|  | @@ -820,7 +802,7 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |                  cur.Center = center;
 | 
	
		
			
				|  |  |                  cur.Radius = radius;
 | 
	
		
			
				|  |  |                  cur.MarkerTemplate = template;
 | 
	
		
			
				|  |  | -                cur.Markers = viewmodel.Markers;
 | 
	
		
			
				|  |  | +                cur.Markers = ViewModel.Markers;
 | 
	
		
			
				|  |  |                  cur.BingMapKey = "5kn7uPPBBGKdmWYiwHJL~LjUY7IIgFzGdXpkpWT7Fsw~AmlksNuYOBHNQ3cOa61Nz2ghvK5EbrBZ3aQqvTS4OjcPxTBGNGsj2hKc058CgtgJ";
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -882,5 +864,15 @@ namespace PRSDesktop
 | 
	
		
			
				|  |  |              public string UpdatedBy { get; }
 | 
	
		
			
				|  |  |              public string DeviceID { get; }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private void TabView_PageChanged(object sender, SelectionChangedEventArgs e)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            ViewModel.View = TabView.SelectedIndex == 0
 | 
	
		
			
				|  |  | +                ? MapViewType.Current
 | 
	
		
			
				|  |  | +                : MapViewType.History;
 | 
	
		
			
				|  |  | +            // ImageryLayer.MarkerTemplate = TabView.SelectedIndex == 0
 | 
	
		
			
				|  |  | +            //     ? TryFindResource("MapMarkerTemplate") as DataTemplate
 | 
	
		
			
				|  |  | +            //     : TryFindResource("MapWayPointTemplate") as DataTemplate;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |