using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using C1.Web.Wijmo.Controls.C1Maps;
using System.Collections.ObjectModel;
using System.Drawing;
namespace ControlExplorer.C1Maps
{
    public partial class MapChart : System.Web.UI.Page
	{
		protected void Page_Load(object sender, EventArgs e)
		{
			if (!IsPostBack)
			{
				var layer = new C1VectorLayer();
				C1Maps1.Layers.Add(layer);

				layer.DataType = DataType.WijJson;

				var data = new WijJsonData();
				layer.DataWijJson = data;

				var path = Server.MapPath("Resources/WorldMap.kmz");
				using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
				{
					var items = KmlReader.ReadVectorItems(stream);
					var countries = CreateCounties();

					foreach (var item in items)
					{
						var country = countries[item.Name];
						if (country != null)
						{
							item.Fill = country.Fill;
						}
						else
						{
							item.Fill = Color.Transparent;
						}

						data.Vectors.Add(item);
					}
				}
			}
		}

		private Countries CreateCounties()
		{
			var countries = new Countries();
			var pathGdp = Server.MapPath("Resources/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;
		}
	}
}