using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner.ViewModels;
using AIStudio.Wpf.DiagramDesigner.ViewModels.BaseViewModel;

namespace AIStudio.Wpf.DiagramDesigner
{
    public class RubberbandAdorner : Adorner
    {
        private Point? startPoint;
        private Point? endPoint;
        private List<Point> pointList = new List<Point>();
        private Pen rubberbandPen;

        private DesignerCanvas _designerCanvas;

        private IDiagramViewModel _viewModel
        {
            get
            {
                return _designerCanvas.DataContext as IDiagramViewModel;
            }
        }
        private IDiagramServiceProvider _service
        {
            get
            {
                return DiagramServicesProvider.Instance.Provider;
            }
        }

        public RubberbandAdorner(DesignerCanvas designerCanvas, Point? dragStartPoint)
            : base(designerCanvas)
        {
            this._designerCanvas = designerCanvas;
            this._designerCanvas.Focus();
            this.startPoint = dragStartPoint;
            rubberbandPen = new Pen(Brushes.LightSlateGray, 1);

            rubberbandPen.DashStyle = new DashStyle(new double[] { 2 }, 1);
        }

        protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                if (!this.IsMouseCaptured)
                    this.CaptureMouse();

                endPoint = e.GetPosition(this);

                UpdateSelection();
                this.InvalidateVisual();
            }
            else
            {
                if (this.IsMouseCaptured) this.ReleaseMouseCapture();
            }

            e.Handled = true;
        }

        protected override void OnMouseUp(System.Windows.Input.MouseButtonEventArgs e)
        {
            // release mouse capture
            if (this.IsMouseCaptured) this.ReleaseMouseCapture();

            // remove this adorner from adorner layer
            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this._designerCanvas);
            if (adornerLayer != null)
                adornerLayer.Remove(this);

            if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Text)
            {
                if (this.startPoint.HasValue && this.endPoint.HasValue)
                {
                    if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Text)
                    {
                        TextDesignerItemViewModel itemBase = new TextDesignerItemViewModel();
                        Point position = e.GetPosition(this);
                        itemBase.Left = Math.Min(this.startPoint.Value.X, this.endPoint.Value.X);
                        itemBase.Top = Math.Min(this.startPoint.Value.Y, this.endPoint.Value.Y);
                        itemBase.ItemWidth = Math.Abs(this.endPoint.Value.X - this.startPoint.Value.X);
                        itemBase.ItemHeight = Math.Abs(this.endPoint.Value.Y - this.startPoint.Value.Y);

                        _viewModel.AddCommand.Execute(itemBase);
                    }
                }
                this._service.DrawModeViewModel.ResetDrawMode();
            }

            e.Handled = true;
        }

        protected override void OnRender(DrawingContext dc)
        {
            base.OnRender(dc);

            // without a background the OnMouseMove event would not be fired !
            // Alternative: implement a CanvasBrush as a child of this adorner, like
            // the ConnectionAdorner does.
            dc.DrawRectangle(Brushes.Transparent, null, new Rect(RenderSize));

            if (this.startPoint.HasValue && this.endPoint.HasValue)
            {
                dc.DrawRectangle(Brushes.Transparent, rubberbandPen, new Rect(this.startPoint.Value, this.endPoint.Value));
            }
        }


        private T GetParent<T>(Type parentType, DependencyObject dependencyObject) where T : DependencyObject
        {
            DependencyObject parent = VisualTreeHelper.GetParent(dependencyObject);
            if (parent.GetType() == parentType)
                return (T)parent;

            return GetParent<T>(parentType, parent);
        }

        private void UpdateSelection()
        {
            IDiagramViewModel vm = (_designerCanvas.DataContext as IDiagramViewModel);
            Rect rubberBand = new Rect(startPoint.Value, endPoint.Value);
            ItemsControl itemsControl = GetParent<ItemsControl>(typeof(ItemsControl), _designerCanvas);

            foreach (SelectableDesignerItemViewModelBase item in vm.Items.ToList())
            {
                if (item is SelectableDesignerItemViewModelBase)
                {
                    DependencyObject container = itemsControl.ItemContainerGenerator.ContainerFromItem(item);

                    Rect itemRect = VisualTreeHelper.GetDescendantBounds((Visual)container);
                    Rect itemBounds = ((Visual)container).TransformToAncestor(_designerCanvas).TransformBounds(itemRect);

                    if (rubberBand.Contains(itemBounds))
                    {
                        //item.IsSelected = true;
                        //vm.SelectionService.AddToSelection(item);
                        item.AddToSelection(true, false);
                    }
                    else
                    {
                        if (!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
                        {
                            //item.IsSelected = false;
                            //vm.SelectionService.RemoveFromSelection(item);
                            item.RemoveFromSelection();
                        }
                    }
                }
            }
        }
    }
}
