using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel.Design;
using System.Collections;
using System.Windows.Forms.Design.Behavior;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
namespace DevComponents.DotNetBar.Layout.Design
{
    public class LayoutItemBaseDesigner : ComponentDesigner
    {
        #region Constructor
        /// 
        /// Initializes a new instance of the LayoutItemBaseDesigner class.
        /// 
        public LayoutItemBaseDesigner()
        {
        }
        #endregion
        #region Implementation
        public override void Initialize(System.ComponentModel.IComponent component)
        {
            base.Initialize(component);
            ISelectionService selectionService = (ISelectionService)GetService(typeof(ISelectionService));
            if (selectionService != null)
                selectionService.SelectionChanged += SelectionChanged;
            BehaviorService behaviorService = (BehaviorService)GetService(typeof(BehaviorService));
            Adorner designerActionAdorner = new Adorner();
            behaviorService.Adorners.Add(designerActionAdorner);
            LayoutItemGlyph glyph = new LayoutItemGlyph(behaviorService, (LayoutItemBase)component);
            designerActionAdorner.Glyphs.Add(glyph);
        }
        protected override void Dispose(bool disposing)
        {
            ISelectionService selectionService = (ISelectionService)GetService(typeof(ISelectionService));
            if (selectionService != null)
                selectionService.SelectionChanged -= SelectionChanged;
            base.Dispose(disposing);
        }
        private void OnComponentRemoved(object sender, ComponentEventArgs e)
        {
            if (e.Component == this.Component)
            {
                LayoutItemBase item = e.Component as LayoutItemBase;
                LayoutGroup parent = item.Parent as LayoutGroup;
                LayoutControl lc = null;
                if (parent != null) lc = parent.GetLayoutControl();
                if (item != null && parent != null && parent.Items.Contains(item))
                {
                    IComponentChangeService cc = (IComponentChangeService)GetService(typeof(IComponentChangeService));
                    if (cc != null)
                        cc.OnComponentChanging(parent, TypeDescriptor.GetProperties(parent)["Items"]);
                    parent.Items.Remove(item);
                    if (cc != null)
                        cc.OnComponentChanged(parent, TypeDescriptor.GetProperties(parent)["Items"], null, null);
                    if (lc != null)
                    {
                        lc.Invalidate();
                        IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
                        if (host != null)
                        {
                            IDesigner designer = host.GetDesigner(lc);
                            if (designer is LayoutControlDesigner)
                            {
                                ((LayoutControlDesigner)designer).SelectionRefresh();
                            }
                        }
                    }
                }
            }
        }
        private void SelectionChanged(object sender, EventArgs e)
        {
            bool selected = false;
            ISelectionService selectionService = (ISelectionService)GetService(typeof(ISelectionService));
            if (selectionService.PrimarySelection == this.Component)
                selected = true;
            else
            {
                ICollection selectedComponents = selectionService.GetSelectedComponents();
                foreach (object o in selectedComponents)
                {
                    if (o == this.Component)
                    {
                        selected = true;
                        break;
                    }
                }
            }
            LayoutItemBase item = (LayoutItemBase)this.Component;
            item.IsSelected = selected;
        }
        public override System.Collections.ICollection AssociatedComponents
        {
            get
            {
                LayoutGroup group = this.Component as LayoutGroup;
                if (group == null)
                    return base.AssociatedComponents;
                List items = new List();
                group.Items.CopyTo(items);
                return items;
            }
        }
        protected override void PreFilterProperties(IDictionary properties)
        {
            base.PreFilterProperties(properties);
            properties["Visible"] = TypeDescriptor.CreateProperty(typeof(LayoutItemBaseDesigner), (PropertyDescriptor)properties["Visible"], new Attribute[]
				{
					new DefaultValueAttribute(true),
					new BrowsableAttribute(true),
					new CategoryAttribute("Appearance")});
        }
        /// 
        /// Gets or sets whether item is visible.
        /// 
        [DefaultValue(true), Browsable(true), Category("Appearance"), Description("Indicates visiblity of the item.")]
        public bool Visible
        {
            get
            {
                return (bool)ShadowProperties["Visible"];
            }
            set
            {
                // this value is not passed to the actual control
                this.ShadowProperties["Visible"] = value;
            }
        }
        #endregion
    }
    class LayoutItemGlyph : Glyph
    {
        LayoutItemBase _Item;
        BehaviorService _BehaviorSvc;
        public LayoutItemGlyph(BehaviorService behaviorSvc, LayoutItemBase item)
            :
            base(new LayoutItemBehavior())
        {
            _BehaviorSvc = behaviorSvc;
            _Item = item;
        }
        public LayoutItemBase Item
        {
            get
            {
                return _Item;
            }
        }
        public override Rectangle Bounds
        {
            get
            {
                // Glyph coordinates are in adorner window coordinates, so we must map using the behavior service.
                Rectangle bounds = Rectangle.Empty;
                if (_Item != null && _Item.GetLayoutControl() != null)
                {
                    Point edge = _BehaviorSvc.ControlToAdornerWindow(_Item.GetLayoutControl());
                    if (_Item is LayoutControlItem)
                        bounds = _Item.ActualTextBounds;
                    else
                        bounds = _Item.Bounds;
                    bounds.Offset(edge);
                }
                return bounds;
            }
        }
        public Rectangle CompleteBounds
        {
            get
            {
                Rectangle bounds = Rectangle.Empty;
                if (_Item != null && _Item.GetLayoutControl() != null)
                {
                    Point edge = _BehaviorSvc.ControlToAdornerWindow(_Item.GetLayoutControl());
                    bounds = _Item.Bounds;
                    bounds.Offset(edge);
                }
                return bounds;
            }
        }
        public override Cursor GetHitTest(Point p)
        {
            if (_Item != null && !_Item.IsSelected)
                return null;
            // GetHitTest is called to see if the point is 
            // within this glyph.  This gives us a chance to decide 
            // what cursor to show.  Returning null from here means 
            // the mouse pointer is not currently inside of the glyph. 
            // Returning a valid cursor here indicates the pointer is 
            // inside the glyph, and also enables our Behavior property 
            // as the active behavior. 
            if (Bounds.Contains(p))
            {
                return Cursors.SizeAll;
            }
            return null;
        }
        private bool GetIsItemVisible()
        {
            if (_Item == null)
                return false;
            LayoutControl lc = _Item.GetLayoutControl();
            if (lc != null)
            {
                if (!lc.Visible) return false;
                if (lc.Parent != null && !lc.Parent.Visible) return false;
                if(lc.Parent is TabControlPanel && ((TabControlPanel)lc.Parent).TabItem!=null && !((TabControlPanel)lc.Parent).TabItem.IsSelected)
                    return false;
                if (lc.Parent is SuperTabControlPanel && ((SuperTabControlPanel)lc.Parent).TabItem != null && !((SuperTabControlPanel)lc.Parent).TabItem.IsSelected)
                    return false;
            }
            return true;
        }
        public override void Paint(PaintEventArgs pe)
        {
            // Draw our glyph
            if (_Item != null)
            {
                if (_Item.IsSelected)
                {
                    Rectangle r = CompleteBounds;
                    r.Width--;
                    r.Height--;
                    Graphics g = pe.Graphics;
                    using (Pen pen = new Pen(SelectionColor))
                    {
                        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
                        g.DrawRectangle(pen, r);
                    }
                }
                else if ((!_Item.TextVisible || string.IsNullOrEmpty(_Item.Text)) && GetIsItemVisible())
                {
                    Rectangle r = CompleteBounds;
                    r.Width--;
                    r.Height--;
                    Graphics g = pe.Graphics;
                    using (Pen pen = new Pen(SelectableColor))
                    {
                        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                        g.DrawRectangle(pen, r);
                    }
                }
            }
        }
        private static readonly Color SelectableColor = ColorHelpers.GetColor(0x8C8C91);
        private static readonly Color SelectionColor = ColorHelpers.GetColor(0x696969);
        // By providing our own behavior we can do something interesting 
        // when the user clicks or manipulates our glyph. 
        class LayoutItemBehavior : Behavior
        {
            //public override bool OnMouseUp(Glyph g, MouseButtons button)
            //{
            //    //MessageBox.Show("Hey, you clicked the mouse here");
            //    //return true; // indicating we processed this event.
            //    return base.OnMouseUp(g, button);
            //}
            private Point _MouseDownLocation = Point.Empty;
            public override bool OnMouseDown(Glyph g, MouseButtons button, Point mouseLoc)
            {
                LayoutItemGlyph itemGlyph = (LayoutItemGlyph)g;
                if (itemGlyph._Item != null && itemGlyph._Item.Site != null && (!itemGlyph._Item.IsSelected || itemGlyph._Item is LayoutGroup))
                {
                    LayoutItemBase item = itemGlyph._Item;
                    IComponent selectItem = item;
                    if (item is LayoutGroup)
                    {
                        LayoutControl lc = item.GetLayoutControl();
                        if (lc == null) return base.OnMouseDown(g, button, mouseLoc);
                        Point loc = lc.PointToClient(Control.MousePosition);
                        LayoutItemBase itemAt = lc.HitTest(loc);
                        if (itemAt != null && itemAt != item && itemAt.Site != null)
                        {
                            // Selection is selecting something inside of group
                            selectItem = itemAt;
                            if (itemAt is LayoutControlItem)
                            {
                                LayoutControlItem lci = (LayoutControlItem)itemAt;
                                if (lci.Control != null && lci.Control.ClientRectangle.Contains(lci.Control.PointToClient(Control.MousePosition)) && lci.Control.Site != null)
                                    selectItem = lci.Control;
                            }
                        }
                        // No need to re-select
                        if (selectItem == itemGlyph._Item && itemGlyph.Item.IsSelected)
                            return base.OnMouseDown(g, button, mouseLoc);
                    }
                    ISelectionService selectionService = (ISelectionService)selectItem.Site.GetService(typeof(ISelectionService));
                    if (selectionService != null && selectItem != null)
                    {
                        selectionService.SetSelectedComponents(new IComponent[] { selectItem });
                        return true;
                    }
                }
                return base.OnMouseDown(g, button, mouseLoc);
            }
            public override bool OnMouseUp(Glyph g, MouseButtons button)
            {
                _MouseDownLocation = Point.Empty;
                return base.OnMouseUp(g, button);
            }
            public override bool OnMouseMove(Glyph g, MouseButtons button, Point mouseLoc)
            {
                if (button == MouseButtons.Left && _MouseDownLocation.IsEmpty)
                    _MouseDownLocation = mouseLoc;
                if (button == MouseButtons.Left && !_MouseDownLocation.IsEmpty &&
                    (Math.Abs(mouseLoc.X - _MouseDownLocation.X) > 1 || Math.Abs(mouseLoc.Y - _MouseDownLocation.Y) > 1))
                {
                    LayoutItemGlyph glyph = g as LayoutItemGlyph;
                    if (glyph != null && glyph.Item != null)
                    {
                        ISelectionService selectionService = GetSelectionService(glyph.Item);
                        if (selectionService != null && selectionService.PrimarySelection == glyph.Item && selectionService.GetSelectedComponents().Count == 1)
                        {
                            _MouseDownLocation = Point.Empty;
                            this.DropSource.QueryContinueDrag += new QueryContinueDragEventHandler(this.QueryContinueDrag);
                            this.DropSource.DoDragDrop(new LayoutItemDataObject(glyph.Item), DragDropEffects.Move | DragDropEffects.Copy | DragDropEffects.Scroll);
                        }
                    }
                }
                return false;// base.OnMouseMove(g, button, mouseLoc);
            }
            public override void OnDragDrop(Glyph g, DragEventArgs e)
            {
                if (e.Data is LayoutItemDataObject)
                {
                    LayoutItemDataObject d = (LayoutItemDataObject)e.Data;
                    LayoutControl lc = d.DragComponent.GetLayoutControl();
                    if (lc != null)
                    {
                        lc.HideInsertMarker();
                        LayoutItemBase item = d.DragComponent;
                        ISelectionService selectionService = GetSelectionService(item);
                        IDesignerHost host = GetDesignerHostService(item);
                        IComponentChangeService cc = GetComponentChangeService(item);
                        if (selectionService != null && host != null && cc != null)
                        {
                            HitTestInsertInfo info = lc.GetHitTestInsertInfo(item, lc.PointToClient(new Point(e.X, e.Y)));
                            if (info.Parent != null)
                            {
                                DesignerTransaction dt = host.CreateTransaction("Moving Layout Control Item");
                                cc.OnComponentChanging(lc, TypeDescriptor.GetProperties(lc)["RootGroup"]);
                                //lc.Text = string.Format("Moving at B: {0}", info.InsertIndex);
                                //lc.Invalidate();
                                if (info.Parent != item.Parent)
                                {
                                    LayoutGroup group = (LayoutGroup)item.Parent;
                                    if (group != lc.RootGroup)
                                        cc.OnComponentChanging(group, TypeDescriptor.GetProperties(lc)["Items"]);
                                    group.Items.Remove(item);
                                    if (group != lc.RootGroup)
                                        cc.OnComponentChanged(group, TypeDescriptor.GetProperties(lc)["Items"], null, null);
                                    if (info.Parent != lc.RootGroup)
                                        cc.OnComponentChanging(info.Parent, TypeDescriptor.GetProperties(lc)["Items"]);
                                    if (info.InsertIndex >= 0)
                                        info.Parent.Items.Insert(info.InsertIndex, item);
                                    else
                                        info.Parent.Items.Add(item);
                                    if (info.Parent != lc.RootGroup)
                                        cc.OnComponentChanged(info.Parent, TypeDescriptor.GetProperties(lc)["Items"], null, null);
                                }
                                else
                                {
                                    if (info.Parent != lc.RootGroup)
                                        cc.OnComponentChanging(info.Parent, TypeDescriptor.GetProperties(lc)["Items"]);
                                    info.Parent.Items.Move(item, info.InsertIndex);
                                    if (info.Parent != lc.RootGroup)
                                        cc.OnComponentChanged(info.Parent, TypeDescriptor.GetProperties(lc)["Items"], null, null);
                                }
                                cc.OnComponentChanged(lc, TypeDescriptor.GetProperties(lc)["RootGroup"], null, null);
                                dt.Commit();
                                lc.PerformLayout();
                                lc.Invalidate(true);
                                IDesigner designer = host.GetDesigner(lc);
                                if (designer is LayoutControlDesigner)
                                    ((LayoutControlDesigner)designer).SelectionRefresh();
                            }
                        }
                    }
                }
                base.OnDragDrop(g, e);
            }
            public override void OnDragLeave(Glyph g, EventArgs e)
            {
                LayoutItemGlyph glyph = g as LayoutItemGlyph;
                if (glyph != null && glyph.Item != null)
                {
                    LayoutControl lc = glyph.Item.GetLayoutControl();
                    if (lc != null)
                        lc.HideInsertMarker();
                }
                base.OnDragLeave(g, e);
            }
            public override void OnDragOver(Glyph g, DragEventArgs e)
            {
                if (e.Data is LayoutItemDataObject)
                {
                    e.Effect = DragDropEffects.Move;
                    LayoutItemDataObject d = (LayoutItemDataObject)e.Data;
                    LayoutControl lc = d.DragComponent.GetLayoutControl();
                    if (lc != null)
                    {
                        HitTestInsertInfo info = lc.GetHitTestInsertInfo(d.DragComponent, lc.PointToClient(new Point(e.X, e.Y)));
                        if (!info.InsertMarkerBounds.IsEmpty)
                            lc.ShowInsertMarker(info.InsertMarkerBounds);
                        else
                            lc.HideInsertMarker();
                        e.Effect = DragDropEffects.Move;
                        return;
                    }
                }
                e.Effect = DragDropEffects.None;
                return;
                base.OnDragOver(g, e);
            }
            public override void OnDragEnter(Glyph g, DragEventArgs e)
            {
                if (e.Data is LayoutItemDataObject)
                {
                    e.Effect = DragDropEffects.Move;
                }
                else
                    e.Effect = DragDropEffects.None;
                return;
                base.OnDragEnter(g, e);
            }
            private void QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
            {
                if ((e.Action != DragAction.Continue) && e.EscapePressed)
                {
                    e.Action = DragAction.Cancel;
                    //ToolStripItem glyphItem = sender as ToolStripItem;
                    //this.SetParentDesignerValuesForDragDrop(glyphItem, false, Point.Empty);
                    //ISelectionService selectionService = this.GetSelectionService(glyphItem);
                    //if (selectionService != null)
                    //{
                    //    selectionService.SetSelectedComponents(new IComponent[] { glyphItem }, SelectionTypes.Auto);
                    //}
                    //ToolStripDesigner.dragItem = null;
                }
            }
            private ISelectionService GetSelectionService(LayoutItemBase item)
            {
                if (item.Site != null)
                {
                    return (ISelectionService)item.Site.GetService(typeof(ISelectionService));
                }
                return null;
            }
            private IDesignerHost GetDesignerHostService(LayoutItemBase item)
            {
                if (item.Site != null)
                {
                    return (IDesignerHost)item.Site.GetService(typeof(IDesignerHost));
                }
                return null;
            }
            private IComponentChangeService GetComponentChangeService(LayoutItemBase item)
            {
                if (item.Site != null)
                {
                    return (IComponentChangeService)item.Site.GetService(typeof(IComponentChangeService));
                }
                return null;
            }
            private Control _DropSource = null;
            private Control DropSource
            {
                get
                {
                    if (_DropSource == null)
                    {
                        _DropSource = new Control();
                    }
                    return _DropSource;
                }
            }
        }
    }
    #region LayoutItemDataObject
    internal class LayoutItemDataObject : DataObject
    {
        private LayoutItemBase _DragComponent;
        // Methods
        internal LayoutItemDataObject(LayoutItemBase dragComponents)
        {
            _DragComponent = dragComponents;
        }
        // Properties
        internal LayoutItemBase DragComponent
        {
            get
            {
                return _DragComponent;
            }
        }
    }
    #endregion
}