 import class UIKit.UIColor
 import struct CoreGraphics.CGFloat
 
-public enum ColorComponents {
+public enum ColorComponents: Hashable, Codable {
     public static let blackRGBA: ColorComponents = .rgba(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0)
     public static let blackHSBA: ColorComponents = .hsba(hue: 0.0, saturation: 0.0, brightness: 0.0, alpha: 1.0)
     public static let blackBWA:  ColorComponents = .bwa(white: 0.0, alpha: 1.0)

    case rgba(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)
    case hsba(hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat)
    case bwa(white: CGFloat, alpha: CGFloat)
    
    public var color: UIColor { return UIColor(components: self) }

    public mutating func update(from color: UIColor) -> Bool {
        var updated = false
        switch self {
        case .rgba(var red, var green, var blue, var alpha):
            updated = color.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
            self = .rgba(red: red, green: green, blue: blue, alpha: alpha)
        case .hsba(var hue, var saturation, var brightness, var alpha):
            updated = color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
            self = .hsba(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha)
        case .bwa(var white, var alpha):
            updated = color.getWhite(&white, alpha: &alpha)
            self = .bwa(white: white, alpha: alpha)
        }
        return updated
    }
    
    // Extract brightness. Alpha is ignored. Calculated according to http://www.w3.org/WAI/ER/WD-AERT/#color-contrast for RGBA.
    public var brightness: CGFloat {

            self = .bwa(white: applyChange(to: white), alpha: alpha)
        }
    }
}

extension ColorComponents {
    public var color: UIColor { return UIColor(components: self) }

    public mutating func update(from color: UIColor) -> Bool {
        var updated = false
        switch self {
        case .rgba(var red, var green, var blue, var alpha):
            updated = color.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
            self = .rgba(red: red, green: green, blue: blue, alpha: alpha)
        case .hsba(var hue, var saturation, var brightness, var alpha):
            updated = color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
            self = .hsba(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha)
        case .bwa(var white, var alpha):
            updated = color.getWhite(&white, alpha: &alpha)
            self = .bwa(white: white, alpha: alpha)
        }
        return updated
    }

    // Will try in the following order:
    // - rgba
    // - hsba
