using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace Hanna.Controls
{
	/// <summary>
	/// Summary description for Text.
	/// </summary>
	public class TextShape : Shape
	{
		private string				_text	= "TextShape";
		private StringFormat		_format	= StringFormat.GenericTypographic;
        
		#region construct/init/dispose

		public TextShape()
		{
			InitializeComponent();
		}

		/// <summary> 
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		/// <summary> 
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			this._format.Dispose();
			base.Dispose( disposing );
		}
		#endregion

		#region Component Designer generated code
		/// <summary> 
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			// 
			// TextShape
			// 
			this.Name = "TextShape";
			this.Size = new System.Drawing.Size(192, 32);
			this.FontChanged += new System.EventHandler(this.TextShape_FontChanged);

		}
		#endregion

		public string Caption
		{
			get { return _text; }
			set 
			{
				if ( value != null )
				{
					if ( value != _text )
					{
						this._text = value;
						this.SetRegion();
						this.Invalidate();
					}
				}
			}
		}
	
		#region events and event overrides
		private void TextShape_FontChanged(object sender, System.EventArgs e)
		{
			this.SetRegion();
			this.Invalidate();
		}
		#endregion 

		#region protected overrides
		protected override GraphicsPath GetShapePath(Rectangle rect)
		{
			GraphicsPath path = new GraphicsPath();
			// calc text size
			path.AddString(this.Caption, 
				base.Font.FontFamily, 
				(int) base.Font.Style,
				base.Font.Size,
				rect , 
				this._format);			
			path.CloseAllFigures();
			return path;
		}
		protected override void SetShapeRegion ()
		{
			try
			{
				Rectangle textRect = new Rectangle(0,0,0,0);
				using ( Graphics g = this.CreateGraphics() )
				{
					textRect = this.GetTextRectangle(g);
				}
				if ( this.Region != null ) this.Region.Dispose();				
				Region tmpRegion = new Region(GetShapePath(textRect));

				if ( ( this.BorderStyle != BorderStyles.None ) &&
					 ( this.BorderWidth > 0 ) )
				{
					if ( this.BorderStyle == BorderStyles.Solid )
					{
						using ( GraphicsPath tmpPath = GetShapePath(textRect))
						{
							using ( Pen p = new Pen(this.LineBrush, this.BorderWidth) )
							{
								tmpPath.Widen(p);
							}
							tmpRegion.Exclude(tmpPath);
							tmpRegion.Union(tmpPath);
						}
					}
					else
					{
						//	add shadower that is offset up/left
						textRect.Offset(-this.BorderWidth, -this.BorderWidth);
						tmpRegion.Exclude(this.GetShapePath(textRect));
						tmpRegion.Union(this.GetShapePath(textRect));
						//	add shadower that is offset down/right
						textRect.Offset(this.BorderWidth *2 , this.BorderWidth *2);
						tmpRegion.Exclude(this.GetShapePath(textRect));
						tmpRegion.Union(this.GetShapePath(textRect));
					}
				}
				this.Region = tmpRegion;
			}
			catch ( Exception ex )
			{
				MessageBox.Show("Ex: " + ex.ToString());
			}
		}

		protected override void SetFillRegion()
		{
			Rectangle textRect = new Rectangle(0,0,0,0);
			using ( Graphics g = this.CreateGraphics() )
			{
				textRect = this.GetTextRectangle(g);
			}
			using ( GraphicsPath path = GetShapePath(textRect ) )
			{
				if ( this.FillRegion != null )
					this.FillRegion.Dispose();
				this.FillRegion = new Region(path);								
			}
		}
		#endregion 

		#region private helpers

		private Rectangle GetTextRectangle(Graphics g)
		{
			// calc text size
			CharacterRange[] cr		= { new CharacterRange(0,this.Caption.Length) };
			this._format.SetMeasurableCharacterRanges(cr);
			RectangleF		 rect	= g.MeasureCharacterRanges(this._text, this.Font,this.ClientRectangle, this._format)[0].GetBounds(g);
			SizeF			 sz = rect.Size;
			return new Rectangle(new Point(this.BorderWidth,this.BorderWidth),sz.ToSize());					
		}
		#endregion

	}
}
