using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using Microsoft.Research.DynamicDataDisplay.DataSources;
using Microsoft.Research.DynamicDataDisplay.PointMarkers;
using Microsoft.Research.DynamicDataDisplay.Common;
using System.Windows.Controls;

namespace Microsoft.Research.DynamicDataDisplay
{
    public class ElementMarkerPointsGraph : PointsGraphBase
    {
        /// <summary>List with created but unused markers</summary>
        private readonly List<UIElement> unused = new List<UIElement>();

        /// <summary>Initializes a new instance of the <see cref="MarkerPointsGraph"/> class.</summary>
        public ElementMarkerPointsGraph()
        {
            ManualTranslate = true; // We'll handle translation by ourselves
        }

        /// <summary>Initializes a new instance of the <see cref="MarkerPointsGraph"/> class.</summary>
        /// <param name="dataSource">The data source.</param>
        public ElementMarkerPointsGraph(IPointDataSource dataSource)
            : this()
        {
            DataSource = dataSource;
        }

        Grid grid;
        Canvas canvas;

        protected override void OnPlotterAttached(Plotter plotter)
        {
            base.OnPlotterAttached(plotter);

            grid = new Grid();
            canvas = new Canvas { ClipToBounds = true };
            grid.Children.Add(canvas);

            Plotter2D.CentralGrid.Children.Add(grid);
        }

        protected override void OnPlotterDetaching(Plotter plotter)
        {
            Plotter2D.CentralGrid.Children.Remove(grid);
            grid = null;
            canvas = null;

            base.OnPlotterDetaching(plotter);
        }

        protected override void OnDataChanged()
        {
            //			if (canvas != null)
            //			{
            //                foreach(UIElement child in canvas.Children)
            //                    unused.Add(child);
            //				canvas.Children.Clear();
            //			}
            // todo почему так?
            base.OnDataChanged();
        }

        public ElementPointMarker Marker
        {
            get { return (ElementPointMarker)GetValue(MarkerProperty); }
            set { SetValue(MarkerProperty, value); }
        }

        public static readonly DependencyProperty MarkerProperty =
            DependencyProperty.Register(
              "Marker",
              typeof(ElementPointMarker),
              typeof(ElementMarkerPointsGraph),
              new FrameworkPropertyMetadata { DefaultValue = null, AffectsRender = true }
                  );

        protected override void OnRenderCore(DrawingContext dc, RenderState state)
        {
            if (Marker == null)
                return;

            if (DataSource == null) // No data is specified
            {
                if (canvas != null)
                {
                    foreach (UIElement child in canvas.Children)
                        unused.Add(child);
                    canvas.Children.Clear();
                }
            }
            else // There is some data
            {
          
                int index = 0;
                var transform = GetTransform();
                using (IPointEnumerator enumerator = DataSource.GetEnumerator(GetContext()))
                {
                    Point point = new Point();

					DataRect bounds = DataRect.Empty;

                    while (enumerator.MoveNext())
                    {
                        enumerator.GetCurrent(ref point);
                        enumerator.ApplyMappings(Marker);

                        if (index >= canvas.Children.Count)
                        {
                            UIElement newMarker;
                            if (unused.Count > 0)
                            {
                                newMarker = unused[unused.Count - 1];
                                unused.RemoveAt(unused.Count - 1);
                            }
                            else
                                newMarker = Marker.CreateMarker();
                            canvas.Children.Add(newMarker);
                        }

                        Marker.SetMarkerProperties(canvas.Children[index]);
						bounds.Union(point);
                        Point screenPoint = point.DataToScreen(transform);
                        Marker.SetPosition(canvas.Children[index], screenPoint);
                        index++;
                    }

					Viewport2D.SetContentBounds(this, bounds);

                    while (index < canvas.Children.Count)
                    {
                        unused.Add(canvas.Children[index]);
                        canvas.Children.RemoveAt(index);
                    }
                }
            }
        }
    }
}