using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner.Geometrys;

namespace AIStudio.Wpf.DiagramDesigner.Controls
{
    public class DragThumb : Thumb
    {
        public DragThumb()
        {
            base.DragDelta += new DragDeltaEventHandler(DragThumb_DragDelta);
            base.DragStarted += DragThumb_DragStarted;
            base.DragCompleted += DragThumb_DragCompleted;
        }

        public IDiagramViewModel DiagramViewModel
        {
            get
            {
                return (this.DataContext as SelectableDesignerItemViewModelBase)?.Root;
            }
        }
        private List<SelectableDesignerItemViewModelBase> designerItems;

        private bool drag;
        private void DragThumb_DragStarted(object sender, DragStartedEventArgs e)
        {
            GetDesignerCanvas(this)?.Focus();

            drag = false;
            SelectableDesignerItemViewModelBase designerItem = this.DataContext as SelectableDesignerItemViewModelBase;

            if (designerItem != null && designerItem.IsSelected)
            {
                // we only move DesignerItems
                designerItems = designerItem.Root.SelectedItems.ToList();
                if (designerItem is IGroupable groupable)
                {
                    designerItems.AddRange(designerItem.Root.SelectionService.GetGroupMembers(groupable).OfType<SelectableDesignerItemViewModelBase>());
                }

                if (designerItem is ConnectionViewModel connector)
                {
                    designerItems.Add(connector.SourceConnectorInfo.DataItem);
                    if (connector.IsFullConnection)
                    {
                        designerItems.Add(connector.SinkConnectorInfoFully.DataItem);
                    }
                }

                if (designerItem is PointDesignerItemViewModel)
                {
                    designerItems = new List<SelectableDesignerItemViewModelBase> { designerItem };
                }

                designerItems = designerItems.Distinct().ToList();

                DiagramViewModel.DoCommandManager.BeginDo = true;
                foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
                {
                    item.SetOldValue(item.TopLeft, nameof(item.TopLeft));
                }

                e.Handled = true;
            }
            else
            {
                designerItems = null;
            }
        }

        private void DragThumb_DragCompleted(object sender, DragCompletedEventArgs e)
        {
            if (drag == false) 
            { 
                DiagramViewModel.DoCommandManager.BeginDo = false;
                return; 
            }

            if (designerItems != null)
            {
                foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
                {
                    item.SetCellAlignment();
                }

                Dictionary<DesignerItemViewModelBase, Tuple<PointBase, PointBase>> infos =
                    designerItems.OfType<DesignerItemViewModelBase>().ToDictionary(p => p,
                    p => new Tuple<PointBase, PointBase>(p.GetOldValue<PointBase>(nameof(p.TopLeft)), p.TopLeft));
                DiagramViewModel.DoCommandManager.BeginDo = false;
                DiagramViewModel.DoCommandManager.DoNewCommand(this.ToString(),
                  () => {
                      foreach (var info in infos)
                      {
                          info.Key.TopLeft = info.Value.Item2;
                      }
                  },
                  () => {
                      foreach (var info in infos)
                      {
                          info.Key.TopLeft = info.Value.Item1;
                      }
                  });
                e.Handled = true;
            }
        }

        void DragThumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            drag = true;
            if (designerItems != null)
            {
                foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
                {
                    item.Left += e.HorizontalChange;
                    item.Top += e.VerticalChange;
                }

                e.Handled = true;
            }
        }

        private DesignerCanvas GetDesignerCanvas(DependencyObject element)
        {
            while (element != null && !(element is DesignerCanvas))
                element = VisualTreeHelper.GetParent(element);

            return element as DesignerCanvas;
        }
    }
}
