namespace DevComponents.DotNetBar
{
    using System;
	using System.Windows.Forms;
	using System.Drawing;
	using System.Drawing.Text;
    using System.Drawing.Drawing2D;
    /// 
    ///    Summary description for Tooltip.
    /// 
    [System.ComponentModel.ToolboxItem(false),System.ComponentModel.DesignTimeVisible(false)]
    public class ToolTip : System.Windows.Forms.Control
    {
		const long WS_POPUP=0x80000000L;
		const long WS_CLIPSIBLINGS=0x04000000L;
		const long WS_CLIPCHILDREN=0x02000000L;
		const long WS_EX_TOOLWINDOW=0x00000080L;
		const long WS_EX_TOPMOST=0x00000008L;
		// When set to true tooltip will be shown Immediately without delay
		//static bool bShowToolTip;
		
		private string m_ToolTip;
        private TextMarkup.BodyElement m_TextMarkup = null;
        private eDotNetBarStyle m_Style = eDotNetBarStyle.Office2003;
		private PopupShadow m_DropShadow=null;
        private bool m_AntiAlias = false;
        /// 
        /// Gets or sets the rectangle of the control or item tooltip is displayed for.
        /// 
        public Rectangle ReferenceRectangle = Rectangle.Empty;
        public ToolTip()
        {
			m_ToolTip="";
			this.SetStyle(ControlStyles.Selectable,false);
			this.SetStyle(ControlStyles.AllPaintingInWmPaint,true);
			this.SetStyle(ControlStyles.Opaque,true);
			this.SetStyle(ControlStyles.ResizeRedraw,true);
            this.Font = SystemFonts.DefaultFont; // System.Windows.Forms.SystemInformation.MenuFont.Clone() as Font;
			this.BackColor=SystemColors.Control;
			this.ForeColor=SystemColors.ControlText;
        }
        
        public new string Text
		{
			get
			{
				return m_ToolTip;
			}
			set
			{
				m_ToolTip=value;
                if (MarkupEnabled && TextMarkup.MarkupParser.IsMarkup(ref m_ToolTip))
                    m_TextMarkup = TextMarkup.MarkupParser.Parse(m_ToolTip);
                else
                    m_TextMarkup = null;
                if (m_TextMarkup != null)
                    AntiAlias = true;
                if (_TooltipShown)
                {
                    UpdateSize();
                }
			}
		}
        private static bool _MarkupEnabled = true;
        /// 
        /// Gets or sets whether text-markup is enabled for the tooltips.
        /// 
        public static bool MarkupEnabled
        {
            get { return _MarkupEnabled; }
            set
            {
                _MarkupEnabled = value;
            }
        }
        
        public bool AntiAlias
        {
            get { return m_AntiAlias; }
            set { m_AntiAlias = value; }
        }
        private int _ColorDepth = -1;
		protected override void OnPaint(PaintEventArgs e)
		{
            // Get the Color of ToolTip text
            Color textColor = SystemColors.InfoText;
            Color backColor = SystemColors.Info;
            Color backColor2=Color.Empty;
            Color borderColor = ColorScheme.GetColor("767676");
            if (_ColorDepth == -1)
            {
                _ColorDepth = Screen.FromControl(this).BitsPerPixel;
            }
            if (_ColorDepth < 8)
            {
                backColor = Color.White;
                textColor = Color.Black;
            }
            else
            {
                if (StyleManager.IsMetro(m_Style))
                {
                    DevComponents.DotNetBar.Metro.ColorTables.MetroColorTable metroColors = DevComponents.DotNetBar.Metro.Rendering.MetroRender.GetColorTable();
                    backColor = metroColors.CanvasColor;
                    textColor = metroColors.ForeColor;
                }
                else if (BarFunctions.IsOffice2007Style(m_Style) && this.BackColor == SystemColors.Control)
                {
                    backColor = ColorScheme.GetColor("FFFFFF");
                    backColor2 = ColorScheme.GetColor("E4E4F0");
                    textColor = ColorScheme.GetColor("4C4C4C");
                }
                else
                {
                    textColor = GetToolTipColor();
                    if (this.BackColor != SystemColors.Control)
                        backColor = this.BackColor;
                }
            }
			Graphics g=e.Graphics;
			Rectangle r=this.ClientRectangle;
            if (m_AntiAlias)
            {
                g.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            }
            SmoothingMode sm = g.SmoothingMode;
            g.SmoothingMode = SmoothingMode.None;
            if (BarFunctions.IsOffice2007Style(m_Style))
            {
                DisplayHelp.DrawRectangle(g, borderColor, r);
            }
            else
            {
                System.Windows.Forms.ControlPaint.DrawBorder3D(g, r, System.Windows.Forms.Border3DStyle.Raised, System.Windows.Forms.Border3DSide.All);
            }
			
			r.Inflate(-1,-1);
            if (backColor2.IsEmpty)
                DisplayHelp.FillRectangle(g, r, backColor);
            else
                DisplayHelp.FillRectangle(g, r, backColor, backColor2);
			
			r.Offset(1,0);
            g.SmoothingMode = sm;
            if (m_TextMarkup == null)
                TextDrawing.DrawString(g, GetDrawText(), this.Font, textColor, r, GetStringFormat());
            else
            {
                TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, this.Font, textColor, (this.RightToLeft == RightToLeft.Yes), e.ClipRectangle, true);
                m_TextMarkup.Bounds = new Rectangle(r.Location, m_TextMarkup.Bounds.Size);
                m_TextMarkup.Render(d);
            }
		}
        private void UpdateSize()
        {
            // Calculate Size of the window
            using (Graphics g = this.CreateGraphics())
            {
                if (m_AntiAlias)
                {
                    g.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint;
                    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                }
                Size size = GetTooltipSize(g);
                this.Size = size;
                g.SmoothingMode = SmoothingMode.Default;
                g.TextRenderingHint = TextRenderingHint.SystemDefault;
            }
            if (!_FixedLocation.IsEmpty)
                this.Location = _FixedLocation;
            this.Invalidate();
            Rectangle r = this.Bounds;
            if (m_DropShadow != null)
            {
                NativeFunctions.SetWindowPos(m_DropShadow.Handle, this.Handle, r.Left + 5, r.Top + 5, r.Width - 2, r.Height - 2, NativeFunctions.SWP_SHOWWINDOW | NativeFunctions.SWP_NOACTIVATE);
                m_DropShadow.UpdateShadow();
            }
        }
        private bool _TooltipShown = false;
        private Size GetTooltipSize(Graphics g)
        {
            Size sz = Size.Empty;
            if (m_TextMarkup == null)
                sz = TextDrawing.MeasureString(g, GetDrawText(), this.Font, Screen.PrimaryScreen.WorkingArea.Size, GetStringFormat());
            else
            {
                TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, this.Font, SystemColors.Control, (this.RightToLeft == RightToLeft.Yes));
                m_TextMarkup.Measure(Screen.PrimaryScreen.WorkingArea.Size, d);
                sz = m_TextMarkup.Bounds.Size;
                m_TextMarkup.Arrange(new Rectangle(Point.Empty, sz), d);
            }
            sz.Width += Dpi.Width4;
            sz.Height += Dpi.Height4;
            return sz;
        }
		public void ShowToolTip()
		{
			if (!this.IsHandleCreated)
				this.CreateControl();
            
			// Calculate Size of the window
			Graphics g=this.CreateGraphics();
            if (m_AntiAlias)
            {
                g.TextRenderingHint = DisplayHelp.AntiAliasTextRenderingHint;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            }
            Size sz = Size.Empty;
            try
            {
                g.PageUnit = GraphicsUnit.Pixel;
                sz = GetTooltipSize(g);
                //if (m_TextMarkup == null)
                //    sz = TextDrawing.MeasureString(g, GetDrawText(), this.Font, Screen.PrimaryScreen.WorkingArea.Size, GetStringFormat());
                //else
                //{
                //    TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(g, this.Font, SystemColors.Control, (this.RightToLeft == RightToLeft.Yes));
                //    m_TextMarkup.Measure(Screen.PrimaryScreen.WorkingArea.Size, d);
                //    sz = m_TextMarkup.Bounds.Size;
                //    m_TextMarkup.Arrange(new Rectangle(Point.Empty, sz), d);
                //}
            }
            finally
            {
                g.SmoothingMode = SmoothingMode.Default;
                g.TextRenderingHint = TextRenderingHint.SystemDefault;
                g.Dispose();
            }
			g=null;
			Point mousePosition=System.Windows.Forms.Control.MousePosition;
			Rectangle r=new Rectangle(System.Windows.Forms.Control.MousePosition.X,System.Windows.Forms.Control.MousePosition.Y,(int)sz.Width,(int)sz.Height);
			//r.Inflate(2,2);
			r.Offset(12,24);
			ScreenInformation screen=BarFunctions.ScreenFromPoint(mousePosition);
			if(screen!=null)
			{
				System.Drawing.Size layoutArea=screen.WorkingArea.Size;
				layoutArea.Width-=(int)(layoutArea.Width*.2f);
                if (r.Right > screen.WorkingArea.Right)
                {
                    r.X = r.Left - (r.Right - screen.WorkingArea.Right);
                }
                if (r.Bottom > screen.Bounds.Bottom)
                {
                    if (ReferenceRectangle.IsEmpty)
                        r.Y = mousePosition.Y - r.Height;
                    else
                    {
                        r.Y = ReferenceRectangle.Y - r.Height - 1;
                    }
                }
				
				if(r.Contains(System.Windows.Forms.Control.MousePosition.X,System.Windows.Forms.Control.MousePosition.Y))
				{
					// We have to move it out of mouse position
                    if (r.Height + System.Windows.Forms.Control.MousePosition.Y + 1 <= screen.WorkingArea.Height && (ReferenceRectangle.IsEmpty || !ReferenceRectangle.IntersectsWith(new Rectangle(r.X, System.Windows.Forms.Control.MousePosition.Y + 1, r.Width, r.Height))))
						r.Y=System.Windows.Forms.Control.MousePosition.Y+1;
					else
						r.Y=System.Windows.Forms.Control.MousePosition.Y-r.Height-1;
				}
			}
            
            if (!_FixedLocation.IsEmpty)
                r.Location = _FixedLocation;
			this.Location=r.Location;
			this.ClientSize=r.Size;
			if(NativeFunctions.ShowDropShadow && this.ShowDropShadow)
			{
				if(m_DropShadow==null)
				{
					m_DropShadow=new PopupShadow(NativeFunctions.AlphaBlendingSupported);
					m_DropShadow.CreateControl();
				}
				//m_DropShadow.Location=new Point(r.Left+4,r.Top+4);
				//m_DropShadow.Size=r.Size;
				// TODO: Bug Cannot set size and location correctly using the Size and Location because Form caption is hidden
				m_DropShadow.Hide();
			}
			NativeFunctions.SetWindowPos(this.Handle,new IntPtr(NativeFunctions.HWND_TOP),0,0,0,0,NativeFunctions.SWP_SHOWWINDOW | NativeFunctions.SWP_NOSIZE | NativeFunctions.SWP_NOACTIVATE | NativeFunctions.SWP_NOMOVE);
			if(m_DropShadow!=null)
			{
				NativeFunctions.SetWindowPos(m_DropShadow.Handle,this.Handle,r.Left+5,r.Top+5,r.Width-2,r.Height-2,NativeFunctions.SWP_SHOWWINDOW | NativeFunctions.SWP_NOACTIVATE);
				m_DropShadow.UpdateShadow();
			}
            _TooltipShown = true;
		}
        private string GetDrawText()
        {
            string s = m_ToolTip.Replace(@"\\n", "{spec_nl}");
            s = s.Replace(@"\n", Environment.NewLine);
            return s.Replace("{spec_nl}",@"\n");
        }
		private eTextFormat GetStringFormat()
		{
            eTextFormat format = eTextFormat.Default | eTextFormat.WordBreak | eTextFormat.VerticalCenter;
            return format;
		}
		private Color GetToolTipColor()
		{
			if(this.ForeColor!=SystemColors.ControlText)
				return this.ForeColor;
			Color clrRet=SystemColors.WindowText;
			try
			{
				Microsoft.Win32.RegistryKey objReg=Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Control Panel\\Colors\\",false);
				string sColor=objReg.GetValue("InfoText").ToString();
				objReg.Close();
				objReg=null;
				
				if(sColor==null || sColor=="")
					return clrRet;
				Char [] separator = {' '};
				string[] sArr=sColor.Split(separator,3);
				if(sArr.GetUpperBound(0)==2)
					clrRet=Color.FromArgb(System.Convert.ToInt16(sArr[0]),System.Convert.ToInt16(sArr[1]),System.Convert.ToInt16(sArr[2]));
			}
			catch(Exception)
			{
			}
			return clrRet;
		}
		protected override void OnLocationChanged(EventArgs e)
		{
			base.OnLocationChanged(e);
			if(m_DropShadow!=null)
			{
				NativeFunctions.SetWindowPos(m_DropShadow.Handle,new IntPtr(NativeFunctions.HWND_TOP),this.Left+5,this.Top+5,0,0,NativeFunctions.SWP_SHOWWINDOW | NativeFunctions.SWP_NOACTIVATE | NativeFunctions.SWP_NOSIZE);
			}
		}
        private Point _FixedLocation = Point.Empty;
        /// 
        /// Specifies fixed location for tooltip window.
        /// 
        public Point FixedLocation
        {
            get { return _FixedLocation; }
            set { _FixedLocation = value; }
        }
		protected override CreateParams CreateParams
		{
			get
			{
				CreateParams p=base.CreateParams;
				p.Style=unchecked((int)(WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN));
				p.ExStyle=(int)(WS_EX_TOOLWINDOW | WS_EX_TOPMOST);
				p.Caption="";
				return p;
			}
		}
		protected override void OnVisibleChanged(EventArgs e)
		{
			if(!this.Visible && m_DropShadow!=null)
			{
				m_DropShadow.Hide();
				m_DropShadow.Dispose();
				m_DropShadow=null;
			}
			base.OnVisibleChanged(e);
		}
        public eDotNetBarStyle Style
        {
            get { return m_Style; }
            set
            {
                m_Style = value;
                if (BarFunctions.IsOffice2007Style(m_Style))
                    this.AntiAlias = true;
            }
        }
        private bool _ShowDropShadow = true;
        public bool ShowDropShadow
        {
            get { return _ShowDropShadow; }
            set
            {
                _ShowDropShadow = value;
            }
        }
        
    }
}