using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;

namespace MapComparison
{
    /// <summary>
    /// Class that contains our data.
    /// </summary>
    public class DataModel
    {
        PagedCollectionView _view;
        bool _showNatural = true;
        bool _showManMade = true;

        public DataModel()
        {
            // create some data
            var list = new ObservableCollection<Landmark>();
            list.Add(new Landmark("Eiffel Tower", 48.8583, 2.2943, true));
            list.Add(new Landmark("Big Ben", 51.5008, -0.1246, true));
            list.Add(new Landmark("Disney World", 28.3741, -81.5495, true));
            list.Add(new Landmark("Sydney Opera House", -33.8572, 151.2152, true));
            list.Add(new Landmark("Cristo Redentor", -22.9519, -43.2105, true));
            list.Add(new Landmark("Taj Mahal", 27.1728, 78.0417, true));
            list.Add(new Landmark("Statue of Liberty", 40.6891, -74.0447, true));
            list.Add(new Landmark("Golden Gate", 37.8071, -122.4757, true));
            list.Add(new Landmark("Panama Canal", 9.0097, -79.6032, true));
            list.Add(new Landmark("Niagara Falls", 43.0962, -79.0377, false));
            list.Add(new Landmark("Foz do Iguacu", -25.5469, -54.5882, false));
            list.Add(new Landmark("Koh Phi Phi", 7.7435, 98.7757, false));

            // create a lot more data
            if (false)
            {
                double cx = 40;
                double cy = -74;
                for (int i = 0; i < 100; i++)
                {
                    var x = cx + Noise();
                    var y = cy + Noise();
                    list.Add(new Landmark(string.Format("LM{0}", i), x, y, false));
                }
            }

            // create a CollectionView
            _view = new PagedCollectionView(list);

            // hook up the filter
            _view.Filter = v =>
            {
                var landmark = v as Landmark;
                return landmark.ManMade ? ShowManMade : ShowNatural;
            };
        }
        Random _rnd = new Random();
        double Noise()
        {
            var d = 0.0;
            for (int i = 0; i < 5; i++)
            {
                d += (_rnd.NextDouble() - 0.5) * 4;
            }
            return d;
        }
        public ICollectionView Landmarks
        {
            get { return _view; }
        }
        public bool ShowNatural
        {
            get { return _showNatural; }
            set
            {
                _showNatural = value;
                UpdateFilter();
            }
        }
        public bool ShowManMade
        {
            get { return _showManMade; }
            set
            {
                _showManMade = value;
                UpdateFilter();
            }
        }
        void UpdateFilter()
        {
            _view.Refresh();
        }
    }
    /// <summary>
    /// Represents a well-know location on the map, defined by a name, latitude, and longitude.
    /// </summary>
    public class Landmark : INotifyPropertyChanged
    {
        //---------------------------------------------------------------------------------
        #region ** ctor

        public Landmark(string name, double latitude, double longitude, bool manMade)
        {
            Name = name;
            Latitude = latitude;
            Longitude = longitude;
            ManMade = manMade;
        }

        #endregion

        //---------------------------------------------------------------------------------
        #region ** object model

        public string Name 
        { 
            get { return (string)GetValue("Name", null); }
            set { SetValue("Name", value); }
        }
        public double Latitude 
        { 
            get { return (double)GetValue("Latitude", 0); }
            set { SetValue("Latitude", value); }
        }
        public double Longitude
        { 
            get { return (double)GetValue("Longitude", 0); }
            set { SetValue("Longitude", value); }
        }
        public bool ManMade
        {
            get { return (bool)GetValue("ManMade", true); }
            set { SetValue("ManMade", value); }
        }
        public Point LongLat { get { return new Point(Longitude, Latitude); } }
        public override string ToString()
        {
            return Name;
        }
        public string DisplayName
        {
            get
            {
                var name = Name.ToUpper();
                if (ManMade)
                {
                    name = "the " + name;
                }
                return name;
            }
        }

        #endregion

        //---------------------------------------------------------------------------------
        #region ** INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, e);
        }

        #endregion

        //---------------------------------------------------------------------------------
        #region ** implementation

        Dictionary<string, object> _dct = new Dictionary<string, object>();
        object GetValue(string key, object defVal)
        {
            object value;
            return _dct.TryGetValue(key, out value) ? value : defVal;
        }
        void SetValue(string key, object value)
        {
            if (!object.Equals(GetValue(key, null), value))
            {
                _dct[key] = value;
                OnPropertyChanged(new PropertyChangedEventArgs(key));
            }
        }
        #endregion
    }
}
