using System;
using System.Collections.Generic;
using Quik.Media;
using Quik.Typography;

namespace Quik
{
    public enum TextAlignment
    {
        Left,
        Center,
        Right,
        Justify
    }

    public enum TextDecoration
    {
        None,
        Underline,
        Overline,
        Strikethrough
    }

    public enum TextTransform
    {
        None,
        Title,
        Upper,
        Lower,
    }

    public enum ListMarkerType
    {
        None,
        Disc,
        Circle,
        FilledSquare,
        Square,
        Dash,
        ArabicNumeral,
        RomanNumeralUpper,
        RomanNumeralLower,
        AlphabetUpper,
        AlphabetLower,
        Image
    }

    public enum ListMarkerPosition
    {
        Inside,
        Outside,
    }

    public abstract class StyleBase
    {
        public abstract object this[string key] { get; set; }

        public QColor? Color
        {
            get => (QColor?)this["color"];
            set => this["color"] = value;
        }

        public float? LineHeight
        {
            get => (float?)this["line-height"];
            set => this["line-height"] = value;
        }

        public float? LetterSpacing
        {
            get => (float?)this["letter-spacing"];
            set => this["letter-spacing"] = value;
        }

        public TextAlignment? TextAlignment
        {
            get => (TextAlignment?)this["text-alignment"];
            set => this["text-alignment"] = value;
        }

        public TextDecoration? TextDecoration
        {
            get => (TextDecoration?)this["text-decoration"];
            set => this["text-decoration"] = value;
        }

        public float? TextIndent
        {
            get => (float?)this["text-indent"];
            set => this["text-indent"] = value;
        }

        public TextTransform? TextTransform
        {
            get => (TextTransform?)this["text-transform"];
            set => this["text-transform"] = value;
        }

        public ListMarkerType? ListMarker
        {
            get => (ListMarkerType?)this["list-marker"];
            set => this["list-marker"] = value;
        }

        public ListMarkerPosition? ListMarkerPosition
        {
            get => (ListMarkerPosition?)this["list-marker-position"];
            set => this["list-marker-position"] = value;
        }

        public QuikTexture ListMarkerImage
        {
            get => (QuikTexture)this["list-marker-image"];
            set => this["list-marker-image"] = value;
        }

        public float? StrokeWidth
        {
            get => (float?)this["stroke-width"];
            set => this["stroke-width"] = value;
        }

        public QColor? StrokeColor
        {
            get => (QColor?)this["stroke-color"];
            set => this["stroke-color"] = value;
        }

        public FontInfo Font
        {
            get => (FontInfo)this["font"];
            set => this["font"] = value;
        }

        public int? ZIndex
        {
            get => (int?)this["z-index"];
            set => this["z-index"] = value;
        }
    }

    public class Style : StyleBase
    {
        private readonly Dictionary<string, object> _keys = new Dictionary<string, object>();

        public override object this[string styleKey]
        {
            get => _keys.TryGetValue(styleKey, out object value) ? value : null;
            set
            {
                if (value == null)
                    _keys.Remove(styleKey);
                else
                    _keys[styleKey] = value;
            }
        }
    }

    public class StyleStack : StyleBase
    {
        public readonly List<Style> _styles = new List<Style>();

        public Style BaseStyle { get; }

        public override object this[string key]
        {
            get
            {
                object value = null;

                for (int i = _styles.Count; i != 0 && value == null; i--)
                {
                    value = _styles[i-1][key];
                }

                return value;
            }
            set => throw new InvalidOperationException();
        }

        public StyleStack(Style baseStyle)
        {
            BaseStyle = baseStyle;
            Push(BaseStyle);
        }

        public void Clear()
        {
            _styles.Clear();
            Push(BaseStyle);
        }

        public void Push(Style style)
        {
            _styles.Add(style);
        }

        public void Pop()
        {
            if (_styles.Count == 1)
                return;

            _styles.RemoveAt(_styles.Count - 1);
        }
    }

    /// <summary>
    /// A line stipple pattern.
    /// </summary>
    public struct QuikStipplePattern
    {
        /// <summary>
        /// The stipple pitch value.
        /// </summary>
        public float Pitch;

        /// <summary>
        /// The stipple duty cycle.
        /// </summary>
        public float DutyCycle;
        
        public QuikStipplePattern(float pitch, float dutyCycle)
        {
            Pitch = pitch;
            DutyCycle = dutyCycle;
        }
        
        public static QuikStipplePattern None => new QuikStipplePattern(0.0f, 1.0f);
    }
    
    /// <summary>
    /// Stroke style for lines and borders.
    /// </summary>
    public class QuikStrokeStyle
    {
        /// <summary>
        /// Stroke color.
        /// </summary>
        public QColor Color { get; set; }

        /// <summary>
        /// Stroke width.
        /// </summary>
        public float Width { get; set; }

        // /// <summary>
        // /// Stroke stipple pattern.
        // /// </summary>
        // public QuikStipplePattern StipplePattern { get; set; }

        public QuikStrokeStyle()
        {
        }
        
        public QuikStrokeStyle(QColor color, float width /*, QuikStipplePattern pattern*/)
        {
            Color = color;
            Width = width;
            // StipplePattern = pattern;
        }

        // public QuikStrokeStyle(QuikColor color, float width) : this(color, width, QuikStipplePattern.None)
        // {
        // }
    }

    /// <summary>
    /// Fill style for rectangles and the like.
    /// </summary>
    public class QuikFillStyle
    {
        public QColor Color { get; set; }
    }
}