using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
namespace DevComponents.DotNetBar.Charts.Style
{
    /// 
    /// Represents the base visual style.
    /// 
    [ToolboxItem(false), DesignTimeVisible(false)]
    public class BaseVisualStyle : INotifyPropertyChanged, IDisposable, IProcessSerialElement
    {
        #region Static data
        static private List _StyleList;
        private static StyleUpdateMode _StyleUpdateMode = StyleUpdateMode.Full;
        #endregion
        #region Private variables
        private StyleType _StyleType;
        private BaseVisualStyle _Parent;
        private ushort _StyleUpdateCount;
        private string _Class = "";
        private object _Tag;
        #endregion
        #region Public properties
        #region Class
        /// 
        /// Gets or sets the class style belongs to. 
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string Class
        {
            get { return (_Class); }
            set
            {
                if (_Class != value)
                {
                    _Class = value;
                    OnPropertyChangedEx("Class", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region IsEmpty
        /// 
        /// Gets whether the style is logically Empty.
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Description("Gets whether the style is logically Empty.")]
        public virtual bool IsEmpty
        {
            get { return (_Tag == null); }
        }
        #endregion
        #region Tag
        /// 
        /// Gets or sets the user defined reference Tag.
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Description("User defined reference Tag.")]
        public object Tag
        {
            get { return (_Tag); }
            set { _Tag = value; }
        }
        #endregion
        #endregion
        #region Internal properties
        #region StyleType
        internal StyleType StyleType
        {
            get { return (_StyleType); }
            set { _StyleType = value; }
        }
        #endregion
        #region StyleUpdateCount
        internal ushort StyleUpdateCount
        {
            get { return (_StyleUpdateCount); }
            set { _StyleUpdateCount = value; }
        }
        #endregion
        #region StyleUpdateMode
        internal StyleUpdateMode StyleUpdateMode
        {
            get { return (_StyleUpdateMode); }
            set { _StyleUpdateMode = value; }
        }
        #endregion
        #region Parent
        internal BaseVisualStyle Parent
        {
            get { return (_Parent); }
            set { _Parent = value; }
        }
        #endregion
        #region StyleList
        internal List StyleList
        {
            get { return (_StyleList); }
            set { _StyleList = value; }
        }
        #endregion
        #endregion
        #region ApplyStyle
        /// 
        /// Applies the style to instance of this style.
        /// 
        /// Style to apply.
        public void ApplyStyle(BaseVisualStyle style)
        {
            if (StyleList != null)
                StyleList.Add(style ?? this);
        }
        #endregion
        #region GetApplyStyleTypes
        internal StyleType[] GetApplyStyleTypes(StyleType e)
        {
            StyleType[] css = null;
            switch (e)
            {
                case StyleType.Default:
                    css = new StyleType[] { StyleType.Default};
                    break;
                case StyleType.MouseOver:
                    css = new StyleType[] { StyleType.Default, e };
                    break;
                case StyleType.Selected:
                    css = new StyleType[] { StyleType.Default, e };
                    break;
                case StyleType.SelectedMouseOver:
                    css = new StyleType[] { StyleType.Default, StyleType.Selected, e };
                    break;
            }
            return (css);
        }
        #endregion
        #region Copy
        /// 
        /// Returns the copy of the style.
        /// 
        /// Copy of the style.
        public BaseVisualStyle Copy()
        {
            BaseVisualStyle style = new BaseVisualStyle();
            CopyTo(style);
            return (style);
        }
        #endregion
        #region CopyTo
        /// 
        /// Returns the copy of the style.
        /// 
        /// Copy of the style.
        public void CopyTo(BaseVisualStyle copy)
        {
            copy.Class = _Class;
            copy.Tag = _Tag;
        }
        #endregion
        #region GetSerialData
        internal virtual SerialElementCollection GetSerialData(string serialName)
        {
            if ((String.IsNullOrEmpty(Class) == false) || (Tag != null))
            {
                SerialElementCollection sec = new SerialElementCollection();
                if (serialName != null)
                {
                    if (serialName.Equals("") == true)
                        serialName = "BaseVisualStyle";
                    sec.AddStartElement(serialName);
                }
                sec.AddValue("Class", Class, "");
                sec.AddValue("Tag", Tag, null);
                if (serialName != null)
                    sec.AddEndElement(serialName);
                return (sec);
            }
            return (null);
        }
        #endregion
        #region PutSerialData
        #region ProcessValue
        void IProcessSerialElement.ProcessValue(SerialElement se)
        {
            ProcessValue(se);
        }
        internal virtual void ProcessValue(SerialElement se)
        {
            switch (se.Name)
            {
                case "Name":
                    Class = se.StringValue;
                    break;
                case "Tag":
                    Tag = se.DataValue;
                    break;
                default:
                    throw new Exception("Unknown Serial Value (" + se.Name + ")");
            }
        }
        #endregion
        #region ProcessCollection
        void IProcessSerialElement.ProcessCollection(SerialElement se)
        {
            ProcessCollection(se);
        }
        internal virtual void ProcessCollection(SerialElement se)
        {
            throw new Exception("Unknown Serial Collection (" + se.Name + ")");
        }
        #endregion
        #endregion
        #region ApplyDefaults
        public virtual void ApplyDefaults()
        {
        }
        #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)
        {
            if ((StyleUpdateMode & StyleUpdateMode.UpdateCount) == StyleUpdateMode.UpdateCount)
                StyleUpdateCount++;
            if ((StyleUpdateMode & StyleUpdateMode.Notify) == StyleUpdateMode.Notify)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, e);
            }
        }
        /// 
        /// Default PropertyChanged processing
        /// 
        /// 
        protected void OnPropertyChanged(string s)
        {
            if ((StyleUpdateMode & StyleUpdateMode.UpdateCount) == StyleUpdateMode.UpdateCount)
                StyleUpdateCount++;
            if (PropertyChanged != null)
                OnPropertyChanged(new VisualPropertyChangedEventArgs(s));
        }
        /// 
        /// Default PropertyChanged processing
        /// 
        /// 
        /// invalidate
        protected void OnPropertyChangedEx(string s, VisualChangeType changeType)
        {
            if ((StyleUpdateMode & StyleUpdateMode.UpdateCount) == StyleUpdateMode.UpdateCount)
                StyleUpdateCount++;
            if (PropertyChanged != null)
                OnPropertyChanged(new VisualPropertyChangedEventArgs(s, changeType));
        }
        #endregion
        #region UpdateChangeHandler
        /// 
        /// UpdateChangeHandler
        /// 
        /// 
        /// 
        protected void UpdateChangeHandler(
            INotifyPropertyChanged oldValue, INotifyPropertyChanged newValue)
        {
            if (oldValue != null)
                oldValue.PropertyChanged -= ValuePropertyChanged;
            if (newValue != null)
                newValue.PropertyChanged += ValuePropertyChanged;
        }
        void ValuePropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            OnPropertyChanged(e);
        }
        #endregion
        #region OnStyleChanged
        protected void OnStyleChanged(string property,
            INotifyPropertyChanged oldValue, INotifyPropertyChanged newValue)
        {
            UpdateChangeHandler(oldValue, newValue);
            OnPropertyChanged(property);
        }
        #endregion
        #region IDisposable
        /// 
        /// Dispose
        /// 
        public virtual void Dispose()
        {
        }
        #endregion
    }
    #region enums
    #region StyleState
    ///
    /// StyleState
    ///
    [Flags]
    public enum StyleState
    {
        ///
        /// Default
        ///
        Default = 0,
        ///
        /// MouseOver
        ///
        MouseOver = (1 << 0),
        ///
        /// Selected
        ///
        Selected = (1 << 1),
    }
    #endregion
    #region StyleType
    ///
    /// StyleType
    ///
    public enum StyleType
    {
        ///
        /// CellStyle is Not Set
        ///
        NotSet = -1,
        ///
        /// Default
        ///
        Default = 0,
        ///
        /// MouseOver
        ///
        MouseOver,
        ///
        /// Selected
        ///
        Selected,
        ///
        /// SelectedMouseOver
        ///
        SelectedMouseOver,
    }
    #endregion
    #region StyleUpdateMode
    [Flags]
    internal enum StyleUpdateMode
    {
        None = 0,
        Notify = (1 << 0),
        UpdateCount = (1 << 1),
        Full = (UpdateCount | Notify),
    }
    #endregion
    #region Tbool
    ///
    /// TBool - Three state boolean
    ///
    public enum Tbool
    {
        ///
        /// NotSet
        ///
        NotSet,
        ///
        /// True
        ///
        True,
        ///
        /// False
        ///
        False
    }
    #endregion
    #region VisualChangeType
    /// 
    /// Defines visual property change type.
    /// 
    public enum VisualChangeType
    {
        /// 
        /// Visual style has changed so Recalc is needed
        /// 
        Recalc,
        /// 
        /// Visual style has changed so layout is impacted, but not recalc
        /// 
        Layout,
        /// 
        /// Visual style has changed so visuals are impacted, but not layout
        /// 
        Render
    }
    #endregion
    #endregion
    #region VisualPropertyChangedEventArgs
    /// 
    /// Represents visual property changed event arguments.
    /// 
    public class VisualPropertyChangedEventArgs : PropertyChangedEventArgs
    {
        #region Public data
        /// 
        /// Gets the change type.
        /// 
        public readonly VisualChangeType ChangeType;
        #endregion
        /// 
        /// Initializes a new instance of the VisualPropertyChangedEventArgs class.
        /// 
        public VisualPropertyChangedEventArgs(string propertyName)
            : base(propertyName)
        {
            ChangeType = VisualChangeType.Layout;
        }
        /// 
        /// Initializes a new instance of the VisualPropertyChangedEventArgs class.
        /// 
        public VisualPropertyChangedEventArgs(string propertyName, VisualChangeType changeType)
            : base(propertyName)
        {
            ChangeType = changeType;
        }
    }
    #endregion
    #region VisualStylesConverter
    ///
    /// VisualStylesConverter
    ///
    public class VisualStylesConverter : ExpandableObjectConverter
    {
        /// 
        /// ConvertTo
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public override object ConvertTo(
            ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(string))
                return (" ");
            return (base.ConvertTo(context, culture, value, destinationType));
        }
    }
    #endregion
    #region DefaultStyleConvertor
    public class DefaultStyleConvertor : ExpandableObjectConverter
    {
        public override object ConvertTo(
            ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(string))
            {
                BaseVisualStyle bvs = value as BaseVisualStyle;
                if (bvs != null)
                {
                    ColorConverter cvt = new ColorConverter();
                    return ((bvs.IsEmpty == true) ? " " : "(Set)");
                }
            }
            return (base.ConvertTo(context, culture, value, destinationType));
        }
    }
    #endregion
}