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

namespace Machinations.GUI
{
    /// <summary>
    /// ancestor of all machinations node views,contains common metods of them
    /// can be used as a source for simlink 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class NodeView<T> : PointObjectView, ILinkableObject, INodeView<T> where T : MachinationsNode
    {
        protected T m_model;
        protected readonly TextBlock m_descriptionTextBlock;
        protected List<SimlinkView> m_simlinkViews;


        //protected NodeView(T model, GraphSymbol symbol) : this(model)
        //{
        //    model.Symbol = symbol;
        //}

        protected NodeView(T model)
        {
            m_model = model;
            m_textBlock.Text = model.Caption;
            m_simlinkViews = new List<SimlinkView>();
            model.Simlinks.ForEach(sm =>
            {
                CreateSimlinkView(sm);
            });
            m_descriptionTextBlock = new TextBlock {Text = m_model.Description, Background = ColorsUtils.ConnectionTextBrush } ;
            model.InhibitedChanged += () => Selected = ViewSelectionMode.None;
            model.DescriptionChanged += () => m_descriptionTextBlock.Text = m_model.Description;
            m_model.OnSelect += () => { Selected = ViewSelectionMode.Selected; };
            m_model.OnUnselect += () => { Selected = ViewSelectionMode.None; };
        }


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

        public override string Label
        {
            get { return m_model.Caption; }
            set
            {
                m_model.Caption = value;
                base.Label = value;
                m_simlinkViews.ForEach(sv => sv.Label = value);
            }
        }

        public int ActivationMode
        {
            get { return (int)m_model.ActivationMode; }
            set
            {
                m_model.ActivationMode = (ActivationMode)value;
            }
        }

        public int PullMode
        {
            get { return (int)m_model.PullMode; }
            set { m_model.PullMode = (PullMode)value; }
        }

        public T Model
        {
            get { return m_model; }
        }

        public override Point Position
        {
            get { return Model.Position; }
            set
            {
                base.Position = value;
                Model.Position = value;
                m_descriptionTextBlock.SetValue(Canvas.LeftProperty, value.X + Radius / 2);
                m_descriptionTextBlock.SetValue(Canvas.TopProperty, value.Y - Radius / 2);
            }
        }

        public override Color BaseColor
        {
            get { return m_model.Color; }
            set
            {
                m_model.Color = value;
                ColorView(new SolidColorBrush(value));
            }
        }

        public override ViewSelectionMode Selected
        {
            set
            {
                base.Selected = value;
                m_simlinkViews.ForEach(sv => sv.Selected = value);
            }
        }

        public override ViewHighlightMode Highlighted
        {
            set
            {
                base.Highlighted = value;
                m_simlinkViews.ForEach(sv => sv.Highlighted = value);
            }
        }

        public IEnumerable<SimlinkView> SimlinkViews
        {
            get { return m_simlinkViews; }
        }


        public virtual void InitShape()
        {
            Border border = new Border
            {
                CornerRadius = new CornerRadius(Radius),
                Width = Radius,
                Height = Radius,
                Background = Brushes.Transparent,
                BorderBrush = new SolidColorBrush(m_model.Color),
                BorderThickness = new Thickness(m_model.Thickness)
            };
            m_uiElement = border;
        }

        public override void AddConnection(IConnectionView connectionView, bool start, bool withModel = true)
        {
            var correctView = GetViewOrSimlink(connectionView.Model);
            if (correctView != this)
            {
                correctView.AddConnection(connectionView, start, withModel);
            }
            else
            {
                base.AddConnection(connectionView, start);
                if(withModel)
                    connectionView.Model.ConnectToElement(Model, start);
            }

        }

        public override List<UIElement> GetAllUiElements()
        {
            return new List<UIElement> { m_uiElement, m_descriptionTextBlock, m_textBlock };
            //return
            //    m_simlinkViews.SelectMany(v => v.GetAllUiElements())
            //        .Concat(new[] { m_uiElement, m_descriptionTextBlock, m_textBlock })
            //        .ToList();
        }

        public override void ColorView(Brush brush)
        {
            ((Border)m_uiElement).BorderBrush = brush;
        }

        public override void Dispose()
        {
            base.Dispose();
            m_model.Dispose();
        }

        protected override Brush GetBrushForNormalSelection()
        {
            if (Model.Inhibited) return Brushes.LightGray;
            return new SolidColorBrush(Model.Color);
        }

        public override GraphElement GetModelElement()
        {
            return Model;
        }

        public SimlinkView CreateSimlinkView(SimlinkModel existing = null)
        {
            if (existing == null)
            {
                Point newPosition = new Point(Position.X, Position.Y + 20);
                existing = new SimlinkModel(Model, newPosition);
            }
            var simlinkView = new SimlinkView(this, existing) { Position = existing.Position, Label = Label };
            m_simlinkViews.Add(simlinkView);
            return simlinkView;
        }

        private IObjectView GetViewOrSimlink(MachinationsConnection connection)
        {
            var simlink = m_simlinkViews.SingleOrDefault(sl => sl.Model.Connections.Contains(connection));
            if (simlink != null)
                return simlink;
            return this;
        }
    }

    public interface ILinkableObject
    {
        IEnumerable<SimlinkView> SimlinkViews { get; }
    }
}
