//! Various styles for the [`Knob`] widget
//!
//! [`Knob`]: ../native/knob/struct.Knob.html

use iced_native::Color;
//use iced_native::image;

pub use iced_graphics::widget::canvas::{Canvas, LineCap};

use crate::style::{default_colors, text_marks, tick_marks};
use crate::KnobAngleRange;

/// The appearance of a [`Knob`],
///
/// [`Knob`]: ../../native/knob/struct.Knob.html
#[derive(Debug, Clone)]
pub enum Appearance {
    //Texture(TextureStyle),
    /// A classic circular style
    Circle(CircleAppearance),
    /// A modern arc style
    Arc(ArcAppearance),
    /// A modern arc style with. It can display different colors
    /// for left, right, and center positions.
    ArcBipolar(ArcBipolarAppearance),
}

/*
/// An [`Appearance`] for a [`Knob`] that uses an image texture for the knob
///
/// [`Appearance`]: enum.Appearance.html
/// [`Knob`]: ../../native/knob/struct.Knob.html
/// [`Handle`]: https://docs.rs/iced/0.1.1/iced/widget/image/struct.Handle.html
#[derive(Debug, Clone)]
pub struct TextureStyle {
    /// the [`Handle`] to the image texture
    pub texture: image::Handle,
    /// the width of the knob, not including padding
    pub knob_width: u16,
    /// the height of the knob, not including padding
    pub knob_height: u16,
    /// the texture padding around the knob bounding
    /// rectangle. This is useful when the texture is of a glowing handle or has
    /// a drop shadow, etc.
    pub texture_padding: Option<TexturePadding>,
}
*/

/// A length in a [`Knob`] stylesheet
///
/// [`Knob`]: ../../native/knob/struct.Knob.html
#[derive(Debug, Clone)]
pub enum StyleLength {
    /// The diameter of the knob scaled to this value
    Scaled(f32),
    /// Absolute length in pixels
    Fixed(f32),
}

impl StyleLength {
    /// Returns the length based on the given knob diameter
    #[inline]
    pub fn from_knob_diameter(&self, knob_diameter: f32) -> f32 {
        match self {
            StyleLength::Scaled(scale) => knob_diameter * *scale,
            StyleLength::Fixed(units) => *units,
        }
    }
}

/// Circle notch
#[derive(Debug, Clone)]
pub struct CircleNotch {
    /// The color of the circle
    pub color: Color,
    /// The width of the border
    pub border_width: f32,
    /// The color of the border
    pub border_color: Color,
    /// The diameter of the circle
    pub diameter: StyleLength,
    /// The offset from the edge of the knob to the center of the notch.
    pub offset: StyleLength,
}

/// Line notch
#[derive(Debug, Clone)]
pub struct LineNotch {
    /// The color of the line
    pub color: Color,
    /// The width (thickness) of the line
    pub width: StyleLength,
    /// The length of the line
    pub length: StyleLength,
    /// The cap at the ends of the line
    pub cap: LineCap,
    /// The offset from the edge of the knob to the center of the notch.
    pub offset: StyleLength,
}

/// The shape of the notch
#[derive(Debug, Clone)]
pub enum NotchShape {
    /// No notch
    None,
    /// Circle notch
    Circle(CircleNotch),
    /// Line notch
    Line(LineNotch),
}

/// A classic circular [`Appearance`] of a [`Knob`]
///
/// [`Appearance`]: enum.Appearance.html
/// [`Knob`]: ../../native/knob/struct.Knob.html
#[derive(Debug, Clone)]
pub struct CircleAppearance {
    /// The color of the knob
    pub color: Color,
    /// The width of the border around the knob
    pub border_width: f32,
    /// The color of the border around the knob
    pub border_color: Color,
    /// The shape of the notch
    pub notch: NotchShape,
}

impl Default for CircleAppearance {
    fn default() -> Self {
        CircleAppearance {
            color: default_colors::LIGHT_BACK,
            border_width: 1.0,
            border_color: default_colors::BORDER,
            notch: NotchShape::Circle(CircleNotch {
                color: default_colors::BORDER,
                border_width: 0.0,
                border_color: Color::TRANSPARENT,
                diameter: StyleLength::Scaled(0.17),
                offset: StyleLength::Scaled(0.15),
            }),
        }
    }
}

/// A modern arc [`Appearance`] of a [`Knob`]
///
/// [`Appearance`]: enum.Appearance.html
/// [`Knob`]: ../../native/knob/struct.Knob.html
#[derive(Debug, Clone)]
pub struct ArcAppearance {
    /// The width (thickness) of the arc
    pub width: StyleLength,
    /// The color of an empty portion of the arc
    pub empty_color: Color,
    /// The color of the filled portion of the arc
    pub filled_color: Color,
    /// The shape of the notch
    pub notch: NotchShape,
    /// The cap at the ends of the arc
    pub cap: LineCap,
}

/// A modern arc [`Appearance`] of a [`Knob`].
/// It can display different colors for left, right, and center positions. The filled arc
/// color draws from the center position.
///
/// [`Appearance`]: enum.Appearance.html
/// [`Knob`]: ../../native/knob/struct.Knob.html
#[derive(Debug, Clone)]
pub struct ArcBipolarAppearance {
    /// The width (thickness) of the arc
    pub width: StyleLength,
    /// The color of the empty background portion of the arc
    pub empty_color: Color,
    /// The color of the filled portion to the left of the center
    pub left_filled_color: Color,
    /// The color of the filled portion to the right of the center
    pub right_filled_color: Color,
    /// The shape of the notch when in the center position
    pub notch_center: NotchShape,
    /// The shape of the notch when it is to the left and right of the
    /// center. Set this to `None` to only use `notch_center`.
    pub notch_left_right: Option<(NotchShape, NotchShape)>,
    /// The cap at the ends of the arc
    pub cap: LineCap,
}

/// A style for a value arc around a [`Knob`]
///
/// [`Knob`]: ../../native/knob/struct.Knob.html
#[derive(Debug, Copy, Clone)]
pub struct ValueArcAppearance {
    /// The width (thickness) of the arc
    pub width: f32,
    /// The offset from the edge of the `Knob` in pixels
    pub offset: f32,
    /// The color of the empty background portion in the arc. Set this to
    /// `None` for no background arc.
    pub empty_color: Option<Color>,
    /// The color of a filled portion of the ring. If `right_filled_color` is
    /// `Some`, then this will only apply to the left side of the ring.
    pub left_filled_color: Color,
    /// The color of a filled portion on the right side of the ring.
    /// Set this to `None` for unipolar mode.
    pub right_filled_color: Option<Color>,
    /// The cap at the ends of the arc
    pub cap: LineCap,
}

/// A style for a [`ModulationRange`] arc around a [`Knob`]
///
/// [`ModulationRange`]: ../../core/struct.ModulationRange.html
/// [`Knob`]: ../../native/knob/struct.Knob.html
#[derive(Debug, Copy, Clone)]
pub struct ModRangeArcAppearance {
    /// The width (thickness) of the arc
    pub width: f32,
    /// The offset from the edge of the `Knob` in pixels
    pub offset: f32,
    /// The color of an empty background portion in the arc. Set this to
    /// `None` for no background arc.
    pub empty_color: Option<Color>,
    /// The color of a filled portion of the arc
    pub filled_color: Color,
    /// The color of a filled portion of the arc when `end` is less than
    /// `start`
    pub filled_inverse_color: Color,
    /// The cap at the ends of the arc
    pub cap: LineCap,
}

/// Style of tick marks for a [`Knob`].
///
/// [`Knob`]: ../../native/knob/struct.Knob.html
#[derive(Debug, Clone)]
pub struct TickMarksAppearance {
    /// The style of the tick marks
    pub style: tick_marks::Appearance,
    /// The offset from the edge of the knob in pixels
    pub offset: f32,
}

/// Style of text marks for a [`Knob`].
///
/// [`Knob`]: ../../native/knob/struct.Knob.html
#[derive(Debug, Clone)]
pub struct TextMarksAppearance {
    /// The style of the text marks
    pub style: text_marks::Appearance,
    /// The offset from the edge of the knob in pixels
    pub offset: f32,
    /// Extra horizontal offset in pixels for each additional character
    /// in the text label. This is used to keep longer labels on the sides
    /// of the knob from being too close to the knob.
    ///
    /// The default is `3.0`.
    pub h_char_offset: f32,
    /// The vertical offset in pixels.
    ///
    /// The default is `-0.75`.
    pub v_offset: f32,
}

impl std::default::Default for TextMarksAppearance {
    fn default() -> Self {
        Self {
            style: text_marks::Appearance::default(),
            offset: 15.0,
            h_char_offset: 3.0,
            v_offset: -0.75,
        }
    }
}

/// A set of rules that dictate the style of a [`Knob`].
///
/// [`Knob`]: ../../native/knob/struct.Knob.html
pub trait StyleSheet {
    /// The supported style of the [`StyleSheet`].
    type Style: Default;

    /// Produces the style of an active [`Knob`].
    ///
    /// [`Knob`]: ../../native/knob/struct.Knob.html
    fn active(&self, style: &Self::Style) -> Appearance;

    /// Produces the style of a hovered [`Knob`].
    ///
    /// [`Knob`]: ../../native/knob/struct.Knob.html
    fn hovered(&self, style: &Self::Style) -> Appearance;

    /// Produces the style of a [`Knob`] that is being dragged.
    ///
    /// [`Knob`]: ../../native/knob/struct.Knob.html
    fn dragging(&self, style: &Self::Style) -> Appearance;

    /// a [`KnobAngleRange`] that defines the minimum and maximum angle that the
    /// knob rotates
    ///
    /// [`KnobAngleRange`]: struct.KnobAngleRange.html
    fn angle_range(&self, _style: &Self::Style) -> KnobAngleRange {
        KnobAngleRange::default()
    }

    /// The style of tick marks around a [`Knob`]
    ///
    /// For no tick marks, don't override this or set this to return `None`.
    ///
    /// [`TickMarkGroup`]: ../../core/tick_marks/struct.TickMarkGroup.html
    /// [`Knob`]: ../../native/knob/struct.Knob.html
    fn tick_marks_appearance(
        &self,
        _style: &Self::Style,
    ) -> Option<TickMarksAppearance> {
        None
    }

    /// The style of a value arc around a [`Knob`]
    ///
    /// For no value arc, don't override this or set this to return `None`.
    ///
    /// [`Knob`]: ../../native/knob/struct.Knob.html
    fn value_arc_appearance(
        &self,
        _style: &Self::Style,
    ) -> Option<ValueArcAppearance> {
        None
    }

    /// The style of a [`ModulationRange`] arc around a [`Knob`]
    ///
    /// For no modulation range arc, don't override this or set this to return `None`.
    ///
    /// [`ModulationRange`]: ../../core/struct.ModulationRange.html
    /// [`Knob`]: ../../native/knob/struct.Knob.html
    fn mod_range_arc_appearance(
        &self,
        _style: &Self::Style,
    ) -> Option<ModRangeArcAppearance> {
        None
    }

    /// The style of a second [`ModulationRange`] arc around a [`Knob`]
    ///
    /// For no second modulation range arc, don't override this or set this to return `None`.
    ///
    /// [`ModulationRange`]: ../../core/struct.ModulationRange.html
    /// [`Knob`]: ../../native/knob/struct.Knob.html
    fn mod_range_arc_appearance_2(
        &self,
        _style: &Self::Style,
    ) -> Option<ModRangeArcAppearance> {
        None
    }

    /// The style of text marks around a [`Knob`]
    ///
    /// For no text marks, don't override this or set this to return `None`.
    ///
    /// [`TextMarkGroup`]: ../../core/text_marks/struct.TextMarkGroup.html
    /// [`Knob`]: ../../native/knob/struct.Knob.html
    fn text_marks_appearance(
        &self,
        _style: &Self::Style,
    ) -> Option<TextMarksAppearance> {
        None
    }
}
