using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace Telerik.WinControls
{
    /// <summary>Represents round rectangle shape.</summary>
	[ToolboxItem(false), ComVisible(false)]
	public class QsfShape : ElementShape
	{
		int radius = 5;
      
		/// <summary><para>Gets or sets the radius of the shape.</para></summary>
		[Description("Gets or sets the radius of the shape.")]
		[DefaultValue(5)]
		[Category("Appearance")]
		public int Radius
		{
			get { return radius; }
			set { radius = value; }
		}

        /// <summary>
        /// Gets or sets value indicating whether the bottom left corner of the shape should be round
        /// </summary>
        [DefaultValue(true)]
        public bool BottomLeftRounded
        {
            get { return bottomLeftRounded; }
            set { bottomLeftRounded = value; }
        }

        /// <summary>
        /// Gets or sets value indicating whether top left corner of the shape should be round
        /// </summary>
        [DefaultValue(true)]
        public bool TopLeftRounded
        {
            get { return topLeftRounded; }
            set { topLeftRounded = value; }
        }

        /// <summary>
        /// Gets or sets value indicating whether bottom right corner of the shape should be round
        /// </summary>
        [DefaultValue(true)]
        public bool BottomRightRounded
        {
            get { return bottomRightRounded; }
            set { bottomRightRounded = value; }
        }

        /// <summary>
        /// Gets or sets value indicating whether top right corner of the shape should be round
        /// </summary>
        [DefaultValue(true)]
        public bool TopRightRounded
        {
            get { return topRightRounded; }
            set { topRightRounded = value; }
        }

        /// <summary>Initializes a new instance of the RoundRectShape class.</summary>
        public QsfShape()
        {
        }

        /// <summary>Initializes a new instance of the RoundRectShape class.</summary>
        public QsfShape(IContainer components): base(components)
        {
        }

        /// <summary>Initializes a new instance of the RoundRectShape class using a radius.</summary>
        public QsfShape(int radius)
		{
			this.radius = radius;
		}

        public override GraphicsPath CreatePath(Rectangle bounds)
        {
            return this.CreatePath(new RectangleF(bounds.X, bounds.Y, bounds.Width, bounds.Height));
        }

        /// <summary>Greates round rectangle like path.</summary>
        public override GraphicsPath CreatePath(RectangleF bounds)
        {

            GraphicsPath path = new GraphicsPath();

            if (bounds.Height <= 0 || bounds.Width <= 0)
                return path;

            if (this.Radius <= 0.0F)
            {
                path.AddRectangle(bounds);
                path.CloseFigure();

                return path;
            }

            float diameter;
            SizeF sizeF;
            RectangleF arc;

            if (this.Radius >= (Math.Min(bounds.Width, bounds.Height)) / 2.0)
            {
                try
                {
                    if (bounds.Width > bounds.Height)
                    {
                        diameter = bounds.Height;
                        sizeF = new SizeF(diameter, diameter);
                        arc = new RectangleF(bounds.Location, sizeF);
                        //Misho: throw/cach exception can be avioded
                        if (arc.Size != SizeF.Empty)
                        {
                            path.AddArc(arc, 90f, 180f);
                            arc.X = bounds.Right - diameter;
                            path.AddArc(arc, 270f, 180f);
                        }
                        else
                        {
                            path.AddEllipse(bounds);
                        }
                    }
                    else if (bounds.Width < bounds.Height)
                    {
                        diameter = bounds.Width;
                        sizeF = new SizeF(diameter, diameter);
                        arc = new RectangleF(bounds.Location, sizeF);
                        //Misho: throw/cach exception can be avioded
                        if (arc.Size != SizeF.Empty)
                        {
                            path.AddArc(arc, 180f, 180f);
                            arc.Y = bounds.Bottom - diameter;
                            path.AddArc(arc, 0f, 180f);
                        }
                        else
                        {
                            path.AddEllipse(bounds);
                        }
                    }
                    else
                    {
                        path.AddEllipse(bounds);
                    }
                }
                catch (Exception)
                {
                    path.AddEllipse(bounds);
                }
                finally
                {
                    path.CloseFigure();
                }

                return path;
            }

            diameter = this.Radius * 2.0F;
            sizeF = new SizeF(diameter, diameter);
            arc = new RectangleF(bounds.Location, sizeF);

            float notRoundDiameter = 1f;
            SizeF notRoundSize = new SizeF(notRoundDiameter, notRoundDiameter);
            RectangleF notRoundArc = new RectangleF(bounds.Location, notRoundSize);

            const float angle = 90f;
            const int topOffset = 9;
            const int iconLeftOffset = 16;
            const int iconWidth = 63;

            arc.Y += topOffset;
            
            if (this.TopLeftRounded)
            {
                path.AddArc(arc, 180f, angle);
            }
            else
            {
                path.AddArc(notRoundArc, 180f, angle);
            }

            //Add the icon shape
            //   ____
            //___|  |___

            path.AddLine(iconLeftOffset, topOffset, iconLeftOffset, topOffset - 1);

            path.AddArc(new Rectangle(iconLeftOffset, 0, 10, 10), 180f, angle);
            path.AddArc(new Rectangle(iconLeftOffset + iconWidth - 12, 0, 11, 11), 270f, angle);

            path.AddLine(iconLeftOffset + iconWidth, topOffset - 1, iconLeftOffset + iconWidth, topOffset);

            arc.X = bounds.Right - diameter;
            notRoundArc.X = bounds.Right - notRoundDiameter;

            if (this.TopRightRounded)
            {
                path.AddArc(arc, 270f, angle);
            }
            else
            {
                path.AddArc(notRoundArc, 270f, angle);
            }

            arc.Y = bounds.Bottom - diameter;
            notRoundArc.Y = bounds.Bottom - notRoundDiameter;

            if (this.BottomRightRounded)
            {
                path.AddArc(arc, 0f, angle);
            }
            else
            {
                path.AddArc(notRoundArc, 0f, angle);
            }

            arc.X = bounds.Left;
            notRoundArc.X = bounds.Left;

            if (this.BottomLeftRounded)
            {
                path.AddArc(arc, 90f, angle);
            }
            else
            {
                path.AddArc(notRoundArc, 90f, angle);
            }

            path.CloseFigure();           

            return path;
        }

		private bool bottomLeftRounded = true;
		private bool topLeftRounded = true;
		private bool bottomRightRounded = true;
		private bool topRightRounded = true;


        /// <summary>Serializes properties. Required for telerik serialization mechanism.</summary>
        public override string SerializeProperties()
        {
            string res = radius.ToString();

			if (!this.BottomLeftRounded ||
				!this.TopLeftRounded ||
				!this.BottomRightRounded ||
				!this.TopRightRounded)
			{
				res += ", " + this.BottomLeftRounded.ToString();
				res += ", " + this.TopLeftRounded.ToString();
				res += ", " + this.BottomRightRounded.ToString();
				res += ", " + this.TopRightRounded.ToString();
			}

			return res;
        }

        /// <summary>Deserializes properties. Required for telerik deserialization mechanism.</summary>
        public override void DeserializeProperties(string propertiesString)
        {
            if (string.IsNullOrEmpty(propertiesString))
            {
				return;
            }

			string[] propParts = propertiesString.Split(',');

			if (propParts.Length > 0)
			{
				radius = int.Parse(propParts[0]);
			}

			if (propParts.Length > 1)
			{
				this.BottomLeftRounded = bool.Parse(propParts[1]);
			}

			if (propParts.Length > 2)
			{
				this.TopLeftRounded = bool.Parse(propParts[2]);
			}

			if (propParts.Length > 3)
			{
				this.BottomRightRounded = bool.Parse(propParts[3]);
			}

			if (propParts.Length > 4)
			{
				this.TopRightRounded = bool.Parse(propParts[4]);
			}
        }
	}	
}