using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
namespace DevComponents.Tree.Display
{
	/// 
	/// Represents professional rendered which provides extensive rendering above and beyond the NodeSystemRenderer.
	/// 
	public class NodeProfessionalRenderer : NodeSystemRenderer
	{
		#region Private Variables
		private NodeProfessionalColorTable m_ColorTable=new NodeProfessionalColorTable();
		#endregion
		
		/// 
		/// Gets or sets the color table used by renderer.
		/// 
		public NodeProfessionalColorTable ColorTable
		{
			get { return m_ColorTable;}
			set
			{
				m_ColorTable = value;
			}
		}
		/// 
		/// Draws node background. If you need to provide custom rendering this is the method that you should override in your custom rendered. If you
		/// do not want default rendering to occur do not call the base implementation. You can call OnRenderNodeBackground method so events can occur.
		/// 
		/// Information provided for rendering.
		public override void DrawNodeBackground(NodeRendererEventArgs e)
		{
			ElementStyleDisplayInfo di=GetElementStyleDisplayInfo(e.Style,e.Graphics,DisplayHelp.GetDrawRectangle(e.NodeBounds));
			PaintBackground(e);
			ElementStyleDisplay.PaintBackgroundImage(di);
			ElementStyleDisplay.PaintBorder(di);
			
			// Let events occur
			OnRenderNodeBackground(e);
		}
		
		private void PaintBackgroundPart(Graphics g, Rectangle bounds, GraphicsPath path, Color color1, Color color2, eGradientType gradientType, int gradientAngle)
		{
			if(color2.IsEmpty)
			{
				if(!color1.IsEmpty)
				{
					using(SolidBrush brush=new SolidBrush(color1))
						g.FillPath(brush,path);
				}
			}
			else if(!m_ColorTable.NodeTopGradientBegin.IsEmpty)
			{
				if (gradientType == eGradientType.Linear)
				{
					Rectangle rb = bounds;
					rb.X--;
					rb.Height++;
					rb.Width += 2;
					using (LinearGradientBrush brush = DisplayHelp.CreateLinearGradientBrush(rb, color1, color2, gradientAngle))
					{
						g.FillPath(brush, path);
					}
				}
				else if (gradientType == eGradientType.Radial)
				{
					int d = (int)Math.Sqrt(bounds.Width * bounds.Width + bounds.Height * bounds.Height);
					GraphicsPath fillPath = new GraphicsPath();
					fillPath.AddEllipse(bounds.X - (d - bounds.Width), bounds.Y - (d - bounds.Height) / 2, d, d);
					using (PathGradientBrush brush = new PathGradientBrush(fillPath))
					{
						brush.CenterColor = color1;
						brush.SurroundColors = new Color[] { color2 };
						g.FillPath(brush, path);
					}
					fillPath.Dispose();
				}
			}
		}
		
		/// 
		/// Paints background of the node.
		/// 
		/// Context information.
		protected virtual void PaintBackground(NodeRendererEventArgs e)
		{
			Graphics g = e.Graphics;
			bool mouseOver = e.Node.IsMouseOver;
			
			Region oldClip = g.Clip;
			Rectangle clipRect=e.NodeBounds;
			clipRect.Width--;
			clipRect.Height--;
			g.SetClip(clipRect, CombineMode.Replace);
			
			// Prepare colors
			NodeColors colors=new NodeColors();
			colors.NodeTopGradientBegin = m_ColorTable.NodeTopGradientBegin;
			colors.NodeTopGradientMiddle = m_ColorTable.NodeTopGradientMiddle;
			colors.NodeTopGradientEnd = m_ColorTable.NodeTopGradientEnd;
			colors.NodeTopGradientType = m_ColorTable.NodeTopGradientType;
			colors.NodeTopGradientAngle = m_ColorTable.NodeTopGradientAngle;
			colors.NodeBottomGradientBegin = m_ColorTable.NodeBottomGradientBegin;
			colors.NodeBottomGradientMiddle = m_ColorTable.NodeBottomGradientMiddle;
			colors.NodeBottomGradientEnd = m_ColorTable.NodeBottomGradientEnd;
			colors.NodeBottomGradientType = m_ColorTable.NodeBottomGradientType;
			colors.NodeBottomGradientAngle = m_ColorTable.NodeBottomGradientAngle;
			if(mouseOver)
			{
				colors.NodeTopGradientBegin = m_ColorTable.NodeMouseOverTopGradientBegin;
				colors.NodeTopGradientMiddle = m_ColorTable.NodeMouseOverTopGradientMiddle;
				colors.NodeTopGradientEnd = m_ColorTable.NodeMouseOverTopGradientEnd;
				colors.NodeTopGradientType = m_ColorTable.NodeMouseOverTopGradientType;
				colors.NodeTopGradientAngle = m_ColorTable.NodeMouseOverTopGradientAngle;
				colors.NodeBottomGradientBegin = m_ColorTable.NodeMouseOverBottomGradientBegin;
				colors.NodeBottomGradientMiddle = m_ColorTable.NodeMouseOverBottomGradientMiddle;
				colors.NodeBottomGradientEnd = m_ColorTable.NodeMouseOverBottomGradientEnd;
				colors.NodeBottomGradientType = m_ColorTable.NodeMouseOverBottomGradientType;
				colors.NodeBottomGradientAngle = m_ColorTable.NodeMouseOverBottomGradientAngle;
			}
			
			// Paint Background, Top Part
			Rectangle bounds=DisplayHelp.GetDrawRectangle(ElementStyleDisplay.GetBackgroundRectangle(e.Style,e.NodeBounds));
			GraphicsPath path;
			if (g.SmoothingMode == SmoothingMode.AntiAlias)
			{
				Rectangle r = bounds;
				r.Width--;
				path = ElementStyleDisplay.GetBackgroundPath(e.Style, r, eStyleBackgroundPathPart.TopHalf);
			}
			else
				path = ElementStyleDisplay.GetBackgroundPath(e.Style, bounds, eStyleBackgroundPathPart.TopHalf);
			path.CloseAllFigures();
			Rectangle backRect = bounds;
			backRect.Height = backRect.Height/2;
			PaintBackgroundPart(g, backRect, path, colors.NodeTopGradientBegin, colors.NodeTopGradientEnd,
			                    colors.NodeTopGradientType, colors.NodeTopGradientAngle);
			
			Rectangle ellipse = new Rectangle(bounds.X, bounds.Y - bounds.Height / 2, bounds.Width, bounds.Height);
			GraphicsPath pathFill=new GraphicsPath();
			pathFill.AddEllipse(ellipse);
			PathGradientBrush pathBrush = new PathGradientBrush(pathFill);
			pathBrush.CenterColor = colors.NodeTopGradientMiddle;
			pathBrush.SurroundColors = new Color[] { Color.Transparent };
			pathBrush.CenterPoint = new PointF(ellipse.X + ellipse.Width / 2, bounds.Y);
			Blend blend = new Blend();
			blend.Factors = new float[] { 0f, .8f, 1f };
			blend.Positions = new float[] { .0f, .8f, 1f };
			pathBrush.Blend = blend;
			pathFill.Dispose();
			g.FillPath(pathBrush, path);
			pathBrush.Dispose();
			path.Dispose();
			
			// Bottom Part
			if (g.SmoothingMode == SmoothingMode.AntiAlias)
			{
				Rectangle r = bounds;
				r.Width--;
				path = ElementStyleDisplay.GetBackgroundPath(e.Style, r, eStyleBackgroundPathPart.BottomHalf);
			}
			else
				path = ElementStyleDisplay.GetBackgroundPath(e.Style, bounds, eStyleBackgroundPathPart.BottomHalf);
			path.CloseAllFigures();
			
			backRect.Y += backRect.Height;
			PaintBackgroundPart(g, backRect, path, colors.NodeBottomGradientBegin, colors.NodeBottomGradientEnd,
				colors.NodeBottomGradientType, colors.NodeBottomGradientAngle);
			
			ellipse = new Rectangle(bounds.X, bounds.Y + bounds.Height / 2 - 2, bounds.Width, bounds.Height + 4);
			pathFill=new GraphicsPath();
			pathFill.AddEllipse(ellipse);
			pathBrush = new PathGradientBrush(pathFill);
			pathBrush.CenterColor = colors.NodeBottomGradientMiddle;
			pathBrush.SurroundColors = new Color[] { Color.Transparent };
			pathBrush.CenterPoint = new PointF(ellipse.X + ellipse.Width / 2, bounds.Bottom);
			blend = new Blend();
			blend.Factors = new float[] { 0f, .5f, 1f };
			blend.Positions = new float[] { .0f, .4f, 1f };
			pathBrush.Blend = blend;
			//path.Dispose();
			g.FillPath(pathBrush, path);
			pathBrush.Dispose();
			pathFill.Dispose();
			path.Dispose();
			
			if (oldClip != null)
				g.Clip = oldClip;
			else
				g.ResetClip();
			
		}
		
		private class NodeColors
		{
			public Color NodeTopGradientBegin;
			public Color NodeTopGradientMiddle;
			public Color NodeTopGradientEnd;
			public eGradientType NodeTopGradientType=eGradientType.Linear;
			public int NodeTopGradientAngle=90;
		
			public Color NodeBottomGradientBegin;
			public Color NodeBottomGradientMiddle;
			public Color NodeBottomGradientEnd;
			public eGradientType NodeBottomGradientType=eGradientType.Linear;
			public int NodeBottomGradientAngle=90;
		}
		
	}
}