using System;
using System.Collections.Generic;
using System.Text;

namespace AIStudio.Wpf.DiagramDesigner
{
    public class ShapeViewModel : BindableBase, IShapeViewModel
    {
        private ILinkMarker _sourceMarker = LinkMarker.None;
        public ILinkMarker SourceMarker
        {
            get
            {
                return _sourceMarker;
            }
            set
            {
                if (_sourceMarker != value)
                {
                    if (_sourceMarker != null && _sourceMarker is LinkMarker _linkMarker1)
                    {
                        _linkMarker1.PropertyChanged -= ShapeViewModel_PropertyChanged;
                    }
                    SetProperty(ref _sourceMarker, value);
                    if (_sourceMarker != null && _sourceMarker is LinkMarker _linkMarker2)
                    {
                        _linkMarker2.PropertyChanged += ShapeViewModel_PropertyChanged;
                    }
                }
                else
                {
                    RaisePropertyChanged(nameof(SourceMarker));
                }
            }
        }

        private ILinkMarker _sinkMarker = LinkMarker.Arrow;
        public ILinkMarker SinkMarker
        {
            get
            {
                return _sinkMarker;
            }
            set
            {
                if (_sinkMarker != value)
                {
                    if (_sinkMarker != null && _sinkMarker is LinkMarker _linkMarker1)
                    {
                        _linkMarker1.PropertyChanged -= ShapeViewModel_PropertyChanged;
                    }
                    SetProperty(ref _sinkMarker, value);
                    if (_sinkMarker != null && _sinkMarker is LinkMarker _linkMarker2)
                    {
                        _linkMarker2.PropertyChanged += ShapeViewModel_PropertyChanged;
                    }
                }
                else
                {
                    RaisePropertyChanged(nameof(SinkMarker));
                }
            }
        }

        private void ShapeViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (sender == SourceMarker)
            {
                RaisePropertyChanged(nameof(SourceMarker));
            }
            else if (sender == SinkMarker)
            {
                RaisePropertyChanged(nameof(SinkMarker));
            }
        }
    }

    public class LinkMarker : BindableBase, ILinkMarker
    {
        public static LinkMarker None { get; } = new LinkMarker("", 10, 10, ArrowPathStyle.None, ArrowSizeStyle.Middle);
        public static LinkMarker Arrow { get; } = new LinkMarker("M 0 -5 10 0 0 5 z", 10, 10, ArrowPathStyle.Arrow, ArrowSizeStyle.Middle);
        public static LinkMarker Circle { get; } = new LinkMarker("M 0, 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0", 10, 10, ArrowPathStyle.Circle, ArrowSizeStyle.Middle);
        public static LinkMarker Square { get; } = new LinkMarker("M 0 -5 10 -5 10 5 0 5 z", 10, 10, ArrowPathStyle.Square, ArrowSizeStyle.Middle);

        public static readonly Dictionary<ArrowPathStyle, string> ArrowDictionary = new Dictionary<ArrowPathStyle, string>()
        {
            { ArrowPathStyle.None, None.Path },
            { ArrowPathStyle.Arrow, Arrow.Path },
            { ArrowPathStyle.Circle, Circle.Path },
            { ArrowPathStyle.Square, Square.Path },
        };

        public LinkMarker()
        {

        }

        public LinkMarker(string path, double width, double height, ArrowPathStyle arrowPathStyle, ArrowSizeStyle arrowSizeStyle)
        {
            Path = path;
            Width = width;
            Height = height;
            _pathStyle = arrowPathStyle;
            _sizeStyle = arrowSizeStyle;
        }

        private string _path;
        [CanDo]
        public string Path
        {
            get
            {
                return _path;
            }
            set
            {
                SetProperty(ref _path, value);
            }
        }

        private double _witdh;
        [CanDo]
        public double Width
        {
            get
            {
                return _witdh;
            }
            set
            {
                SetProperty(ref _witdh, value);
            }
        }

        private double _height;
        [CanDo]
        public double Height
        {
            get
            {
                return _height;
            }
            set
            {
                SetProperty(ref _height, value);
            }
        }

        private ArrowPathStyle _pathStyle = ArrowPathStyle.None;
        [CanDo]
        public ArrowPathStyle PathStyle
        {
            get
            {
                return _pathStyle;
            }
            set
            {
                if (SetProperty(ref _pathStyle, value))
                {
                    if (ArrowDictionary.ContainsKey(_pathStyle))
                    {
                        Path = ArrowDictionary[_pathStyle];
                    }
                }
            }
        }

        private ArrowSizeStyle _sizeStyle = ArrowSizeStyle.Middle;
        [CanDo]
        public ArrowSizeStyle SizeStyle
        {
            get
            {
                return _sizeStyle;
            }
            set
            {
                if (SetProperty(ref _sizeStyle, value))
                {
                    Width = (double)_sizeStyle;
                    Height = (double)_sizeStyle;
                }
            }
        }

        public static LinkMarker NewArrow(double width, double height)
            => new LinkMarker(FormattableString.Invariant($"M 0 -{height / 2} {width} 0 0 {height / 2}"), width, height, ArrowPathStyle.Arrow, (ArrowSizeStyle)width);

        public static LinkMarker NewCircle(double r)
            => new LinkMarker(FormattableString.Invariant($"M 0, 0 a {r},{r} 0 1,0 {r * 2},0 a {r},{r} 0 1,0 -{r * 2},0"), r * 2, r * 2, ArrowPathStyle.Circle, (ArrowSizeStyle)(r * 2));

        public static LinkMarker NewRectangle(double width, double height)
            => new LinkMarker(FormattableString.Invariant($"M 0 -{height / 2} {width} -{height / 2} {width} {height / 2} 0 {height / 2} z"), width, height, ArrowPathStyle.Square, (ArrowSizeStyle)width);

        public static LinkMarker NewSquare(double size) => NewRectangle(size, size);
    }

    public interface ILinkMarker
    {
        string Path
        {
            get; set;
        }

        double Width
        {
            get; set;
        }

        double Height
        {
            get; set;
        }

        ArrowPathStyle PathStyle
        {
            get; set;
        }

        ArrowSizeStyle SizeStyle
        {
            get; set;
        }
    }
}
