using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace wijmoSample1.Models.Maps
{
    public class MapsAction
    {
        public VectorLayerWijJsonData ReadKmzFile(Stream stream)
        {
            var responseData = new VectorLayerWijJsonData();
            var vectorItems = KmlReader.ReadVectorItems(stream);

            var countries = CreateCounties();

            foreach (var item in vectorItems)
            {
                var country = countries[item.Name];
                if (country != null)
                {
                    item.Fill = country.Fill == null ? "" : country.Fill == Color.Transparent ? "transparent" : string.Format("#{0}{1}{2}", country.Fill.R.ToString("X2"), country.Fill.G.ToString("X2"), country.Fill.B.ToString("X2")).ToLower();
                }
                else
                {
                    item.Fill = "transparent";
                }
                responseData.Vectors.Add(item);
            }
            return responseData;
        }

        private Countries CreateCounties()
        {
            var countries = new Countries();
            var pathGdp = HttpContext.Current.Server.MapPath("~/Content/Maps/data/gdp-ppp.txt");
            using (var stream = new FileStream(pathGdp, FileMode.Open, FileAccess.Read))
            {
                using (var sr = new StreamReader(stream))
                {
                    for (; !sr.EndOfStream; )
                    {
                        string s = sr.ReadLine();

                        if (s != null)
                        {
                            string[] ss = s.Split(new[] { '\t' },
                                StringSplitOptions.RemoveEmptyEntries);

                            countries.Add(new Country { Name = ss[1].Trim(), Value = double.Parse(ss[2], CultureInfo.InvariantCulture) });
                        }
                    }
                }
            }

            // create palette
            var cvals = new ColorValues
			{
				new ColorValue {Color = Color.FromArgb(255, 241, 244, 255), Value = 0},
				new ColorValue {Color = Color.FromArgb(255, 241, 244, 255), Value = 5000},
				new ColorValue {Color = Color.FromArgb(255, 224, 224, 246), Value = 10000},
				new ColorValue {Color = Color.FromArgb(255, 203, 205, 255), Value = 20000},
				new ColorValue {Color = Color.FromArgb(255, 179, 182, 230), Value = 50000},
				new ColorValue {Color = Color.FromArgb(255, 156, 160, 240), Value = 100000},
				new ColorValue {Color = Color.FromArgb(255, 127, 132, 243), Value = 200000},
				new ColorValue {Color = Color.FromArgb(255, 89, 97, 230), Value = 500000},
				new ColorValue {Color = Color.FromArgb(255, 56, 64, 217), Value = 1000000},
				new ColorValue {Color = Color.FromArgb(255, 19, 26, 148), Value = 2000000},
				new ColorValue {Color = Color.FromArgb(255, 0, 3, 74), Value = 1.001*countries.GetMax()}
			};

            countries.Converter = cvals;

            return countries;
        }
    }

    public interface IValueToColor
    {
        Color ValueToColor(double value);
    }

    public class Country
    {
        private Color _fill = Color.Empty;
        private double _value;
        internal Countries Parent;

        public string Name { get; set; }

        public double Value
        {
            get { return _value; }
            set
            {
                _value = value;
                _fill = Color.Empty;
            }
        }

        public Color Fill
        {
            get
            {
                if (_fill == Color.Empty)
                {
                    if (Parent != null)
                        _fill = Parent.ValueToColor(Value);
                }

                return _fill;
            }
        }
    }

    public class Countries : Collection<Country>, IValueToColor
    {
        private readonly Dictionary<string, Country> _dict = new Dictionary<string, Country>();

        public IValueToColor Converter { get; set; }

        public Color ValueToColor(double value)
        {
            if (Converter != null)
                return Converter.ValueToColor(value);

            return Color.Empty;
        }

        public Country this[string name]
        {
            get
            {
                if (_dict.ContainsKey(name))
                    return _dict[name];
                return null;
            }
        }

        public double GetMin()
        {
            double min = double.NaN;

            foreach (Country country in this)
            {
                if (double.IsNaN(min) || country.Value < min)
                    min = country.Value;
            }

            return min;
        }

        public double GetMax()
        {
            double max = double.NaN;

            foreach (Country country in this)
            {
                if (double.IsNaN(max) || country.Value > max)
                    max = country.Value;
            }

            return max;
        }

        protected override void InsertItem(int index, Country item)
        {
            base.InsertItem(index, item);
            item.Parent = this;
            _dict.Add(item.Name, item);
        }

        protected override void ClearItems()
        {
            foreach (Country item in this)
                item.Parent = null;

            base.ClearItems();
            _dict.Clear();
        }

        protected override void RemoveItem(int index)
        {
            Country item = this[index];
            base.RemoveItem(index);

            _dict.Remove(item.Name);
            item.Parent = null;
        }
    }

    public class ColorValue
    {
        public Color Color { get; set; }
        public double Value { get; set; }
    }

    public class ColorValues : Collection<ColorValue>, IValueToColor
    {
        public Color ValueToColor(double value)
        {
            Color color = Color.Empty;

            ColorValue greater = null;
            ColorValue less = null;

            foreach (ColorValue cval in this)
            {
                if (cval.Value < value)
                {
                    if (less == null || (value - cval.Value < value - less.Value))
                        less = cval;
                }
                if (cval.Value > value)
                {
                    if (greater == null || (value - cval.Value > value - greater.Value))
                        greater = cval;
                }
            }

            if (less != null && greater != null)
            {
                Color clr1 = less.Color;
                Color clr2 = greater.Color;

                double rval = (value - less.Value) / (greater.Value - less.Value);

                color = Color.FromArgb(
                    (byte)(clr1.A + rval * (clr2.A - clr1.A)),
                    (byte)(clr1.R + rval * (clr2.R - clr1.R)),
                    (byte)(clr1.G + rval * (clr2.G - clr1.G)),
                    (byte)(clr1.B + rval * (clr2.B - clr1.B)));
            }

            return color;
        }
    }
}
