context: // Copyright 2005, 2006 - Morten Nielsen (www.iter.dk)
  //
  // This file is part of SharpMap.
  // Mapsui is free software; you can redistribute it and/or modify
  // it under the terms of the GNU Lesser General Public License as published by
  // the Free Software Foundation; either version 2 of the License, or
  // (at your option) any later version.
  // 
  // SharpMap is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  // GNU Lesser General Public License for more details.
  
  // You should have received a copy of the GNU Lesser General Public License
  // along with SharpMap; if not, write to the Free Software
  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  
  using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Linq;
  using Mapsui.Fetcher;
  using Mapsui.Geometries;
  using Mapsui.Layers;
  using Mapsui.Projection;
  using Mapsui.Styles;
  using Mapsui.UI;
  using Mapsui.Widgets;
  
  namespace Mapsui
  {
      /// <summary>
      /// Map class
      /// </summary>
      /// <remarks>
      /// Map holds all map related infos like transformation, layers, widgets and so on.
      /// </remarks>
      public class Map : INotifyPropertyChanged
      {
          private LayerCollection _layers = new LayerCollection();
          private Color _backColor = Color.White;
  
          /// <summary>
          /// Initializes a new map
          /// </summary>
          public Map()
          {
              BackColor = Color.White;
              Layers = new LayerCollection();
          }
  
          /// <summary>
          /// List of Widgets belonging to map
          /// </summary>
          public List<IWidget> Widgets { get; } = new List<IWidget>();
  
          /// <summary>
          /// Pan mode to use, when map is paned
          /// </summary>
          public PanMode PanMode { get; set; } = PanMode.KeepCenterWithinExtents;
  
          /// <summary>
          /// Zoom mode to use, when map is zoomed
          /// </summary>
          public ZoomMode ZoomMode { get; set; } = ZoomMode.KeepWithinResolutions;
  
          /// <summary>
          /// Set this property in combination KeepCenterWithinExtents or KeepViewportWithinExtents.
          /// If PanLimits is not set, Map.Extent will be used as restricted extent.
          /// </summary>
          public BoundingBox PanLimits { get; set; }
  
          /// <summary>
          /// Pair of the limits for the resolutions (smallest and biggest). If ZoomMode is set 
          /// to anything else than None, resolution is kept between these values.
          /// </summary>
          public MinMax ZoomLimits { get; set; }
  
          /// <summary>
          /// Projection type of Map. Normally in format like "EPSG:3857"
          /// </summary>
          public string CRS { get; set; }
  
          /// <summary>
          /// Transformation to use for the different coordinate systems
          /// </summary>
          public ITransformation Transformation { get; set; }
  
          /// <summary>
          /// A collection of layers. The first layer in the list is drawn first, the last one on top.
          /// </summary>
          public LayerCollection Layers
          {
              get => _layers;
              private set
              {
                  var tempLayers = _layers;
                  if (tempLayers != null)
                  {
                      _layers.LayerAdded -= LayersLayerAdded;
                      _layers.LayerRemoved -= LayersLayerRemoved;
                  }
                  _layers = value;
                  _layers.LayerAdded += LayersLayerAdded;
                  _layers.LayerRemoved += LayersLayerRemoved;
              }
          }
  
          [Obsolete("Use ILayer.IsMapInfoLayer instead", true)]
          public IList<ILayer> InfoLayers { get; } = new List<ILayer>();
  
          [Obsolete("Use your own hover event and call MapControl.GetMapInfo", true)]
          public IList<ILayer> HoverLayers { get; } = new List<ILayer>();
  
          /// <summary>
          /// Map background color (defaults to transparent)
          ///  </summary>
          public Color BackColor
          {
              get => _backColor;
              set
              {
                  if (_backColor == value) return;
                  _backColor = value;
                  OnPropertyChanged(nameof(BackColor));
              }
          }
  
          /// <summary>
          /// Gets the extents of the map based on the extents of all the layers in the layers collection
          /// </summary>
          /// <returns>Full map extents</returns>
          public BoundingBox Envelope
          {
              get
              {
                  if (_layers.Count == 0) return null;
  
                  BoundingBox bbox = null;
                  foreach (var layer in _layers)
                  {
                      bbox = bbox == null ? layer.Envelope : bbox.Join(layer.Envelope);
                  }
                  return bbox;
              }
          }
  
          /// <summary>
          /// List of all native resolutions of this map
          /// </summary>
          public IReadOnlyList<double> Resolutions { get; private set; }
  
          /// <summary>
          /// Called whenever a property changed
          /// </summary>
          public event PropertyChangedEventHandler PropertyChanged;
  
          /// <summary>
          /// DataChanged should be triggered by any data changes of any of the child layers
          /// </summary>
          public event DataChangedEventHandler DataChanged;
  
  #pragma warning disable 67
          [Obsolete("Use PropertyChanged instead", true)]
          public event EventHandler RefreshGraphics;
  #pragma warning restore 67
  
          [Obsolete("Use MapControl.Info instead", true)]
  #pragma warning disable 67
          public event EventHandler<MapInfoEventArgs> Info;
  #pragma warning restore 67
  
          [Obsolete("Use your own hover event instead and call MapControl.GetMapInfo", true)]
  #pragma warning disable 67
          public event EventHandler<MapInfoEventArgs> Hover;
  #pragma warning restore 67
          
          /// <summary>
          /// Abort fetching of all layers
          /// </summary>
          public void AbortFetch()
          {
              foreach (var layer in _layers.ToList())
              {
                  layer.AbortFetch();
              }
          }
  
          /// <summary>
          /// Clear cache of all layers
          /// </summary>
          public void ClearCache()
          {
              foreach (var layer in _layers)
              {
                  layer.ClearCache();
              }
          }
  
          public void RefreshData(BoundingBox extent, double resolution, bool majorChange)
          {
              foreach (var layer in _layers.ToList())
              {
                  layer.RefreshData(extent, resolution, majorChange);
              }
          }
  
          private void LayersLayerAdded(ILayer layer)
          {
              layer.DataChanged += LayerDataChanged;
              layer.PropertyChanged += LayerPropertyChanged;
  
              layer.Transformation = Transformation;
              layer.CRS = CRS;
              Resolutions = DetermineResolutions(Layers);
              OnPropertyChanged(nameof(Layers));
          }
  
          private void LayersLayerRemoved(ILayer layer)
          {
              layer.AbortFetch();
  
              layer.DataChanged -= LayerDataChanged;
              layer.PropertyChanged -= LayerPropertyChanged;
  
  
gt:             Resolutions = DetermineResolutions(Layers);