using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Drawing.Imaging;
using DevComponents.DotNetBar.Rendering;
namespace DevComponents.DotNetBar
{
    [ToolboxItem(false)]
    public class RadialMenuPopup : Control
    {
        #region Constructor
        /// 
        /// Initializes a new instance of the RadialMenuPopup class.
        /// 
        public RadialMenuPopup()
        {
            //this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            this.Text = "RadialMenuPopup";
            //this.ShowInTaskbar = false;
            this.SetStyle(ControlStyles.Selectable, false);
            //this.StartPosition = FormStartPosition.Manual;
            //this.TopMost = true;
        }
        protected override void OnLocationChanged(EventArgs e)
        {
            base.OnLocationChanged(e);
        }
        #endregion
        #region Implementation
        private bool _Painting = false;
        protected override void OnInvalidated(InvalidateEventArgs e)
        {
            if (!this.IsHandleCreated || this.IsDisposed || _DisplayItem == null || _Painting) return;
            _Painting = true;
            try
            {
                if (_DisplayItem.NeedRecalcSize)
                    _DisplayItem.RecalcSize();
                Bitmap oldContent = this.ContentImage;
                Bitmap b = null;
                bool clearBitmap = false;
                if (oldContent != null && oldContent.Width == _DisplayItem.WidthInternal && oldContent.Height == _DisplayItem.HeightInternal)
                {
                    b = oldContent;
                    clearBitmap = true;
                }
                else
                {
                    if (oldContent != null) oldContent.Dispose();
                    b = new Bitmap(_DisplayItem.WidthInternal, _DisplayItem.HeightInternal, PixelFormat.Format32bppArgb);
                }
                using (Graphics g = Graphics.FromImage(b))
                {
                    if (clearBitmap) g.Clear(Color.Transparent);
                    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                    g.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint;
                    ItemPaintArgs p = GetItemPaintArgs(g);
                    _DisplayItem.Paint(p);
                }
                this.ContentImage = b;
                //if (oldContent != null) oldContent.Dispose();
            }
            finally
            {
                _Painting = false;
            }
            base.OnInvalidated(e);
        }
        internal ItemPaintArgs GetItemPaintArgs(System.Drawing.Graphics g)
        {
            ItemPaintArgs pa = new ItemPaintArgs(this as IOwner, this, g, GetColorScheme());
            pa.Renderer = this.GetRenderer();
            if (_DisplayItem.DesignMode)
            {
                ISite site = this.GetSite();
                if (site != null && site.DesignMode)
                    pa.DesignerSelection = true;
            }
            pa.GlassEnabled = !this.DesignMode && WinApi.IsGlassEnabled;
            return pa;
        }
        private ISite GetSite()
        {
            ISite site = null;
            if (site == null && _DisplayItem != null)
            {
                BaseItem item = _DisplayItem;
                while (site == null && item != null)
                {
                    if (item.Site != null && item.Site.DesignMode)
                        site = item.Site;
                    else
                        item = item.Parent;
                }
            }
            return site;
        }
        private RadialMenuContainer _DisplayItem;
        /// 
        /// Identifies the item displayed by this popup.
        /// 
        public RadialMenuContainer DisplayItem
        {
            get { return _DisplayItem; }
            set
            {
                if (value != _DisplayItem)
                {
                    RadialMenuContainer oldValue = _DisplayItem;
                    _DisplayItem = value;
                    OnDisplayItemChanged(oldValue, value);
                }
            }
        }
        /// 
        /// Called when DisplayItem property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnDisplayItemChanged(RadialMenuContainer oldValue, RadialMenuContainer newValue)
        {
            if (oldValue != null)
                oldValue.ContainerControl = null;
            if (newValue != null)
            {
                newValue.ContainerControl = this;
            }
            this.Invalidate();
            //OnPropertyChanged(new PropertyChangedEventArgs("DisplayItem"));
        }
        const uint WS_POPUP = 0x80000000;
        const uint WS_CLIPSIBLINGS = 0x04000000;
        const uint WS_CLIPCHILDREN = 0x02000000;
        const uint WS_EX_TOPMOST = 0x00000008;
        const uint WS_EX_TOOLWINDOW = 0x00000080;
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                //cp.ExStyle |= 0x00080000; // Sets WS_EX_LAYERED extended style
                cp.Style = unchecked((int)(WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN));
                cp.ExStyle = (int)(WS_EX_TOPMOST | WS_EX_TOOLWINDOW | 0x00080000); // Sets WS_EX_LAYERED extended style
                cp.Caption = ""; // Setting caption would show window under tasks in Windows Task Manager
                return cp;
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            PaintLayeredWindow(_ContentImage);
        }
        private Bitmap _ContentImage = null;
        /// 
        /// Gets or sets the content image displayed on the window.
        /// 
        public Bitmap ContentImage
        {
            get { return _ContentImage; }
            set
            {
                _ContentImage = value;
                if (_ContentImage != null && _ContentImage.Size != this.Size)
                    this.Size = _ContentImage.Size;
                PaintLayeredWindow(_ContentImage);
            }
        }
        private void PaintLayeredWindow(Bitmap windowContentImage)
        {
            if (!this.IsHandleCreated) return;
            IntPtr screenDc = NativeFunctions.GetDC(IntPtr.Zero);
            IntPtr memDc = WinApi.CreateCompatibleDC(screenDc);
            IntPtr hBitmap = IntPtr.Zero;
            IntPtr oldBitmap = IntPtr.Zero;
            try
            {
                //Display-image
                hBitmap = windowContentImage.GetHbitmap(Color.FromArgb(0));  //Set the fact that background is transparent
                oldBitmap = WinApi.SelectObject(memDc, hBitmap);
                //Display-rectangle
                Size size = windowContentImage.Size;
                Point pointSource = new Point(0, 0);
                Point topPos = new Point(this.Left, this.Top);
                //Set up blending options
                NativeFunctions.BLENDFUNCTION blend = new NativeFunctions.BLENDFUNCTION();
                blend.BlendOp = (byte)NativeFunctions.Win23AlphaFlags.AC_SRC_OVER;
                blend.BlendFlags = 0;
                blend.SourceConstantAlpha = 255;
                blend.AlphaFormat = (byte)NativeFunctions.Win23AlphaFlags.AC_SRC_ALPHA;
                NativeFunctions.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size,
                    memDc, ref pointSource, 0, ref blend, (int)NativeFunctions.Win32UpdateLayeredWindowsFlags.ULW_ALPHA);
                //Clean-up
                WinApi.ReleaseDC(IntPtr.Zero, screenDc);
                if (hBitmap != IntPtr.Zero)
                {
                    WinApi.SelectObject(memDc, oldBitmap);
                    WinApi.DeleteObject(hBitmap);
                }
                WinApi.DeleteDC(memDc);
            }
            catch (Exception)
            {
            }
        }
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == (int)WinApi.WindowsMessages.WM_MOUSEACTIVATE)
            {
                m.Result = new System.IntPtr(NativeFunctions.MA_NOACTIVATE);
                return;
            }
            base.WndProc(ref m);
        }
        #region BaseItem Forwarding
        protected override void OnClick(EventArgs e)
        {
            Point p = this.PointToClient(MousePosition);
            InternalOnClick(MouseButtons, p);
            base.OnClick(e);
        }
        protected virtual void InternalOnClick(MouseButtons mb, Point mousePos)
        {
            _DisplayItem.InternalClick(mb, mousePos);
        }
        protected override void OnDoubleClick(EventArgs e)
        {
            _DisplayItem.InternalDoubleClick(MouseButtons, MousePosition);
            base.OnDoubleClick(e);
        }
        protected override void OnKeyDown(KeyEventArgs e)
        {
            ExKeyDown(e);
            base.OnKeyDown(e);
        }
        internal virtual void ExKeyDown(KeyEventArgs e)
        {
            _DisplayItem.InternalKeyDown(e);
        }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            _DisplayItem.InternalMouseDown(e);
            base.OnMouseDown(e);
        }
        protected override void OnMouseHover(EventArgs e)
        {
            base.OnMouseHover(e);
            _DisplayItem.InternalMouseHover();
        }
        protected override void OnMouseLeave(EventArgs e)
        {
            _DisplayItem.InternalMouseLeave();
            base.OnMouseLeave(e);
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            _DisplayItem.InternalMouseUp(e);
        }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            InternalMouseMove(e);
        }
        protected virtual void InternalMouseMove(MouseEventArgs e)
        {
            _DisplayItem.InternalMouseMove(e);
        }        
        #endregion
        #region Renderer Handling
        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_DefaultRenderer;
        }
        /// 
        /// Gets or sets the rendering 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;
            }
        }
        private ColorScheme m_ColorScheme = null;
        /// 
        /// 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()
        {
            BaseRenderer r = GetRenderer();
            if (r is Office2007Renderer)
                return ((Office2007Renderer)r).ColorTable.LegacyColors;
            if (m_ColorScheme == null)
                m_ColorScheme = new ColorScheme(eDotNetBarStyle.Metro);
            return m_ColorScheme;
        }
        #endregion
        #endregion
    }
}