|  | @@ -0,0 +1,270 @@
 | 
	
		
			
				|  |  | +using System;
 | 
	
		
			
				|  |  | +using InABox.Core;
 | 
	
		
			
				|  |  | +using Syncfusion.Windows.Shared;
 | 
	
		
			
				|  |  | +using System.Collections.Generic;
 | 
	
		
			
				|  |  | +using System.Linq;
 | 
	
		
			
				|  |  | +using System.Threading.Tasks;
 | 
	
		
			
				|  |  | +using System.Windows;
 | 
	
		
			
				|  |  | +using System.Windows.Controls;
 | 
	
		
			
				|  |  | +using System.Windows.Media;
 | 
	
		
			
				|  |  | +using Geocoding;
 | 
	
		
			
				|  |  | +using Geocoding.Google;
 | 
	
		
			
				|  |  | +using InABox.Wpf;
 | 
	
		
			
				|  |  | +using InABox.WPF;
 | 
	
		
			
				|  |  | +using InABox.Wpf.DynamicGrid;
 | 
	
		
			
				|  |  | +using Address = InABox.Core.Address;
 | 
	
		
			
				|  |  | +using Location = InABox.Core.Location;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +namespace InABox.DynamicGrid;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +public class AddressEditorControl : DynamicEnclosedEditorControl<Address, AddressEditor>
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private Grid Grid = null!; // Late-initialized in CreateEditor
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    private TextBox StreetBox = null!; // Late-initialized in CreateEditor
 | 
	
		
			
				|  |  | +    private TextBox CityBox = null!; // Late-initialized in CreateEditor
 | 
	
		
			
				|  |  | +    private TextBox StateBox = null!; // Late-initialized in CreateEditor
 | 
	
		
			
				|  |  | +    private TextBox PostcodeBox = null!; // Late-initialized in CreateEditor
 | 
	
		
			
				|  |  | +    private Button MapButton = null!; // Late-initialized in CreateEditor
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    public override int DesiredHeight()
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        return int.MaxValue;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public override int DesiredWidth()
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        return int.MaxValue;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public override void SetColor(Color color)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        StreetBox.Background = new SolidColorBrush(color);
 | 
	
		
			
				|  |  | +        CityBox.Background = new SolidColorBrush(color);
 | 
	
		
			
				|  |  | +        StateBox.Background = new SolidColorBrush(color);
 | 
	
		
			
				|  |  | +        PostcodeBox.Background = new SolidColorBrush(color);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public override void SetFocus()
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        StreetBox.Focus();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public override void Configure()
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    protected override FrameworkElement CreateEditor()
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        Grid = new Grid
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            VerticalAlignment = VerticalAlignment.Stretch,
 | 
	
		
			
				|  |  | +            HorizontalAlignment = HorizontalAlignment.Stretch
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +        Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
 | 
	
		
			
				|  |  | +        Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
 | 
	
		
			
				|  |  | +        Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
 | 
	
		
			
				|  |  | +        Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        Grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
 | 
	
		
			
				|  |  | +        Grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        StreetBox = CreateBox(0, 0, 4, 0, 0.0, 0.0, nameof(Address.Street), "Street");
 | 
	
		
			
				|  |  | +        CityBox = CreateBox(1, 0, 1, 0, 0.0, 5.0, nameof(Address.City),"City");
 | 
	
		
			
				|  |  | +        StateBox = CreateBox(1, 1, 1, 150, 5.0, 5.0, nameof(Address.State),"State");
 | 
	
		
			
				|  |  | +        PostcodeBox = CreateBox(1,2,1,80, 5.0, 5.0, nameof(Address.PostCode),"Postcode");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        MapButton = new Button();
 | 
	
		
			
				|  |  | +        MapButton.SetValue(Grid.RowProperty,1);
 | 
	
		
			
				|  |  | +        MapButton.SetValue(Grid.ColumnProperty,3);
 | 
	
		
			
				|  |  | +        MapButton.Width = 25.0;
 | 
	
		
			
				|  |  | +        MapButton.Margin = new Thickness(5.0, 5.0, 0.0, 0.0);
 | 
	
		
			
				|  |  | +        MapButton.BorderThickness = new Thickness(0.75);
 | 
	
		
			
				|  |  | +        MapButton.Background = Brushes.Transparent;
 | 
	
		
			
				|  |  | +        MapButton.Content = new Image() { Source = InABox.Wpf.Resources.map.AsBitmapImage() };
 | 
	
		
			
				|  |  | +        MapButton.Click += (sender, args) => ShowMap();
 | 
	
		
			
				|  |  | +        MapButton.Visibility = !string.IsNullOrWhiteSpace(CoreUtils.GoogleAPIKey) && EditorDefinition.ShowMapButton 
 | 
	
		
			
				|  |  | +            ? Visibility.Visible 
 | 
	
		
			
				|  |  | +            : Visibility.Collapsed;
 | 
	
		
			
				|  |  | +        Grid.Children.Add(MapButton);
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        return Grid;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private void ShowMap()
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        var values = new Dictionary<string,object?>(GetChildValues());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        var address = new Address();
 | 
	
		
			
				|  |  | +        if (values.TryGetValue(nameof(Address.Street), out var street)) 
 | 
	
		
			
				|  |  | +            address.Street = street?.ToString() ?? "";
 | 
	
		
			
				|  |  | +        if (values.TryGetValue(nameof(Address.City), out var city)) 
 | 
	
		
			
				|  |  | +            address.City = city?.ToString() ?? "";
 | 
	
		
			
				|  |  | +        if (values.TryGetValue(nameof(Address.State), out var state)) 
 | 
	
		
			
				|  |  | +            address.State = state?.ToString() ?? "";
 | 
	
		
			
				|  |  | +        if (values.TryGetValue(nameof(Address.PostCode), out var postcode)) 
 | 
	
		
			
				|  |  | +            address.PostCode = postcode?.ToString() ?? "";
 | 
	
		
			
				|  |  | +        if (values.TryGetValue(nameof(Address.Geofence), out var geofence)) 
 | 
	
		
			
				|  |  | +            address.Geofence = geofence?.ToString() ?? "";
 | 
	
		
			
				|  |  | +        if (values.TryGetValue($"{nameof(Address.Location)}.{nameof(Address.Location.Latitude)}", out var latitude)) 
 | 
	
		
			
				|  |  | +            address.Location.Latitude = latitude != null ? (double)latitude : 0.0;
 | 
	
		
			
				|  |  | +        if (values.TryGetValue($"{nameof(Address.Location)}.{nameof(Address.Location.Longitude)}", out var longitude)) 
 | 
	
		
			
				|  |  | +            address.Location.Longitude = longitude != null ? (double)longitude : 0.0;
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        var map = new GeofenceEditor(address, true);
 | 
	
		
			
				|  |  | +        map.ShowDialog();
 | 
	
		
			
				|  |  | +        _latitude = address.Location.Latitude;
 | 
	
		
			
				|  |  | +        _longitude = address.Location.Longitude;
 | 
	
		
			
				|  |  | +        _geofence = address.Geofence;
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        CheckChanged($"{nameof(Address.Location)}.{nameof(Address.Location.Latitude)}");
 | 
	
		
			
				|  |  | +        CheckChanged($"{nameof(Address.Location)}.{nameof(Address.Location.Longitude)}");
 | 
	
		
			
				|  |  | +        CheckChanged(nameof(Address.Geofence));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private TextBox CreateBox(int row, int col, int colspan, double minWidth, double leftpad, double toppad, string property, string watermark)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        var box = new TextBox();
 | 
	
		
			
				|  |  | +        box.SetValue(Grid.RowProperty,row);
 | 
	
		
			
				|  |  | +        box.SetValue(Grid.ColumnProperty,col);
 | 
	
		
			
				|  |  | +        box.SetValue(Grid.ColumnSpanProperty,Math.Max(1,colspan));
 | 
	
		
			
				|  |  | +        box.MinWidth = minWidth;
 | 
	
		
			
				|  |  | +        box.Margin = new Thickness(leftpad, toppad, 0, 0);
 | 
	
		
			
				|  |  | +        box.TextChanged += AddressChanged;
 | 
	
		
			
				|  |  | +        box.LostFocus += CheckChanged;
 | 
	
		
			
				|  |  | +        box.Tag = property;
 | 
	
		
			
				|  |  | +        TextBoxUtils.SetPlaceholder(box, watermark);
 | 
	
		
			
				|  |  | +        Grid.Children.Add(box);
 | 
	
		
			
				|  |  | +        return box;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private bool _dirty = false;
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    private void CheckChanged(object sender, RoutedEventArgs e)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        if (sender is not TextBox box)
 | 
	
		
			
				|  |  | +            return;
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        CheckChanged((box.Tag as string)!);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (_dirty)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            _latitude = 0.0;
 | 
	
		
			
				|  |  | +            _longitude = 0.0;
 | 
	
		
			
				|  |  | +            _geofence = "";
 | 
	
		
			
				|  |  | +            CheckChanged($"{nameof(Address.Location)}.{nameof(Address.Location.Latitude)}");
 | 
	
		
			
				|  |  | +            CheckChanged($"{nameof(Address.Location)}.{nameof(Address.Location.Longitude)}");
 | 
	
		
			
				|  |  | +            CheckChanged($"{nameof(Address.Geofence)}");
 | 
	
		
			
				|  |  | +            _dirty = false;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        MapButton.Background = string.IsNullOrWhiteSpace(_geofence) ? Brushes.Red : Brushes.LightGreen;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // CoreUtils.GoogleAPIKey = "AIzaSyAVReknl_sP2VLz5SUD8R-sZh1KDVCcWis";
 | 
	
		
			
				|  |  | +        // IGeocoder geocoder = new GoogleGeocoder(CoreUtils.GoogleAPIKey);
 | 
	
		
			
				|  |  | +        // var address = geocoder.GeocodeAsync($"{StreetBox.Text}, {CityBox.Text} {StateBox.Text} {PostcodeBox.Text} Australia").Result.FirstOrDefault();
 | 
	
		
			
				|  |  | +        // if (address != null)
 | 
	
		
			
				|  |  | +        // {
 | 
	
		
			
				|  |  | +        //     var latOffset = new GeoPoint(address.Coordinates.Latitude, address.Coordinates.Longitude).DistanceTo(new GeoPoint(_latitude, address.Coordinates.Longitude));
 | 
	
		
			
				|  |  | +        //     if (address.Coordinates.Latitude < _latitude)
 | 
	
		
			
				|  |  | +        //         latOffset *= -1.0;
 | 
	
		
			
				|  |  | +        //     
 | 
	
		
			
				|  |  | +        //     var longOffset = new GeoPoint(address.Coordinates.Latitude, address.Coordinates.Longitude).DistanceTo(new GeoPoint(address.Coordinates.Latitude, _longitude));
 | 
	
		
			
				|  |  | +        //     if (address.Coordinates.Longitude < _longitude)
 | 
	
		
			
				|  |  | +        //         longOffset *= -1.0;
 | 
	
		
			
				|  |  | +        //     
 | 
	
		
			
				|  |  | +        //     var fence = Serialization.Deserialize<GeoFence>(_geofence) ?? new GeoFence();
 | 
	
		
			
				|  |  | +        //     List<GeoPoint> newPoints = new List<GeoPoint>();
 | 
	
		
			
				|  |  | +        //     foreach (var coord in fence.Coordinates)
 | 
	
		
			
				|  |  | +        //         newPoints.Add(coord.Move(longOffset * 1000.0, latOffset * 1000.0));
 | 
	
		
			
				|  |  | +        //     fence.Coordinates.Clear();
 | 
	
		
			
				|  |  | +        //     fence.Coordinates.AddRange(newPoints);
 | 
	
		
			
				|  |  | +                
 | 
	
		
			
				|  |  | +        //         _latitude = address.Coordinates.Latitude;
 | 
	
		
			
				|  |  | +        //         _longitude = address.Coordinates.Longitude;
 | 
	
		
			
				|  |  | +        //         _geofence = Serialization.Serialize(fence);
 | 
	
		
			
				|  |  | +        //     }
 | 
	
		
			
				|  |  | +        //     else
 | 
	
		
			
				|  |  | +        //     {
 | 
	
		
			
				|  |  | +        //         _latitude = 0.0;
 | 
	
		
			
				|  |  | +        //         _longitude = 0.0;
 | 
	
		
			
				|  |  | +        //         _geofence = "";
 | 
	
		
			
				|  |  | +        //     }
 | 
	
		
			
				|  |  | +        //
 | 
	
		
			
				|  |  | +        // }
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private void AddressChanged(object sender, TextChangedEventArgs e)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        _dirty = true;
 | 
	
		
			
				|  |  | +        // Set Latitude and Longitude to Zero
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public override void SetEnabled(bool enabled)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        StreetBox.IsEnabled = enabled;
 | 
	
		
			
				|  |  | +        CityBox.IsEnabled = enabled;
 | 
	
		
			
				|  |  | +        StateBox.IsEnabled = enabled;
 | 
	
		
			
				|  |  | +        PostcodeBox.IsEnabled = enabled;
 | 
	
		
			
				|  |  | +        base.SetEnabled(enabled);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    protected override object? GetChildValue(string property)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        if (string.Equals(property,nameof(Address.Street))) 
 | 
	
		
			
				|  |  | +            return StreetBox.Text;
 | 
	
		
			
				|  |  | +        if (string.Equals(property,nameof(Address.City))) 
 | 
	
		
			
				|  |  | +            return CityBox.Text;
 | 
	
		
			
				|  |  | +        if (string.Equals(property,nameof(Address.State))) 
 | 
	
		
			
				|  |  | +            return StateBox.Text;
 | 
	
		
			
				|  |  | +        if (string.Equals(property,nameof(Address.PostCode))) 
 | 
	
		
			
				|  |  | +            return PostcodeBox.Text;
 | 
	
		
			
				|  |  | +        if (string.Equals(property, $"{nameof(Address.Location)}.{nameof(Address.Location.Latitude)}"))
 | 
	
		
			
				|  |  | +            return _latitude;
 | 
	
		
			
				|  |  | +        if (string.Equals(property, $"{nameof(Address.Location)}.{nameof(Address.Location.Longitude)}"))
 | 
	
		
			
				|  |  | +            return _longitude;
 | 
	
		
			
				|  |  | +        if (string.Equals(property,nameof(Address.Geofence))) 
 | 
	
		
			
				|  |  | +            return _geofence;
 | 
	
		
			
				|  |  | +        return null;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    protected override IEnumerable<KeyValuePair<string, object?>> GetChildValues()
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        yield return new(nameof(Address.Street), StreetBox.Text);
 | 
	
		
			
				|  |  | +        yield return new(nameof(Address.City), CityBox.Text);
 | 
	
		
			
				|  |  | +        yield return new(nameof(Address.State), StateBox.Text);
 | 
	
		
			
				|  |  | +        yield return new(nameof(Address.PostCode), PostcodeBox.Text);
 | 
	
		
			
				|  |  | +        yield return new($"{nameof(Address.Location)}.{nameof(Address.Location.Latitude)}", _latitude);
 | 
	
		
			
				|  |  | +        yield return new($"{nameof(Address.Location)}.{nameof(Address.Location.Longitude)}", _longitude);
 | 
	
		
			
				|  |  | +        yield return new(nameof(Address.Geofence), _geofence);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private double _latitude = 0.0;
 | 
	
		
			
				|  |  | +    private double _longitude = 0.0;
 | 
	
		
			
				|  |  | +    private String _geofence = "";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    protected override void SetChildValue(string property, object? value)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        if (string.Equals(property,nameof(Address.Street))) 
 | 
	
		
			
				|  |  | +            StreetBox.Text = value?.ToString() ?? "";
 | 
	
		
			
				|  |  | +        if (string.Equals(property,nameof(Address.City))) 
 | 
	
		
			
				|  |  | +            CityBox.Text = value?.ToString() ?? "";
 | 
	
		
			
				|  |  | +        if (string.Equals(property,nameof(Address.State))) 
 | 
	
		
			
				|  |  | +            StateBox.Text = value?.ToString() ?? "";
 | 
	
		
			
				|  |  | +        if (string.Equals(property,nameof(Address.PostCode))) 
 | 
	
		
			
				|  |  | +            PostcodeBox.Text = value?.ToString() ?? "";
 | 
	
		
			
				|  |  | +        if (string.Equals(property, $"{nameof(Address.Location)}.{nameof(Address.Location.Latitude)}"))
 | 
	
		
			
				|  |  | +            _latitude = (double?)value ?? 0.0;
 | 
	
		
			
				|  |  | +        if (string.Equals(property, $"{nameof(Address.Location)}.{nameof(Address.Location.Longitude)}"))
 | 
	
		
			
				|  |  | +            _longitude = (double?)value ?? 0.0;
 | 
	
		
			
				|  |  | +        if (string.Equals(property, nameof(Address.Geofence)))
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            _geofence = value?.ToString() ?? "";
 | 
	
		
			
				|  |  | +            MapButton.Background = string.IsNullOrWhiteSpace(_geofence) ? Brushes.Red : Brushes.LightGreen;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 |