using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner.Helpers;

namespace AIStudio.Wpf.DiagramDesigner
{
    public class ConnectorViewModel : SelectableDesignerItemViewModelBase
    {
        public ConnectorViewModel(IDiagramViewModel parent, FullyCreatedConnectorInfo sourceConnectorInfo, FullyCreatedConnectorInfo sinkConnectorInfo,
            SelectableDesignerItemBase designer, DrawMode vectorLineDrawMode) : base(parent, designer)
        {
            VectorLineDrawMode = vectorLineDrawMode;
            Init(sourceConnectorInfo, sinkConnectorInfo);

        }

        public ConnectorViewModel(IDiagramViewModel parent, FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo, DrawMode vectorLineDrawMode)
        {
            Parent = parent;
            VectorLineDrawMode = vectorLineDrawMode;
            Init(sourceConnectorInfo, sinkConnectorInfo);
        }

        public ConnectorViewModel( FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo, DrawMode vectorLineDrawMode):this(null, sourceConnectorInfo, sinkConnectorInfo, vectorLineDrawMode)
        {
         
        }

        public override SelectableDesignerItemBase ToXmlObject()
        {
            if (SinkConnectorInfo is FullyCreatedConnectorInfo sinkConnector)
            {
                ConnectionItem connection = new ConnectionItem(
                   SourceConnectorInfo.DataItem.Id,
                   SourceConnectorInfo.Orientation,
                   SourceConnectorInfo.DataItem.GetType(),
                   GetXRatioFromConnector(SourceConnectorInfo),
                   GetYRatioFromConnector(SourceConnectorInfo),
                   SourceConnectorInfo.IsInnerPoint,
                   sinkConnector.DataItem.Id,
                   sinkConnector.Orientation,
                   sinkConnector.DataItem.GetType(),
                   GetXRatioFromConnector(sinkConnector),
                   GetYRatioFromConnector(sinkConnector),
                   sinkConnector.IsInnerPoint,
                   this);

                return connection;
            }
            else
            {
                return null;
            }
        }

        public override Type ToXmlType()
        {
            return typeof(ConnectionItem);
        }

        public IPathFinder PathFinder
        {
            get; set;
        }

        public bool IsFullConnection
        {
            get
            {
                return _sinkConnectorInfo is FullyCreatedConnectorInfo;
            }
        }

        private Point _sourceA;
        public Point SourceA
        {
            get
            {
                return _sourceA;
            }
            set
            {
                if (SetProperty(ref _sourceA, value))
                {
                    UpdateArea();
                }
            }
        }

        private Point _sourceB;
        public Point SourceB
        {
            get
            {
                return _sourceB;
            }
            set
            {
                if (SetProperty(ref _sourceB, value))
                {
                    UpdateArea();
                }
            }
        }

        private List<PointInfoBase> _connectionPoints;
        public List<PointInfoBase> ConnectionPoints
        {
            get
            {
                return _connectionPoints;
            }
            private set
            {
                if (_connectionPoints != null)
                {
                    _connectionPoints.ForEach(p => p.PropertyChanged -= new WeakINPCEventHandler(ConnectionPoint_PropertyChanged).Handler);
                }
                SetProperty(ref _connectionPoints, value);
                if (_connectionPoints != null)
                {
                    _connectionPoints.ForEach(p => p.PropertyChanged += new WeakINPCEventHandler(ConnectionPoint_PropertyChanged).Handler);
                }
            }
        }

        private Point _startPoint;
        public Point StartPoint
        {
            get
            {
                return _startPoint;
            }
            private set
            {
                SetProperty(ref _startPoint, value);
            }
        }

        private Point _endPoint;
        public Point EndPoint
        {
            get
            {
                return _endPoint;
            }
            private set
            {
                SetProperty(ref _endPoint, value);
            }
        }

        private Rect _area;
        public Rect Area
        {
            get
            {
                return _area;
            }
            private set
            {
                Rect oldarea = _area;
                if (SetProperty(ref _area, value))
                {
                    UpdateConnectionPoints();
                    OutTextItemLocation(oldarea, value);
                }
            }
        }

        public DrawMode VectorLineDrawMode
        {
            get; set;
        }

        public virtual Dictionary<string, string> PropertiesSetting
        {
            get
            {
                return new Dictionary<string, string>()
                {
                    { "Text","文本" },
                };
            }
        }

        public ConnectorInfo ConnectorInfo(ConnectorOrientation orientation, double left, double top, double width, double height, Point position)
        {

            return new ConnectorInfo()
            {
                Orientation = orientation,
                DesignerItemSize = new Size(width, height),
                DesignerItemLeft = left,
                DesignerItemTop = top,
                Position = position

            };
        }

        private FullyCreatedConnectorInfo _sourceConnectorInfo;
        public FullyCreatedConnectorInfo SourceConnectorInfo
        {
            get
            {
                return _sourceConnectorInfo;
            }
            set
            {
                if (SetProperty(ref _sourceConnectorInfo, value))
                {
                    SourceA = PointHelper.GetPointForConnector(_sourceConnectorInfo);
                    (_sourceConnectorInfo.DataItem as INotifyPropertyChanged).PropertyChanged += new WeakINPCEventHandler(ConnectorViewModel_PropertyChanged).Handler;
                }
            }
        }

        private ConnectorInfoBase _sinkConnectorInfo;
        public ConnectorInfoBase SinkConnectorInfo
        {
            get
            {
                return _sinkConnectorInfo;
            }
            set
            {
                if (SetProperty(ref _sinkConnectorInfo, value))
                {
                    if (_sinkConnectorInfo is FullyCreatedConnectorInfo)
                    {
                        SourceB = PointHelper.GetPointForConnector((FullyCreatedConnectorInfo)_sinkConnectorInfo);
                        (((FullyCreatedConnectorInfo)_sinkConnectorInfo).DataItem as INotifyPropertyChanged).PropertyChanged += new WeakINPCEventHandler(ConnectorViewModel_PropertyChanged).Handler;
                    }
                    else
                    {
                        SourceB = ((PartCreatedConnectionInfo)SinkConnectorInfo).CurrentLocation;
                    }
                }
            }
        }

        public double GetXRatioFromConnector(FullyCreatedConnectorInfo info)
        {
            if (info.IsInnerPoint)
            {
                return info.XRatio;
            }
            else
            {
                switch (info.Orientation)
                {
                    case ConnectorOrientation.Top:
                        return 0.5;
                    case ConnectorOrientation.Left:
                        return 0;
                    case ConnectorOrientation.Bottom:
                        return 0.5;
                    case ConnectorOrientation.Right:
                        return 1;
                    default: return info.XRatio;
                }
            }
        }

        public double GetYRatioFromConnector(FullyCreatedConnectorInfo info)
        {
            if (info.IsInnerPoint)
            {
                return info.YRatio;
            }
            else
            {
                switch (info.Orientation)
                {
                    case ConnectorOrientation.Top:
                        return 0;
                    case ConnectorOrientation.Left:
                        return 0.5;
                    case ConnectorOrientation.Bottom:
                        return 1;
                    case ConnectorOrientation.Right:
                        return 0.5;
                    default: return info.YRatio;
                }
            }
        }

        private void UpdateArea()
        {
            Area = new Rect(SourceA, SourceB);
        }

        private void UpdateConnectionPoints()
        {
            ConnectionPoints = PathFinder.UpdateConnectionPoints(Parent, SourceA, SourceB, SourceConnectorInfo, SinkConnectorInfo);
            StartPoint = ConnectionPoints.First();
            EndPoint = ConnectionPoints.Last();

        }      

        private void ConnectorViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "ItemHeight":
                case "ItemWidth":
                case "Left":
                case "Top":
                    SourceA = PointHelper.GetPointForConnector(this.SourceConnectorInfo);
                    if (this.SinkConnectorInfo is FullyCreatedConnectorInfo)
                    {
                        SourceB = PointHelper.GetPointForConnector((FullyCreatedConnectorInfo)this.SinkConnectorInfo);
                    }
                    break;

            }
        }

        private void ConnectionPoint_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "Left":
                case "Top":
                    RaisePropertyChanged(nameof(ConnectionPoints));
                    break;

            }
        }

        private void Init(FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo)
        {
            this.Parent = sourceConnectorInfo.DataItem.Parent;
            if (VectorLineDrawMode == DrawMode.ConnectingLine)
            {
                PathFinder = new StraightLinePathFinder();
            }
            else if (VectorLineDrawMode == DrawMode.BoundaryConnectingLine)
            {
                PathFinder = new BoundaryPathFinder();
            }
            else
            {
                PathFinder = new OrthogonalPathFinder();
            }
            this.SourceConnectorInfo = sourceConnectorInfo;
            this.SinkConnectorInfo = sinkConnectorInfo;            
            DeleteConnectionCommand = new SimpleCommand(DeleteConnection);

            if (Parent != null && Parent.ColorViewModel != null)
            {
                this.ColorViewModel = CopyHelper.Mapper(Parent.ColorViewModel);
            }
            if (sinkConnectorInfo is FullyCreatedConnectorInfo sink && sink.DataItem.ShowArrow == false)
            {
                this.ColorViewModel.RightArrowPathStyle = ArrowPathStyle.None;
            }
        }

        public SimpleCommand DeleteConnectionCommand
        {
            get; set;
        }
        private void DeleteConnection(object args)
        {
            if (this.Parent is IDiagramViewModel)
            {
                var diagramVM = this.Parent as IDiagramViewModel;
                diagramVM.RemoveItemCommand.Execute(this);
            }
        }

        protected override void ExecuteEditCommand(object param)
        {
            if (this.OutTextItem != null) return;
            AddText("");
        }

        public void AddText(string text)
        {
            if (this.Parent is IDiagramViewModel)
            {
                var diagramVM = this.Parent as IDiagramViewModel;

                TextDesignerItemViewModel textitem = new TextDesignerItemViewModel();
                textitem.ItemWidth = Double.NaN;
                textitem.ItemHeight = double.NaN;
                if (diagramVM.DiagramType == DiagramType.FlowChart)
                {
                    var mid = (int)(ConnectionPoints.Count / 2);
                    var p = BoundaryPathFinder.SegmentMiddlePoint(ConnectionPoints[mid - 1], ConnectionPoints[mid]);
                    textitem.Left = this.Area.Left + p.X + 2;
                    textitem.Top = this.Area.Top + p.Y - 15;
                }
                else
                {
                    textitem.Left = this.Area.Left + this.Area.Width / 2 - 16;
                    textitem.Top = this.Area.Top + this.Area.Height / 2 - 5;
                }
                textitem.Watermark = null;
                textitem.ZIndex = diagramVM.Items.Count;
                textitem.ParentId = this.Id;
                textitem.ParentItem = this;
                textitem.ColorViewModel.FillColor = new ColorObject() { Color = Colors.White };
                textitem.Text = text;

                diagramVM.DirectAddItemCommand.Execute(textitem);

                this.OutTextItem = textitem;
            }
        }

        public void OutTextItemLocation(Rect oldArea, Rect newArea)
        {
            if (this.OutTextItem is TextDesignerItemViewModel text)
            {
                var oldpoint = new Point(oldArea.Left + oldArea.Width / 2, oldArea.Top + oldArea.Height / 2);
                var newpoint = new Point(newArea.Left + newArea.Width / 2, newArea.Top + newArea.Height / 2);

                text.Left = text.Left + newpoint.X - oldpoint.X;
                text.Top = text.Top + newpoint.Y - oldpoint.Y;
            }
        }

    }
}
