using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using DevComponents.DotNetBar.SuperGrid.Style;
namespace DevComponents.DotNetBar.SuperGrid
{
    /// 
    /// Represents the base grid item.
    /// 
    [DesignTimeVisible(false), ToolboxItem(false)]
    public abstract class GridElement : Component, INotifyPropertyChanged
    {
        #region Events
        /// 
        /// Occurs when display/rendering of the item is invalidated.
        /// 
        public event EventHandler RenderInvalid;
        /// 
        /// Occurs when layout of the item is invalidated.
        /// 
        public event EventHandler LayoutInvalid;
        /// 
        /// Occurs when parent of the item has changed.
        /// 
        public event EventHandler ParentChanged;
        #endregion
        #region Static variables
        static Point _mouseDownPoint;
        #endregion
        #region Private variables
        private Es _States;
        private Rectangle _BoundsRelative = Rectangle.Empty;
        private GridElement _Parent;
        private SuperGridControl _SuperGrid;
        private GridPanel _GridPanel;
        private object _Tag;
        #endregion
        #region Constructor
        /// 
        /// GridElement
        /// 
        protected GridElement()
        {
            SetState(Es.AllowSelection, true);
            SetState(Es.NeedsMeasured, true);
            SetState(Es.Visible, true);
        }
        #endregion
        #region Abstract methods
        /// 
        /// Performs the arrange pass layout of the item when
        /// the final position and size of the item has been set.
        /// 
        /// Layout information.
        /// 
        /// 
        protected abstract void ArrangeOverride(
            GridLayoutInfo layoutInfo, GridLayoutStateInfo stateInfo, Rectangle layoutBounds);
        /// 
        /// Performs the layout of the item
        /// and sets the Size property to size that item will take.
        /// 
        /// Layout information.
        /// 
        /// 
        protected abstract void MeasureOverride(
            GridLayoutInfo layoutInfo, GridLayoutStateInfo stateInfo, Size constraintSize);
        /// 
        /// Performs drawing of the item and its children.
        /// 
        /// Holds contextual rendering information.
        protected abstract void RenderOverride(GridRenderInfo renderInfo);
        #endregion
        #region Internal properties
        #region Capture
        internal virtual bool Capture
        {
            get { return (CapturedItem != null); }
            set
            {
                if (SuperGrid != null)
                    CapturedItem = (value == true) ? this : null;
            }
        }
        #endregion
        #region CapturedItem
        internal GridElement CapturedItem
        {
            get
            {
                if (SuperGrid != null)
                    return (SuperGrid.CapturedItem);
                return (null);
            }
            set
            {
                if (SuperGrid != null)
                    SuperGrid.CapturedItem = value;
            }
        }
        #endregion
        #region CViewRect
        /// 
        /// Client View Rectangle
        /// 
        internal Rectangle CViewRect
        {
            get
            {
                if (SuperGrid != null)
                    return (SuperGrid.CViewRect);
                return (Rectangle.Empty);
            }
        }
        #endregion
        #region HScrollBounds
        /// 
        /// Horizontal Scroll Bounds
        /// 
        internal Rectangle HScrollBounds
        {
            get
            {
                Rectangle r = BoundsRelative;
                r.X -= HScrollOffset;
                return (r);
            }
        }
        #endregion
        #region HScrollOffset
        internal int HScrollOffset
        {
            get
            {
                SuperGridControl sgc = SuperGrid;
                return (sgc != null)
                    ? sgc.HScrollOffset : 0;
            }
        }
        #endregion
        #region IsMouseDown
        /// 
        /// Gets whether mouse is down
        /// 
        internal virtual bool IsMouseDown
        {
            get { return (Control.MouseButtons != MouseButtons.None); }
        }
        #endregion
        #region IsVFrozen
        ///
        /// IsFrozen
        ///
        internal bool IsVFrozen
        {
            get
            {
                if (SuperGrid != null)
                {
                    GridPanel panel = SuperGrid.PrimaryGrid;
                    return (BoundsRelative.Y < panel.FixedRowHeight);
                }
                return (false);
            }
        }
        #endregion
        #region MouseDownPoint
        /// 
        /// Gets the mouse down Point
        /// 
        internal virtual Point MouseDownPoint
        {
            get { return (_mouseDownPoint); }
            set { _mouseDownPoint = value; }
        }
        #endregion
        #region NeedsMeasured
        /// 
        /// Get or sets whether item needs measured
        /// 
        internal virtual bool NeedsMeasured
        {
            get { return (TestState(Es.NeedsMeasured)); }
            set { SetState(Es.NeedsMeasured, value); }
        }
        #endregion
        #region ScrollBounds
        /// 
        /// Horizontal and Vertical Scroll Bounds
        /// 
        internal Rectangle ScrollBounds
        {
            get
            {
                Rectangle r = BoundsRelative;
                r.X -= HScrollOffset;
                r.Y -= VScrollOffset;
                return (r);
            }
        }
        #endregion
        #region SViewRect
        /// 
        /// Scrollable View Rectangle
        /// 
        internal Rectangle SViewRect
        {
            get
            {
                if (SuperGrid != null)
                    return (SuperGrid.SViewRect);
                return (Rectangle.Empty);
            }
        }
        #endregion
        #region ViewRect
        /// 
        /// View Rectangle
        /// 
        internal Rectangle ViewRect
        {
            get
            {
                if (SuperGrid != null)
                    return (SuperGrid.ViewRect);
                return (Rectangle.Empty);
            }
        }
        #endregion
        #region VScrollBounds
        /// 
        /// Vertical Scroll Bounds
        /// 
        internal Rectangle VScrollBounds
        {
            get
            {
                Rectangle r = BoundsRelative;
                r.Y -= VScrollOffset;
                return (r);
            }
        }
        #endregion
        #region VScrollOffset
        internal int VScrollOffset
        {
            get
            {
                SuperGridControl cgc = SuperGrid;
                return (cgc != null)
                    ? cgc.VScrollOffset : 0;
            }
        }
        #endregion
        #endregion
        #region Public properties
        #region AllowSelection
        /// 
        /// Gets or sets whether the element can be selected
        /// 
        [DefaultValue(true), Category("Behavior")]
        [Description("Indicates whether the element can be selected")]
        public virtual bool AllowSelection
        {
            get { return (TestState(Es.AllowSelection)); }
            set
            {
                if (AllowSelection != value)
                {
                    SetState(Es.AllowSelection, value);
                    OnPropertyChangedEx("AllowSelection", VisualChangeType.Render);
                }
            }
        }
        #endregion
        #region Bounds
        ///
        /// Gets the scroll adjusted bounds
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual Rectangle Bounds
        {
            get { return (BoundsRelative); }
        }
        #endregion
        #region BoundsRelative
        /// 
        /// Gets or sets the relative bounds of the item.
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual Rectangle BoundsRelative
        {
            get { return (_BoundsRelative); }
            internal set { _BoundsRelative = value; }
        }
        #endregion
        #region GridPanel
        /// 
        /// Gets the parent GridPanel
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public GridPanel GridPanel
        {
            get { return (GetParentGridPanel()); }
            internal set { _GridPanel = value; }
        }
        #region GetParentGridPanel
        private GridPanel GetParentGridPanel()
        {
            if (_GridPanel != null)
                return (_GridPanel);
            GridElement parent = this;
            while (parent != null)
            {
                if (parent is GridPanel)
                    return ((GridPanel)parent);
                parent = parent.Parent;
            }
            return (null);
        }
        #endregion
        #endregion
        #region IsLayoutValid
        /// 
        /// Gets whether layout for the item is valid.
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual bool IsLayoutValid
        {
            get { return (TestState(Es.LayoutValid)); }
            internal set { SetState(Es.LayoutValid, value); }
        }
        #endregion
        #region IsMouseOver
        /// 
        /// Gets whether mouse is over the element.
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual bool IsMouseOver
        {
            get { return (TestState(Es.MouseOver)); }
            internal set { SetState(Es.MouseOver, value); }
        }
        #endregion
        #region LocationRelative
        /// 
        /// Gets or sets the relative location of the item.
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Point LocationRelative
        {
            get { return _BoundsRelative.Location; }
            internal set { _BoundsRelative.Location = value; }
        }
        #endregion
        #region Parent
        /// 
        /// Gets or sets the parent of the item.
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual GridElement Parent
        {
            get { return (_Parent); }
            internal set
            {
                if (_Parent != value)
                {
                    GridElement oldParent = value;
                    _Parent = value;
                    if (value == null)
                    {
                        if (SuperGrid != null)
                        {
                            if (SuperGrid.ActiveElement == this)
                                SuperGrid.ActiveElement = null;
                        }
                    }                        
                    OnParentChanged(oldParent, value);
                }
            }
        }
        #endregion
        #region Size
        /// 
        /// Gets or sets the Size of the item.
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Size Size
        {
            get { return (_BoundsRelative.Size); }
            internal set { _BoundsRelative.Size = value; }
        }
        #endregion
        #region SuperGrid
        /// 
        /// Gets the parent super grid control.
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public SuperGridControl SuperGrid
        {
            get { return GetParentSuperGrid(); }
            internal set { _SuperGrid = value; }
        }
        #region GetParentSuperGrid
        private SuperGridControl GetParentSuperGrid()
        {
            if (_SuperGrid != null)
                return (_SuperGrid);
            GridElement parent = _Parent;
            while (parent != null)
            {
                if (parent.SuperGrid != null)
                    return (_SuperGrid = parent.SuperGrid);
                parent = parent.Parent;
            }
            return (null);
        }
        #endregion
        #endregion
        #region Tag
        ///
        /// Gets or sets user-defined data associated with the object
        ///
        [DefaultValue(null)]
        [Description("User-defined data associated with the object")]
        [TypeConverter(typeof(StringConverter))]
        public object Tag
        {
            get { return (_Tag); }
            set { _Tag = value; }
        }
        #endregion
        #region Visible
        /// 
        /// Get or sets whether the item is visible
        /// 
        [DefaultValue(true), Category("Appearance")]
        [Description("Indicates whether item is visible")]
        public virtual bool Visible
        {
            get { return (TestState(Es.Visible)); }
            set
            {
                if (Visible != value)
                {
                    SetState(Es.Visible, value);
                    OnPropertyChangedEx("Visible", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #endregion
        #region TestState
        private bool TestState(Es state)
        {
            return ((_States & state) == state);
        }
        #endregion
        #region SetState
        private void SetState(Es state, bool value)
        {
            if (value == true)
                _States |= state;
            else
                _States &= ~state;
        }
        #endregion
        #region OnEvent processing
        #region OnLayoutInvalid
        /// 
        /// Raises LayoutInvalid event.
        /// 
        /// Provides event arguments.
        protected virtual void OnLayoutInvalid(EventArgs e)
        {
            EventHandler handler = LayoutInvalid;
            if (handler != null)
                handler(this, e);
        }
        #endregion
        #region OnParentChanged
        /// 
        /// Called after parent of the item has changed.
        /// 
        /// Reference to old parent.
        /// Reference to new parent.
        protected virtual void OnParentChanged(GridElement oldParent, GridElement newParent)
        {
            OnParentChanged(EventArgs.Empty);
        }
        /// 
        /// Raises ParentChanged event.
        /// 
        /// Provides event arguments.
        protected virtual void OnParentChanged(EventArgs e)
        {
            EventHandler handler = ParentChanged;
            if (handler != null)
                handler(this, e);
        }
        #endregion
        #region OnRenderInvalid
        /// 
        /// Raises RenderInvalid event.
        /// 
        /// Provides event arguments.
        protected virtual void OnRenderInvalid(EventArgs e)
        {
            EventHandler handler = RenderInvalid;
            if (handler != null)
                handler(this, e);
        }
        #endregion
        #endregion
        #region Measure
        /// 
        /// This method is used by the items internally to invoke the measure pass to
        /// get item size. Override MeasureOverride method to perform actual measuring.
        /// 
        /// Holds contextual layout information.
        /// 
        /// 
        internal void Measure(
            GridLayoutInfo layoutInfo, GridLayoutStateInfo stateInfo, Size constraintSize)
        {
            MeasureOverride(layoutInfo, stateInfo, constraintSize);
            NeedsMeasured = false;
        }
        #endregion
        #region Arrange
        /// 
        /// This method is used by the items internally to invoke the arrange pass after
        /// location and size of the item has been set. Override ArrangeOverride method
        /// to perform internal arranging.
        /// 
        /// 
        /// 
        /// 
        internal void Arrange(
            GridLayoutInfo layoutInfo, GridLayoutStateInfo stateInfo, Rectangle layoutBounds)
        {
            IsLayoutValid = true;
            _BoundsRelative = layoutBounds;
            ArrangeOverride(layoutInfo, stateInfo, layoutBounds);
        }
        #endregion
        #region Render
        /// 
        /// This method is used by the items internally to invoke the rendering
        /// for the item. Override RenderOverride method to perform actual rendering.
        /// 
        /// Holds contextual rendering information.
        internal void Render(GridRenderInfo renderInfo)
        {
            RenderOverride(renderInfo);
        }
        #endregion
        #region InvalidateLayout
        /// 
        /// Invalidates the layout for the item.
        /// 
        public virtual void InvalidateLayout()
        {
            IsLayoutValid = false;
            if (_Parent != null)
            {
                _Parent.InvalidateLayout();
            }
            else
            {
                if (SuperGrid != null)
                    SuperGrid.Invalidate();
            }
            OnLayoutInvalid(EventArgs.Empty);
        }
        #endregion
        #region InvalidateRender
        /// 
        /// Invalidates the display state of the item
        /// 
        public virtual void InvalidateRender()
        {
            SuperGridControl grid = SuperGrid;
            if (grid != null)
            {
                if (grid.InvokeRequired)
                    grid.BeginInvoke(new MethodInvoker(delegate { grid.InvalidateRender(this); }));
                else
                    grid.InvalidateRender(this);
            }
            
            OnRenderInvalid(EventArgs.Empty);
        }
        /// 
        /// Invalidates the display state of the item
        /// 
        public virtual void InvalidateRender(Rectangle bounds)
        {
            SuperGridControl grid = SuperGrid;
            if (grid != null)
                grid.InvalidateRender(bounds);
            OnRenderInvalid(EventArgs.Empty);
        }
        #endregion
        #region Mouse Handling
        #region OnMouseEnter
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal virtual void InternalMouseEnter(EventArgs e)
        {
            IsMouseOver = true;
            OnMouseEnter(e);
        }
        /// 
        /// Called when mouse enter the element.
        /// 
        /// 
        protected virtual void OnMouseEnter(EventArgs e)
        {
        }
        #endregion
        #region OnMouseLeave
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal virtual void InternalMouseLeave(EventArgs e)
        {
            IsMouseOver = false;
            OnMouseLeave(e);
        }
        /// 
        /// Called when mouse leaves the element.
        /// 
        /// 
        protected virtual void OnMouseLeave(EventArgs e)
        {
        }
        #endregion
        #region OnMouseHover
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal virtual void InternalMouseHover(EventArgs e)
        {
            OnMouseHover(e);
        }
        /// 
        /// Called when mouse hovers over the element.
        /// 
        /// 
        protected virtual void OnMouseHover(EventArgs e)
        {
        }
        #endregion
        #region OnMouseDown
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal virtual void InternalMouseDown(MouseEventArgs e)
        {
            MouseDownPoint = e.Location;
            OnMouseDown(e);
        }
        /// 
        /// Called when mouse button is pressed over the element.
        /// 
        /// 
        protected virtual void OnMouseDown(MouseEventArgs e)
        {
        }
        #endregion
        #region OnMouseUp
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal virtual void InternalMouseUp(MouseEventArgs e)
        {
            Capture = false;
            OnMouseUp(e);
        }
        /// 
        /// Called when mouse button is released over the element.
        /// 
        /// 
        protected virtual void OnMouseUp(MouseEventArgs e)
        {
        }
        #endregion
        #region OnMouseMove
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal virtual void InternalMouseMove(MouseEventArgs e)
        {
            OnMouseMove(e);
        }
        /// 
        /// Called when mouse is moved over the element.
        /// 
        /// 
        protected virtual void OnMouseMove(MouseEventArgs e)
        {
        }
        #endregion
        #region OnMouseClick
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal virtual void InternalMouseClick(MouseEventArgs e)
        {
            OnMouseClick(e);
        }
        /// 
        /// Called when mouse is clicked on the element.
        /// 
        /// 
        protected virtual void OnMouseClick(MouseEventArgs e)
        {
        }
        #endregion
        #region OnMouseDoubleClick
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal virtual void InternalMouseDoubleClick(MouseEventArgs e)
        {
            OnMouseDoubleClick(e);
        }
        /// 
        /// Called when mouse is double clicked on the element.
        /// 
        /// 
        protected virtual void OnMouseDoubleClick(MouseEventArgs e)
        {
        }
        #endregion
        #region PostInternalMouseMove
        internal void PostInternalMouseMove()
        {
            SuperGrid.PostInternalMouseMove();
        }
        #endregion
        #endregion
        #region Keyboard handling
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal virtual void InternalKeyDown(Keys keyData)
        {
            OnKeyDown(keyData);
        }
        /// 
        /// Called when mouse button is pressed over the element.
        /// 
        /// 
        protected virtual void OnKeyDown(Keys keyData)
        {
        }
        #endregion
        #region EnsureVisible
        ///
        /// EnsureVisible
        ///
        public void EnsureVisible()
        {
            EnsureVisible(false);
        }
        ///
        /// EnsureVisible
        ///
        ///
        public virtual void EnsureVisible(bool center)
        {
        }
        #endregion
        #region CancelCapture
        ///
        /// Cancels any inprogress operations that may
        /// have the mouse captured (resize, reorder).
        ///
        public virtual void CancelCapture()
        {
            if (CapturedItem == this)
                Capture = false;
        }
        #endregion
        #region IsDesignerHosted
        internal bool IsDesignerHosted
        {
            get
            {
                if (SuperGrid != null)
                    return (SuperGrid.IsDesignerHosted);
                return (false);
            }
        }
        #endregion
        #region INotifyPropertyChanged Members
        /// 
        /// Occurs when property value has changed.
        /// 
        public event PropertyChangedEventHandler PropertyChanged;
        /// 
        /// Raises the PropertyChanged event.
        /// 
        /// Event arguments
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler eh = PropertyChanged;
            if (eh != null)
                eh(this, e);
        }
        /// 
        /// Default PropertyChanged processing
        /// 
        /// 
        protected void OnPropertyChanged(string s)
        {
            if (PropertyChanged != null)
                OnPropertyChanged(new PropertyChangedEventArgs(s));
        }
        /// 
        /// Default PropertyChanged processing
        /// 
        /// 
        /// invalidate
        protected void OnPropertyChangedEx(string s, VisualChangeType changeType)
        {
            OnPropertyChanged(s);
            if (changeType == VisualChangeType.Layout)
                InvalidateLayout();
            else
                InvalidateRender();
        }
        #endregion
        #region ElementStates
        [Flags]
        private enum Es
        {
            AllowSelection = (1 << 0),
            LayoutValid = (1 << 1),
            MouseOver = (1 << 2),
            NeedsMeasured = (1 << 3),
            Visible = (1 << 4),
        }
        #endregion
    }
}