using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.ComponentModel;
using System.Drawing.Drawing2D;
using System.Globalization;
namespace DevComponents.DotNetBar.Layout
{
    [TypeConverter(typeof(BackgroundConvertor))]
    public class Background : INotifyPropertyChanged
    {
        #region Constructor
        /// 
        /// Initializes a new instance of the Background class.
        /// 
        public Background()
        {
        }
        /// 
        /// Initializes a new instance of the Background class with single solid backgruond color.
        /// 
        public Background(Color backColor)
        {
            _Colors = new Color[] { backColor };
        }
        /// 
        /// Initializes a new instance of the Background class.
        /// 
        /// 
        public Background(Color[] colors)
        {
            _Colors = colors;
        }
        /// 
        /// Initializes a new instance of the Background class.
        /// 
        /// 
        /// 
        public Background(Color[] colors, float[] positions)
        {
            _Colors = colors;
            _Positions = positions;
        }
        /// 
        /// Initializes a new instance of the Background class.
        /// 
        /// 
        /// 
        /// 
        public Background(Color[] colors, float[] positions, eGradientType gradientType)
        {
            _Colors = colors;
            _Positions = positions;
            _GradientType = gradientType;
        }
        /// 
        /// Initializes a new instance of the Background class.
        /// 
        /// 
        /// 
        /// 
        /// 
        public Background(Color[] colors, float[] positions, eGradientType gradientType, int linearGradientAngle)
        {
            _Colors = colors;
            _Positions = positions;
            _GradientType = gradientType;
            _LinearGradientAngle = linearGradientAngle;
        }
        #endregion
        #region Implementation
        /// 
        /// Gets whether class is empty.
        /// 
        [Browsable(false)]
        public bool IsEmpty
        {
            get
            {
                return (_Colors == null || _Colors.Length == 0) &&
                    (_Positions == null || _Positions.Length == 0);
            }
        }
        /// 
        /// Gets whether background is visible, i.e. colors are assigned.
        /// 
        [Browsable(false)]
        public bool IsBackgroundSet
        {
            get
            {
                return !(_Colors == null || _Colors.Length == 0);
            }
        }
        /// 
        /// Creates the brush which represents the background.
        /// 
        /// Bounds for the brush.
        /// New instance of the brush or null if brush cannot be created.
        public Brush CreateBrush(Rectangle r)
        {
            if (!IsBackgroundSet)
                return null;
            if (_Colors.Length == 1)
                return new SolidBrush(_Colors[0]);
            if (_GradientType == eGradientType.LinearGradient)
            {
                LinearGradientBrush brush = null;
                if (_Colors.Length == 2)
                {
                    brush = new LinearGradientBrush(r, _Colors[0], _Colors[1], _LinearGradientAngle);
                    if (_Positions != null && _Positions.Length != 2) return brush;
                }
                else
                    brush = new LinearGradientBrush(r, _Colors[0], _Colors[_Colors.Length - 1], _LinearGradientAngle);
                ColorBlend cb = GetColorBlend();
                if (cb != null)
                    brush.InterpolationColors = cb;
                return brush;
            }
            else
            {
                int n = (int)Math.Sqrt(r.Width * r.Width + r.Height * r.Height) + 4;
                using (GraphicsPath path = new GraphicsPath())
                {
                    path.AddEllipse(r.X - (n - r.Width) / 2, r.Y - (n - r.Height) / 2, n, n);
                    PathGradientBrush pbr = new PathGradientBrush(path);
                    pbr.CenterColor = _Colors[0];
                    pbr.SurroundColors = new Color[] { _Colors[_Colors.Length - 1] };
                    ColorBlend cb = GetColorBlend();
                    if (cb != null)
                        pbr.InterpolationColors = cb;
                    return (pbr);
                }
            }
        }
        private ColorBlend GetColorBlend()
        {
            if (_Colors != null &&
                _Colors != null && _Colors.Length > 0)
            {
                ColorBlend cb = new ColorBlend(_Colors.Length);
                cb.Colors = _Colors;
                cb.Positions = GetPositions();
                return (cb);
            }
            return (null);
        }
        private float[] GetPositions()
        {
            float[] cp = _Positions;
            if (cp == null || cp.Length != _Colors.Length)
            {
                cp = new float[_Colors.Length];
                float f = 1f / _Colors.Length;
                for (int i = 0; i < cp.Length; i++)
                    cp[i] = i * f;
                cp[_Colors.Length - 1] = 1;
            }
            return (cp);
        }
        private Color[] _Colors = null;
        /// 
        /// Indicates the array of colors that make up background.
        /// 
        [DefaultValue(null), Category("Appearance"), Description("Indicates the array of colors that make up background."), TypeConverter(typeof(ArrayConverter))]
        public Color[] Colors
        {
            get
            {
                return _Colors;
            }
            set
            {
                if (_Colors != value)
                {
                    _Colors = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("Colors"));
                }
            }
        }
        private float[] _Positions = null;
        /// 
        /// Indicates the positions for the gradient colors when multiple colors are set to Colors property. When not set
        /// the gradient color positions are evenly distributed.
        /// 
        [DefaultValue(null), Category("Appearance"), Description("Indicates the positions for the gradient colors when multiple colors are set to Colors property."), TypeConverter(typeof(ArrayConverter))]
        public float[] Positions
        {
            get
            {
                return _Positions;
            }
            set
            {
                _Positions = value;
                OnPropertyChanged(new PropertyChangedEventArgs("Positions"));
            }
        }
        private eGradientType _GradientType = eGradientType.LinearGradient;
        /// 
        /// Indicates the gradient type used when multiple Colors are specified.
        /// 
        [DefaultValue(eGradientType.LinearGradient), Category("Appearance"), Description("Indicates the gradient type used when multiple Colors are specified.")]
        public eGradientType GradientType
        {
            get { return _GradientType; }
            set { _GradientType = value; OnPropertyChanged(new PropertyChangedEventArgs("GradientType")); }
        }
        private int _LinearGradientAngle = 90;
        /// 
        /// Indicates the linear gradient angle.
        /// 
        [DefaultValue(90), Description("Indicates the linear gradient angle."), Category("Appearance")]
        public int LinearGradientAngle
        {
            get { return _LinearGradientAngle; }
            set { _LinearGradientAngle = value; OnPropertyChanged(new PropertyChangedEventArgs("LinearGradientAngle")); }
        }
        #endregion
        #region INotifyPropertyChanged Members
        /// 
        /// Occurs when property value has changed.
        /// 
        public event PropertyChangedEventHandler PropertyChanged;
        /// 
        /// Raises the PropertyChanged event.
        /// 
        /// Event arguments
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler eh = PropertyChanged;
            if (eh != null)
                eh(this, e);
        }
        /// 
        /// Raises the PropertyChanged event.
        /// 
        /// Event arguments
        protected virtual void OnPropertyChangedEx(string s)
        {
            PropertyChangedEventHandler eh = PropertyChanged;
            if (eh != null)
            {
                PropertyChangedEventArgs e =
                    new PropertyChangedEventArgs(s);
                eh(this, e);
            }
        }
        #endregion
    }
    public enum eGradientType
    {
        LinearGradient,
        RadialGradient
    }
    #region BackgroundConvertor
    ///
    /// BackgroundConvertor
    ///
    public class BackgroundConvertor : ExpandableObjectConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return ((sourceType == typeof(string)) || base.CanConvertFrom(context, sourceType));
        }
        public override object ConvertTo(
            ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(string))
            {
                Background gc = value as Background;
                if (gc != null)
                {
                    if (gc.IsEmpty)
                        return "(Empty)";
                    if (gc.Colors != null && gc.Colors.Length == 1)
                        return ColorHelpers.ToArgbString(gc.Colors[0]);
                    if (gc.Colors != null && gc.Colors.Length > 1)
                        return ("Blended");
                    
                    return "";
                }
            }
            return (base.ConvertTo(context, culture, value, destinationType));
        }
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            string str = value as string;
            if (string.IsNullOrEmpty(str))
            {
                return new BorderColors();
            }
            string str2 = str.Trim();
            if (str2.Length == 0)
            {
                return null;
            }
            if (culture == null)
            {
                culture = CultureInfo.CurrentCulture;
            }
            if (str2.IndexOf(culture.TextInfo.ListSeparator[0]) == -1)
            {
                Color c = Color.FromName(str2);
                if (c.IsEmpty)
                    c = ColorHelpers.GetColor(str2);
                return new Background(c);
            }
            throw new ArgumentException("Text Parsing Failed");
            //char ch = culture.TextInfo.ListSeparator[0];
            //string[] strArray = str2.Split(new char[] { ch });
            //Color[] numArray = new Color[strArray.Length];
            ////TypeConverter converter = TypeDescriptor.GetConverter(typeof(Color));
            //for (int i = 0; i < numArray.Length; i++)
            //{
            //    numArray[i] = ColorHelpers.GetColor(strArray[i]);// (Color)converter.ConvertFromString(context, culture, strArray[i]);
            //}
            //if (numArray.Length == 1)
            //{
            //    return new BorderColors(numArray[0]);
            //}
            //if (numArray.Length != 4)
            //{
            //    throw new ArgumentException("Text Parsing Failed");
            //}
            //return new BorderColors(numArray[0], numArray[1], numArray[2], numArray[3]);
        }
    }
    #endregion
}