using System;
using System.ComponentModel;
namespace DevComponents.DotNetBar.Charts.Style
{
    ///
    /// VisualStyles
    ///
    [TypeConverter(typeof(VisualStylesConverter))]
    public class VisualStyles : IDisposable, INotifyPropertyChanged, IProcessSerialElement
        where T : BaseVisualStyle, new()
    {
        #region Private variables
        private T[] _Styles;
        #endregion
        ///
        /// Constructor
        ///
        public VisualStyles()
        {
            _Styles = new T[Enum.GetValues(typeof(StyleType)).Length - 1];
        }
        #region Public properties
        #region Indexer
        /// 
        /// Gets or sets the visual style
        /// assigned to the element. Default value is null.
        /// 
        [DefaultValue(null), Category("Style")]
        [Description("Indicates visual style assigned to the element")]
        public T this[StyleType e]
        {
            get
            {
                int n = StyleIndex(e);
                return (GetStyle(n));
            }
            set
            {
                int n = StyleIndex(e);
                SetStyle(n, value);
            }
        }
        #endregion
        #region Default
        ///
        /// The normal, default style
        ///
        [Description("Style to use for normal, default items")]
        [TypeConverter(typeof(VisualStylesConverter))]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public T Default
        {
            get { return (GetStyle((int) StyleType.Default)); }
            set { SetStyle((int) StyleType.Default, value); }
        }
        #endregion
        #region MouseOver
        ///
        /// MouseOver
        ///
        [Description("Style to use when the Mouse is over an item")]
        [TypeConverter(typeof(VisualStylesConverter))]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public T MouseOver
        {
            get { return (GetStyle((int)StyleType.MouseOver)); }
            set { SetStyle((int)StyleType.MouseOver, value); }
        }
        #endregion
        #region Selected
        ///
        /// Selected
        ///
        [Description("Style to use when the item is selected")]
        [TypeConverter(typeof(VisualStylesConverter))]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public T Selected
        {
            get { return (GetStyle((int)StyleType.Selected)); }
            set { SetStyle((int)StyleType.Selected, value); }
        }
        #endregion
        #region SelectedMouseOver
        ///
        /// MouseOver
        ///
        [Description("Style to use when the item is selected and the Mouse is over it")]
        [TypeConverter(typeof(VisualStylesConverter))]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public T SelectedMouseOver
        {
            get { return (GetStyle((int)StyleType.SelectedMouseOver)); }
            set { SetStyle((int)StyleType.SelectedMouseOver, value); }
        }
        #endregion
        #region Styles
        ///
        /// Styles array
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public T[] Styles
        {
            get { return (_Styles); }
        }
        #endregion
        #region IsEmpty
        /// 
        /// Gets whether the style collection is logically Empty.
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Description("Gets whether the style collection is logically Empty.")]
        public bool IsEmpty
        {
            get
            {
                for (int i = 0; i < Styles.Length; i++)
                {
                    T vstyle = Styles[i];
                    if (vstyle != null && vstyle.IsEmpty == false)
                        return (false);
                }
                return (true);
            }
        }
        #endregion
        #endregion
        #region Count
        internal int Count
        {
            get { return (_Styles.Length); }
        }
        #endregion
        #region GetStyle
        internal T GetStyle(int n)
        {
            if (_Styles[n] == null)
            {
                _Styles[n] = new T();
                OnStyleChangeHandler(null, _Styles[n]);
            }
            return (_Styles[n]);
        }
        #endregion
        #region SetStyle
        internal void SetStyle(int n, T value)
        {
            if (_Styles[n] != value)
            {
                T oldValue = _Styles[n];
                _Styles[n] = value;
                OnStyleChanged(Enum.GetName(typeof(StyleType), n), oldValue, value);
            }
        }
        #endregion
        #region GetSerialData
        internal SerialElementCollection GetSerialData(string serialName)
        {
            if (IsEmpty == false)
            {
                SerialElementCollection sec = new SerialElementCollection();
                if (serialName != null)
                {
                    if (serialName.Equals("") == true)
                    {
                        serialName = this.ToString();
                        serialName = serialName.Substring(serialName.LastIndexOf('.') + 1);
                    }
                    sec.AddStartElement(serialName);
                }
                string[] enums = Enum.GetNames(typeof(StyleType));
                for (int i = 0; i < Styles.Length; i++)
                {
                    T vstyle = Styles[i];
                    if (vstyle != null && vstyle.IsEmpty == false)
                    {
                        sec.AddStartElement(enums[i]);
                        sec.AddElement(vstyle.GetSerialData(null));
                        sec.AddEndElement(enums[i]);
                    }
                }
                if (serialName != null)
                    sec.AddEndElement(serialName);
                return (sec);
            }
            return (null);
        }
        #endregion
        #region PutSerialData
        #region ProcessValue
        void IProcessSerialElement.ProcessValue(SerialElement se)
        {
            throw new Exception("Unknown Serial Value (" + se.Name + ")");
        }
        #endregion
        #region ProcessCollection
        void IProcessSerialElement.ProcessCollection(SerialElement se)
        {
            switch (se.Name)
            {
                case "Default":
                    se.Sec.PutSerialData(Default);
                    break;
                case "MouseOver":
                    se.Sec.PutSerialData(MouseOver);
                    break;
                case "Selected":
                    se.Sec.PutSerialData(Selected);
                    break;
                case "SelectedMouseOver":
                    se.Sec.PutSerialData(SelectedMouseOver);
                    break;
                default:
                    throw new Exception("Unknown Serial Collection (" + se.Name + ")");
            }
        }
        #endregion
        #endregion
        #region OnStyleChanged
        private void OnStyleChanged(
            string property, T oldValue, T newValue)
        {
            OnStyleChangeHandler(oldValue, newValue);
            OnPropertyChanged(new VisualPropertyChangedEventArgs(property));
        }
        #endregion
        #region StyleIndex
        internal int StyleIndex(Enum e)
        {
            int n = ((IConvertible)e).ToInt32(null);
            if (n < 0 || n > _Styles.Length)
                throw new Exception("Invalid Style indexer");
            return (n);
        }
        #endregion
        #region IsValid
        internal T Style(Enum e)
        {
            int n = ((IConvertible) e).ToInt32(null);
            if (n < 0 || n > _Styles.Length)
                throw new Exception("Invalid Style indexer");
            return (_Styles[n]);
        }
        #endregion
        #region GetStyleType
        internal StyleType GetStyleType(StyleState state)
        {
            switch (state)
            {
                case StyleState.MouseOver:
                    return (StyleType.MouseOver);
                case StyleState.Selected:
                    return (StyleType.Selected);
                case StyleState.Selected | StyleState.MouseOver:
                    return (StyleType.SelectedMouseOver);
                default:
                    return (StyleType.Default);
            }
        }
        #endregion
        #region Style support routines
        #region StyleVisualChangeHandler
        private void OnStyleChangeHandler(T oldValue, T newValue)
        {
            if (oldValue != null)
                oldValue.PropertyChanged -= StyleChanged;
            if (newValue != null)
                newValue.PropertyChanged += StyleChanged;
        }
        #endregion
        #region StyleChanged
        /// 
        /// Occurs when one of element visual styles has property changes.
        /// Default implementation invalidates visual appearance of element.
        /// 
        /// VisualStyle that changed.
        /// Event arguments.
        protected virtual void StyleChanged(object sender, PropertyChangedEventArgs e)
        {
            OnPropertyChanged(e);
        }
        #endregion
        #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);
        }
        #endregion
        #region IDisposable
        /// 
        /// Dispose
        /// 
        public void Dispose()
        {
            for (int i = 0; i < _Styles.Length; i++)
            {
                T style = _Styles[i];
                if (style != null)
                {
                    SetStyle(i, null);
                    style.Dispose();
                }
            }
            _Styles = null;
        }
        #endregion
    }
}