using C1.Xaml.Maps;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Xml.Serialization;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Reflection;
using Windows.Storage;
using System.Threading.Tasks;

// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236

namespace ControlExplorer.Controls.Maps
{
    public sealed partial class Factories
        : UserControl, IExposeApplicationBarItems
    {
        const double minStoreZoom = 10.5;
        DataBase dataBase;
        
        public Factories()
        {
            this.InitializeComponent();

            this.Loaded += Factories_Loaded;
        }

        async void Factories_Loaded(object sender, RoutedEventArgs e)
        {
            await LoadDataBase();
            InitializeMapLayers();
        }

        async Task LoadDataBase()
        {
            var resource = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Resources/Maps/database.xml"));
            using (Stream stream = await resource.OpenStreamForReadAsync())
            {
                if (stream != null)
                {
                    var serializer = new XmlSerializer(typeof(DataBase));
                    dataBase = (DataBase)serializer.Deserialize(stream);
                }
                else
                {
                    dataBase = new DataBase();
                }
            }
        }

        void InitializeMapLayers()
        {
            maps.Layers.Add(new C1MapItemsLayer
            {
                ItemsSource = dataBase.Factories,
                ItemTemplate = (DataTemplate)Resources["factoryTemplate"]
            });

            maps.Layers.Add(new C1MapItemsLayer
            {
                ItemsSource = dataBase.Offices,
                ItemTemplate = (DataTemplate)Resources["officeTemplate"]
            });

            int storeSlices = (int)Math.Pow(2, minStoreZoom);
            maps.Layers.Add(new C1MapVirtualLayer
            {
                Slices =
                    {
                        new MapSlice(1, 1, 0),
                        new MapSlice(storeSlices, storeSlices, minStoreZoom)
                    },
                MapItemsSource = new LocalStroeSource(dataBase),
                ItemTemplate = (DataTemplate)Resources["storeTemplate"]
            });
        }

        #region IExposeApplicationBarItems Members

        public IEnumerable<ICommandBarElement> ApplicationBarItems
        {
            get
            {
                yield break;
            }
        }

        #endregion

        public class LocalStroeSource : IMapVirtualSource
        {
            DataBase _dataBase;

            public LocalStroeSource(DataBase localDataBase)
            {
                _dataBase = localDataBase;
            }


            public void Request(double minZoom, double maxZoom, Point lowerLeft, Point upperRight, Action<System.Collections.ICollection> callback)
            {
                if (minZoom < minStoreZoom)
                {
                    return;
                }

                var stores = new List<Store>();

                foreach (var store in _dataBase.Stores)
                {
                    if (store.Latitude > lowerLeft.Y
                        && store.Longitude > lowerLeft.X
                        && store.Latitude <= upperRight.Y
                        && store.Longitude <= upperRight.X)
                    {
                        stores.Add(store);
                    }
                }

                callback(stores);
            }
        }
    }


    public class Entity
    {
        public string Name { get; set; }
        public double Latitude { get; set; }
        public double Longitude { get; set; }
        public Point Position { get { return new Point(Longitude, Latitude); } }
    }

    public class Office : Entity
    {
        public string Manager { get; set; }
        public int Stores { get; set; }
    }

    public class Factory : Entity
    {
        public double Capacity { get; set; }
    }

    public class Product
    {
        public string Name { get; set; }
    }
    public class ProductSale
    {
        public Product Product { get; set; }
        public int Sales { get; set; }
    }
    public class Store : Entity
    {
        public List<ProductSale> Sales { get; set; }
    }

    public class DataBase
    {
        public List<Factory> Factories { get; set; }
        public List<Office> Offices { get; set; }
        public List<Store> Stores { get; set; }
        public double OfficeStoreDistance { get; set; }

        public DataBase()
        {
            Factories = new List<Factory>();
            Offices = new List<Office>();
            Stores = new List<Store>();
            OfficeStoreDistance = 100000;
        }

    }
}
