using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Machinations.FromFlash.graph;

namespace Machinations.GUI
{
    /// <summary>
    /// ancestor of node class and classes, whitch views are behaving similary to nodeViews, but which dont have a machinations model
    /// </summary>
    public abstract class PointObjectView :IObjectView
    {
        protected Point m_position;
        protected List<IConnectionView> m_inputConnections;
        protected List<IConnectionView> m_outputConnections;
        protected readonly TextBlock m_textBlock;
        /// <summary>
        /// defining shape of an object,each type of object have to have its own
        /// </summary>
        protected UIElement m_uiElement;
        protected ViewSelectionMode m_selected;
        protected ViewHighlightMode m_highlighted;

        protected PointObjectView()
        {
            m_inputConnections = new List<IConnectionView>();
            m_outputConnections = new List<IConnectionView>();
            m_textBlock = new TextBlock {Background = ColorsUtils.ConnectionTextBrush};
        }

        public virtual Point Position
        {
            get { return m_position;}
            set
            {
                m_position = value;
                SetMainUiElementPosition(value);
                UpdateLabelPosition();
                foreach (IConnectionView connection in m_inputConnections)
                {
                    connection.RecalculateEndPoint(true);
                }

                foreach (var connection in m_outputConnections)
                {
                    connection.RecalculateStartPoint(true);
                }

            }
        }

        public event Action OnLoaded;

        public UIElement UiElement
        {
            get { return m_uiElement; }
        }

        public virtual string Label
        {
            get { return m_textBlock.Text; }
            set
            {
                m_textBlock.Text = value;
                UpdateLabelPosition();
            }
        }
        public virtual Color BaseColor { get; set; }
        public virtual ViewSelectionMode Selected
        {
            get { return m_selected; }
            set
            {
                m_selected = value;
                var b = GetBrushForSelection();
                ColorView(b);
            }
        }

        public virtual ViewHighlightMode Highlighted
        {
            get { return m_highlighted; }
            set
            {
                if (value == ViewHighlightMode.Highlighted && m_highlighted != ViewHighlightMode.Highlighted)
                {
                    HighlightSurr();
                }
                else if (m_highlighted == ViewHighlightMode.Highlighted && value != ViewHighlightMode.Highlighted)
                {
                    UnHighlightSurr();
                }
                m_highlighted = value;
                var b = GetBrushForSelection();
                ColorView(b);
            }
        }

        public virtual int Radius
        {
            get { return 40; }
        }

        protected virtual void SetMainUiElementPosition(Point value)
        {
            m_uiElement.SetValue(Canvas.LeftProperty, value.X - Radius/2);
            m_uiElement.SetValue(Canvas.TopProperty, value.Y - Radius/2);
        }

        public virtual List<UIElement> GetAllUiElements()
        {
            return new List<UIElement> {m_uiElement, m_textBlock};
        }

        public Point LinePosition(Point beforeLast)
        {
            Vector fromCenter = new Vector(beforeLast.X - m_position.X, beforeLast.Y - m_position.Y);
            double realDistance = GeometryUtils.PointDistance(beforeLast, m_position);
            double shift = (Radius/2)/realDistance;
            return new Point(m_position.X + shift*fromCenter.X, m_position.Y + shift*fromCenter.Y);
        }

        public abstract GraphElement GetModelElement();

        public virtual void AddConnection(IConnectionView connectionView, bool start, bool withModel = true)
        {
            if (!start)
            {
                m_inputConnections.Add(connectionView);
                connectionView.AddEndView(this);
            }
            else
            {
                m_outputConnections.Add(connectionView);
                connectionView.AddStartView(this);
            }
        }

        public virtual void RemoveConnection(IConnectionView connection, bool start)
        {
            if (!start)
            {
                m_inputConnections.Remove(connection);
                connection.RemoveEnd();
            }
            else
            {
                m_outputConnections.Remove(connection);
                connection.RemoveStart();
            }
            connection.Model.DisconnectElement(start);
        }

        public virtual void Move(double deltaX, double deltaY)
        {
            Position = new Point(Position.X + deltaX, Position.Y + deltaY);
        }

        public virtual void ColorView(Brush brush)
        {
            throw new NotImplementedException();
        }

        protected virtual void UpdateLabelPosition()
        {
            m_textBlock.SetValue(Canvas.LeftProperty, m_position.X - m_textBlock.Text.Length*3);
            m_textBlock.SetValue(Canvas.TopProperty, m_position.Y + Radius/2);
        }


        public Brush GetBrushForSelection()
        {
            if(m_highlighted == ViewHighlightMode.Highlighted)
                return Brushes.DarkKhaki;
            if(m_highlighted == ViewHighlightMode.NextToHighlighted)
                return Brushes.CadetBlue;
            switch (m_selected)
            {
                case ViewSelectionMode.None:
                    return GetBrushForNormalSelection();
                case ViewSelectionMode.Selected:
                    return Brushes.Chartreuse;
                case ViewSelectionMode.ClickedAndWaiting:
                    return Brushes.Aqua;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        protected virtual Brush GetBrushForNormalSelection()
        {
            return new SolidColorBrush(Colors.Black);
        }

        public virtual void Dispose()
        {
            m_inputConnections.ForEach(ic => ic.RemoveEnd());
            m_outputConnections.ForEach(oc => oc.RemoveStart());
        }

        private void HighlightSurr()
        {
            m_inputConnections.ForEach(ic => ic.Highlighted = ViewHighlightMode.NextToHighlighted);
            m_outputConnections.ForEach(oc => oc.Highlighted = ViewHighlightMode.NextToHighlighted);
        }

        private void UnHighlightSurr()
        {
            m_inputConnections.ForEach(ic => ic.Highlighted = ViewHighlightMode.None);
            m_outputConnections.ForEach(oc => oc.Highlighted = ViewHighlightMode.None);
        }
    }
}
