using System;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using DevComponents.DotNetBar.Rendering;
using System.Reflection;
namespace DevComponents.DotNetBar
{
    /// 
    /// Represents the class for the BaseItem non-popup based control host.
    /// 
    [ToolboxItem(false)]
    public abstract class BaseItemControl : Control
    {
        #region Private Variables
        private BaseItem m_Item = null;
        private ElementStyle m_BackgroundStyle = null;
        private ColorScheme m_ColorScheme = null;
        private bool m_DesignModeInternal = false;
        private bool m_AntiAlias = true;
        #endregion
        #region Constructor Dispose
        /// 
        /// Creates new instance of the object.
        /// 
        public BaseItemControl()
        {
            if (!ColorFunctions.ColorsLoaded)
            {
                NativeFunctions.RefreshSettings();
                NativeFunctions.OnDisplayChange();
                ColorFunctions.LoadColors();
            }
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.Opaque, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.StandardDoubleClick, true);
            this.SetStyle(DisplayHelp.DoubleBufferFlag, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            m_ColorScheme = new ColorScheme(eDotNetBarStyle.Office2007);
            m_BackgroundStyle = new ElementStyle();
            m_BackgroundStyle.SetColorScheme(m_ColorScheme);
            m_BackgroundStyle.StyleChanged += new EventHandler(this.VisualPropertyChanged);
        }
        protected override void Dispose(bool disposing)
        {
            if (disposing && m_Item != null)
                m_Item.Dispose();
            base.Dispose(disposing);
        }
        #endregion
        #region Internal Implementation
        protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
        {
            if (Dpi.RecordScalePerControl)
                Dpi.SetScaling(factor);
            if (m_Item != null)
            {
                m_Item.NotifyScaleItem(factor);
                RecalcLayout();
            }
            base.ScaleControl(factor, specified);
        }
        internal bool IsValidationCancelled
        {
            get
            {
                PropertyInfo pi=this.GetType().GetProperty("ValidationCancelled", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                if (pi != null)
                    return (bool)pi.GetValue(this, null);
                return false;
            }
        }
#if FRAMEWORK20
        protected override void OnBindingContextChanged(EventArgs e)
        {
            base.OnBindingContextChanged(e);
            if (m_Item != null)
                m_Item.UpdateBindings();
        }
#endif
        protected bool GetDesignMode()
        {
            if (!m_DesignModeInternal)
                return this.DesignMode;
            return m_DesignModeInternal;
        }
        protected virtual ElementStyle GetBackgroundStyle()
        {
            return m_BackgroundStyle;
        }
        internal void SetDesignMode(bool mode)
        {
            m_DesignModeInternal = mode;
            if(m_Item!=null)
                m_Item.SetDesignMode(mode);
        }
        /// 
        /// Gets or sets the instance of BaseItem object hosted by this control.
        /// 
        protected virtual BaseItem HostItem
        {
            get { return m_Item; }
            set
            {
                m_Item = value;
                if (m_Item != null)
                {
                    m_Item.Displayed = true;
                    m_Item.ContainerControl = this;
                }
            }
        }
        /// 
        /// Returns the color scheme used by control. Color scheme for Office2007 style will be retrieved from the current renderer instead of
        /// local color scheme referenced by ColorScheme property.
        /// 
        /// An instance of ColorScheme object.
        protected virtual ColorScheme GetColorScheme()
        {
            if (m_Item != null && BarFunctions.IsOffice2007Style(m_Item.EffectiveStyle))
            {
                BaseRenderer r = GetRenderer();
                if (r is Office2007Renderer)
                    return ((Office2007Renderer)r).ColorTable.LegacyColors;
            }
            return m_ColorScheme;
        }
        private bool _CallBasePaintBackground = true;
        /// 
        /// Gets or sets whether during painting OnPaintBackground on base control is called when BackColor=Transparent.
        /// 
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool CallBasePaintBackground
        {
            get { return _CallBasePaintBackground; }
            set
            {
                _CallBasePaintBackground = value;
            }
        }
        internal void InternalPaint(PaintEventArgs e)
        {
            OnPaint(e);
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            if ((this.BackColor.IsEmpty || this.BackColor == Color.Transparent) && _CallBasePaintBackground)
            {
                base.OnPaintBackground(e);
            }
            if (m_BackgroundStyle != null)
                m_BackgroundStyle.SetColorScheme(this.GetColorScheme());
            PaintBackground(e);
            PaintControl(e);
            if (this.Focused && /*this.ShowFocusCues &&*/ this.FocusCuesEnabled)
            {
                PaintFocusCues(e);
            }
            base.OnPaint(e);
        }
        private bool _FocusCuesEnabled = true;
        /// 
        /// Gets or sets whether control displays focus cues when focused.
        /// 
        [DefaultValue(true), Category("Behavior"), Description("Indicates whether control displays focus cues when focused.")]
        public virtual bool FocusCuesEnabled
        {
            get { return _FocusCuesEnabled; }
            set
            {
                _FocusCuesEnabled = value;
                if (this.Focused) this.Invalidate();
            }
        }
        /// 
        /// Paints the control focus cues.
        /// 
        /// Paint event information.
        protected virtual void PaintFocusCues(PaintEventArgs e)
        {
            ControlPaint.DrawFocusRectangle(e.Graphics, this.ClientRectangle);
        }
        protected virtual void PaintBackground(PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            Rectangle r = this.ClientRectangle;
            ElementStyle style = this.GetBackgroundStyle();
            if (!this.BackColor.IsEmpty && this.BackColor != Color.Transparent)
            {
                DisplayHelp.FillRectangle(g, r, this.BackColor);
            }
            if (this.BackgroundImage != null)
                base.OnPaintBackground(e);
            if (style.Custom)
            {
                SmoothingMode sm = g.SmoothingMode;
                if (m_AntiAlias)
                    g.SmoothingMode = SmoothingMode.HighQuality;
                ElementStyleDisplayInfo displayInfo = new ElementStyleDisplayInfo(style, e.Graphics, r);
                ElementStyleDisplay.Paint(displayInfo);
                if (m_AntiAlias)
                    g.SmoothingMode = sm;
            }
        }
        protected virtual void PaintControl(PaintEventArgs e)
        {
            SmoothingMode sm = e.Graphics.SmoothingMode;
            TextRenderingHint th = e.Graphics.TextRenderingHint;
            Graphics g = e.Graphics;
            if (m_AntiAlias)
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint;
            }
            ItemPaintArgs pa = GetItemPaintArgs(g);
            pa.ClipRectangle = e.ClipRectangle;
            if (m_Item != null) m_Item.Paint(pa);
            
            if (m_AntiAlias)
            {
                g.SmoothingMode = sm;
                g.TextRenderingHint = th;
            }
        }
        /// 
        /// Creates the Graphics object for the control.
        /// 
        /// The Graphics object for the control.
        public new Graphics CreateGraphics()
        {
            Graphics g = base.CreateGraphics();
            if (m_AntiAlias)
            {
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                #if FRAMEWORK20
                if (!SystemInformation.IsFontSmoothingEnabled)
                #endif
                    g.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint;
            }
            return g;
        }
        protected virtual ItemPaintArgs GetItemPaintArgs(Graphics g)
        {
            ItemPaintArgs pa = new ItemPaintArgs(this as IOwner, this, g, GetColorScheme());
            pa.Renderer = this.GetRenderer();
            pa.DesignerSelection = false;
            pa.GlassEnabled = !this.DesignMode && WinApi.IsGlassEnabled;
            return pa;
        }
        private Rendering.BaseRenderer m_DefaultRenderer = null;
        private Rendering.BaseRenderer m_Renderer = null;
        private eRenderMode m_RenderMode = eRenderMode.Global;
        /// 
        /// Returns the renderer control will be rendered with.
        /// 
        /// The current renderer.
        public virtual Rendering.BaseRenderer GetRenderer()
        {
            if (m_RenderMode == eRenderMode.Global && Rendering.GlobalManager.Renderer != null)
                return Rendering.GlobalManager.Renderer;
            else if (m_RenderMode == eRenderMode.Custom && m_Renderer != null)
                return m_Renderer;
            if (m_DefaultRenderer == null)
                m_DefaultRenderer = new Rendering.Office2007Renderer();
            return m_Renderer;
        }
        /// 
        /// Gets or sets the redering mode used by control. Default value is eRenderMode.Global which means that static GlobalManager.Renderer is used. If set to Custom then Renderer property must
        /// also be set to the custom renderer that will be used.
        /// 
        [Browsable(false), DefaultValue(eRenderMode.Global)]
        public eRenderMode RenderMode
        {
            get { return m_RenderMode; }
            set
            {
                if (m_RenderMode != value)
                {
                    m_RenderMode = value;
                    this.Invalidate(true);
                }
            }
        }
        /// 
        /// Gets or sets the custom renderer used by the items on this control. RenderMode property must also be set to eRenderMode.Custom in order renderer
        /// specified here to be used.
        /// 
        [Browsable(false), DefaultValue(null)]
        public DevComponents.DotNetBar.Rendering.BaseRenderer Renderer
        {
            get
            {
                return m_Renderer;
            }
            set { m_Renderer = value; }
        }
        /// 
        /// Specifies the background style of the control.
        /// 
        [Browsable(true), DevCoBrowsable(true), Category("Style"), Description("Gets or sets bar background style."), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ElementStyle BackgroundStyle
        {
            get { return m_BackgroundStyle; }
        }
        /// 
        /// Resets style to default value. Used by windows forms designer.
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public void ResetBackgroundStyle()
        {
            m_BackgroundStyle.StyleChanged -= new EventHandler(this.VisualPropertyChanged);
            m_BackgroundStyle = new ElementStyle();
            m_BackgroundStyle.StyleChanged += new EventHandler(this.VisualPropertyChanged);
            OnBackgroundStyleChanged();
            this.Invalidate();
        }
        protected virtual void OnBackgroundStyleChanged()
        {
        }
        private void VisualPropertyChanged(object sender, EventArgs e)
        {
            OnVisualPropertyChanged();
        }
        /// 
        /// Called when visual property of the control has changed so the control can be updated.
        /// 
        protected virtual void OnVisualPropertyChanged()
        {
            if (this.GetDesignMode() ||
                this.Parent != null && this.Parent.Site != null && this.Parent.Site.DesignMode)
            {
                this.RecalcLayout();
            }
        }
        /// 
        /// Gets or sets Bar Color Scheme.
        /// 
        [Browsable(false), DevCoBrowsable(false), Category("Appearance"), Description("Gets or sets Bar Color Scheme."), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ColorScheme ColorScheme
        {
            get { return m_ColorScheme; }
            set
            {
                if (value == null)
                    throw new ArgumentException("NULL is not a valid value for this property.");
                m_ColorScheme = value;
                if (this.Visible)
                    this.Refresh();
            }
        }
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeColorScheme()
        {
            return m_ColorScheme.SchemeChanged;
        }
        /// 
        /// Gets or sets whether anti-alias smoothing is used while painting. Default value is false.
        /// 
        [DefaultValue(true), Browsable(true), Category("Appearance"), Description("Gets or sets whether anti-aliasing is used while painting.")]
        public bool AntiAlias
        {
            get { return m_AntiAlias; }
            set
            {
                if (m_AntiAlias != value)
                {
                    m_AntiAlias = value;
                    this.Invalidate();
                }
            }
        }
        protected override void OnParentChanged(EventArgs e)
        {
            base.OnParentChanged(e);
            //if (this.Parent != null && (this.Images != null || this.ImagesLarge != null || this.ImagesMedium != null))
            //{
            //    foreach (BaseItem panel in m_BaseItemContainer.SubItems)
            //    {
            //        foreach (BaseItem item in panel.SubItems)
            //        {
            //            if (item is ImageItem)
            //                ((ImageItem)item).OnImageChanged();
            //        }
            //    }
            //}
            if (this.DesignMode && m_Item!=null)
                m_Item.SetDesignMode(this.DesignMode);
        }
        /// 
        /// Forces the button to perform internal layout.
        /// 
        public virtual void RecalcLayout()
        {
            if (m_Item == null) return;
            Rectangle r = GetItemBounds();
            m_Item.Bounds = r;
            this.RecalcSize();
            m_Item.Bounds = r;
            this.Invalidate();
        }
        /// 
        /// Recalculates the size of the internal item.
        /// 
        protected virtual void RecalcSize()
        {
            m_Item.RecalcSize();
        }
        protected virtual Rectangle GetItemBounds()
        {
            Rectangle r = this.ClientRectangle;
            r.X += ElementStyleLayout.LeftWhiteSpace(this.BackgroundStyle);
            r.Width -= ElementStyleLayout.HorizontalStyleWhiteSpace(this.BackgroundStyle);
            r.Y += ElementStyleLayout.TopWhiteSpace(this.BackgroundStyle);
            r.Height -= ElementStyleLayout.VerticalStyleWhiteSpace(this.BackgroundStyle);
            return r;
        }
        protected override void OnResize(EventArgs e)
        {
            RecalcLayout();
            base.OnResize(e);
        }
        protected override void OnTextChanged(EventArgs e)
        {
            m_Item.Text = this.Text;
            this.RecalcLayout();
            base.OnTextChanged(e);
        }
        protected override void OnFontChanged(EventArgs e)
        {
            base.OnFontChanged(e);
            BarUtilities.InvalidateFontChange(m_Item);
            this.RecalcLayout();
        }
        protected override void OnEnabledChanged(EventArgs e)
        {
            m_Item.Enabled = this.Enabled;
            base.OnEnabledChanged(e);
        }
        private bool m_MouseFocus = false;
        protected override void OnGotFocus(EventArgs e)
        {
            if (!m_MouseFocus)
                m_Item.OnGotFocus();
            m_MouseFocus = false;
            base.OnGotFocus(e);
        }
        protected override void OnLostFocus(EventArgs e)
        {
            m_Item.OnLostFocus();
            base.OnLostFocus(e);
        }
        protected override void OnMouseEnter(EventArgs e)
        {
            m_Item.InternalMouseEnter();
            base.OnMouseEnter(e);
        }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            m_Item.InternalMouseMove(e);
            base.OnMouseMove(e);
        }
        protected override void OnMouseLeave(EventArgs e)
        {
            m_Item.InternalMouseLeave();
            base.OnMouseLeave(e);
        }
        protected override void OnMouseHover(EventArgs e)
        {
            m_Item.InternalMouseHover();
            base.OnMouseHover(e);
        }
        protected virtual MouseButtons MouseDownFocusButtons
        {
            get { return MouseButtons.Left; }
        }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            if ((e.Button & MouseDownFocusButtons) != 0)
            {
                if (!this.Focused && this.GetStyle(ControlStyles.Selectable))
                {
                    m_MouseFocus = true;
                    this.Select();
                }
            }
            m_Item.InternalMouseDown(e);
            base.OnMouseDown(e);
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            m_Item.InternalMouseUp(e);
            base.OnMouseUp(e);
        }
        protected override void OnClick(EventArgs e)
        {
            m_Item.InternalClick(Control.MouseButtons, this.PointToClient(Control.MousePosition));
            base.OnClick(e);
        }
        protected override void OnDoubleClick(EventArgs e)
        {
            m_Item.InternalDoubleClick(Control.MouseButtons, this.PointToClient(Control.MousePosition));
            base.OnDoubleClick(e);
        }
        protected override void OnKeyDown(KeyEventArgs e)
        {
            m_Item.InternalKeyDown(e);
            base.OnKeyDown(e);
        }
        /// 
        /// Gets/Sets the visual style for the control.
        /// 
        [Browsable(true), Category("Appearance"), Description("Specifies the visual style of the control."), DefaultValue(eDotNetBarStyle.Office2007)]
        public virtual eDotNetBarStyle Style
        {
            get
            {
                return m_Item.Style;
            }
            set
            {
                m_Item.Style = value;
                if(!BarFunctions.IsOffice2007Style(value))
                    this.GetColorScheme().Style = value;
                this.RecalcLayout();
            }
        }
        protected override bool ProcessMnemonic(char charCode)
        {
            if (IsMnemonic(charCode, m_Item.Text))
            {
                if (ProcessAccelerator())
                    return true;
            }
            return base.ProcessMnemonic(charCode);
        }
        protected virtual bool ProcessAccelerator()
        {
            m_Item.RaiseClick(eEventSource.Keyboard);
            return true;
        }
        #endregion
        #region Layout Support
        private int m_UpdateSuspendCount = 0;
        /// 
        /// Indicates to control that all further update operations should not result in layout and refresh of control content.
        /// Use this method to optimize the addition of new items to the control. This method supports nested calls meaning
        /// that multiple calls are allowed but they must be ended with appropriate number of EndUpdate calls.
        /// IsUpdateSuspended property returns whether update is suspended.
        /// 
        public void BeginUpdate()
        {
            m_UpdateSuspendCount++;
        }
        /// 
        /// Indicates that update operation is complete and that control should perform layout and refresh to show changes. See BeginUpdate
        /// for more details.
        /// 
        public void EndUpdate()
        {
            EndUpdate(true);
        }
        /// 
        /// Indicates that update operation is complete and that control should perform layout and refresh to show changes. See BeginUpdate
        /// for more details.
        /// 
        public void EndUpdate(bool callRecalcLayout)
        {
            if (m_UpdateSuspendCount > 0)
            {
                m_UpdateSuspendCount--;
                if (m_UpdateSuspendCount == 0 && callRecalcLayout)
                    this.RecalcLayout();
            }
        }
        /// 
        /// Gets whether control layout is suspended becouse of the call to BeginUpdate method.
        /// 
        [Browsable(false)]
        public bool IsUpdateSuspended
        {
            get { return m_UpdateSuspendCount > 0; }
        }
        #endregion
    }
}