--- SILE color type.
-- @types color

local colornames = {
   aliceblue = { 240, 248, 255 },
   antiquewhite = { 250, 235, 215 },
   aqua = { 0, 255, 255 },
   aquamarine = { 127, 255, 212 },
   azure = { 240, 255, 255 },
   beige = { 245, 245, 220 },
   bisque = { 255, 228, 196 },
   black = { 0, 0, 0 },
   blanchedalmond = { 255, 235, 205 },
   blue = { 0, 0, 255 },
   blueviolet = { 138, 43, 226 },
   brown = { 165, 42, 42 },
   burlywood = { 222, 184, 135 },
   cadetblue = { 95, 158, 160 },
   chartreuse = { 127, 255, 0 },
   chocolate = { 210, 105, 30 },
   coral = { 255, 127, 80 },
   cornflowerblue = { 100, 149, 237 },
   cornsilk = { 255, 248, 220 },
   crimson = { 220, 20, 60 },
   cyan = { 0, 255, 255 },
   darkblue = { 0, 0, 139 },
   darkcyan = { 0, 139, 139 },
   darkgoldenrod = { 184, 134, 11 },
   darkgray = { 169, 169, 169 },
   darkgreen = { 0, 100, 0 },
   darkgrey = { 169, 169, 169 },
   darkkhaki = { 189, 183, 107 },
   darkmagenta = { 139, 0, 139 },
   darkolivegreen = { 85, 107, 47 },
   darkorange = { 255, 140, 0 },
   darkorchid = { 153, 50, 204 },
   darkred = { 139, 0, 0 },
   darksalmon = { 233, 150, 122 },
   darkseagreen = { 143, 188, 143 },
   darkslateblue = { 72, 61, 139 },
   darkslategray = { 47, 79, 79 },
   darkslategrey = { 47, 79, 79 },
   darkturquoise = { 0, 206, 209 },
   darkviolet = { 148, 0, 211 },
   deeppink = { 255, 20, 147 },
   deepskyblue = { 0, 191, 255 },
   dimgray = { 105, 105, 105 },
   dimgrey = { 105, 105, 105 },
   dodgerblue = { 30, 144, 255 },
   firebrick = { 178, 34, 34 },
   floralwhite = { 255, 250, 240 },
   forestgreen = { 34, 139, 34 },
   fuchsia = { 255, 0, 255 },
   gainsboro = { 220, 220, 220 },
   ghostwhite = { 248, 248, 255 },
   gold = { 255, 215, 0 },
   goldenrod = { 218, 165, 32 },
   gray = { 128, 128, 128 },
   grey = { 128, 128, 128 },
   green = { 0, 128, 0 },
   greenyellow = { 173, 255, 47 },
   honeydew = { 240, 255, 240 },
   hotpink = { 255, 105, 180 },
   indianred = { 205, 92, 92 },
   indigo = { 75, 0, 130 },
   ivory = { 255, 255, 240 },
   khaki = { 240, 230, 140 },
   lavender = { 230, 230, 250 },
   lavenderblush = { 255, 240, 245 },
   lawngreen = { 124, 252, 0 },
   lemonchiffon = { 255, 250, 205 },
   lightblue = { 173, 216, 230 },
   lightcoral = { 240, 128, 128 },
   lightcyan = { 224, 255, 255 },
   lightgoldenrodyellow = { 250, 250, 210 },
   lightgray = { 211, 211, 211 },
   lightgreen = { 144, 238, 144 },
   lightgrey = { 211, 211, 211 },
   lightpink = { 255, 182, 193 },
   lightsalmon = { 255, 160, 122 },
   lightseagreen = { 32, 178, 170 },
   lightskyblue = { 135, 206, 250 },
   lightslategray = { 119, 136, 153 },
   lightslategrey = { 119, 136, 153 },
   lightsteelblue = { 176, 196, 222 },
   lightyellow = { 255, 255, 224 },
   lime = { 0, 255, 0 },
   limegreen = { 50, 205, 50 },
   linen = { 250, 240, 230 },
   magenta = { 255, 0, 255 },
   maroon = { 128, 0, 0 },
   mediumaquamarine = { 102, 205, 170 },
   mediumblue = { 0, 0, 205 },
   mediumorchid = { 186, 85, 211 },
   mediumpurple = { 147, 112, 219 },
   mediumseagreen = { 60, 179, 113 },
   mediumslateblue = { 123, 104, 238 },
   mediumspringgreen = { 0, 250, 154 },
   mediumturquoise = { 72, 209, 204 },
   mediumvioletred = { 199, 21, 133 },
   midnightblue = { 25, 25, 112 },
   mintcream = { 245, 255, 250 },
   mistyrose = { 255, 228, 225 },
   moccasin = { 255, 228, 181 },
   navajowhite = { 255, 222, 173 },
   navy = { 0, 0, 128 },
   oldlace = { 253, 245, 230 },
   olive = { 128, 128, 0 },
   olivedrab = { 107, 142, 35 },
   orange = { 255, 165, 0 },
   orangered = { 255, 69, 0 },
   orchid = { 218, 112, 214 },
   palegoldenrod = { 238, 232, 170 },
   palegreen = { 152, 251, 152 },
   paleturquoise = { 175, 238, 238 },
   palevioletred = { 219, 112, 147 },
   papayawhip = { 255, 239, 213 },
   peachpuff = { 255, 218, 185 },
   peru = { 205, 133, 63 },
   pink = { 255, 192, 203 },
   plum = { 221, 160, 221 },
   powderblue = { 176, 224, 230 },
   purple = { 128, 0, 128 },
   rebeccapurple = { 102, 51, 153 },
   red = { 255, 0, 0 },
   rosybrown = { 188, 143, 143 },
   royalblue = { 65, 105, 225 },
   saddlebrown = { 139, 69, 19 },
   salmon = { 250, 128, 114 },
   sandybrown = { 244, 164, 96 },
   seagreen = { 46, 139, 87 },
   seashell = { 255, 245, 238 },
   sienna = { 160, 82, 45 },
   silver = { 192, 192, 192 },
   skyblue = { 135, 206, 235 },
   slateblue = { 106, 90, 205 },
   slategray = { 112, 128, 144 },
   slategrey = { 112, 128, 144 },
   snow = { 255, 250, 250 },
   springgreen = { 0, 255, 127 },
   steelblue = { 70, 130, 180 },
   tan = { 210, 180, 140 },
   teal = { 0, 128, 128 },
   thistle = { 216, 191, 216 },
   tomato = { 255, 99, 71 },
   turquoise = { 64, 224, 208 },
   violet = { 238, 130, 238 },
   wheat = { 245, 222, 179 },
   white = { 255, 255, 255 },
   whitesmoke = { 245, 245, 245 },
   yellow = { 255, 255, 0 },
   yellowgreen = { 154, 205, 50 },
}

local color = pl.class({
   type = "color",
   -- Default values amount to much "darkness in the void"
   r = nil,
   g = nil,
   b = nil,
   c = nil,
   m = nil,
   y = nil,
   k = nil,
   l = nil,
})

function color:_init (input)
   local c = type(input) == "string" and self:parse(input) or input
   for k, v in pairs(c) do
      self[k] = v
   end
end

function color:__tostring ()
   local p = {}
   for _, k in pairs({ "r", "g", "b", "c", "m", "y", "k", "l" }) do
      if self[k] then
         table.insert(p, k .. SU.debug_round(self[k]))
      end
   end
   return ("C<%s>"):format(pl.pretty.write(p, ""):gsub('[{}"]', ""))
end

function color:parse (input)
   local r, g, b, c, m, y, k, l
   if not input or type(input) ~= "string" then
      SU.error("Not a color specification string (" .. tostring(input) .. ")")
   end
   local named = colornames[string.lower(input)]
   if named then
      return { r = named[1] / 255, g = named[2] / 255, b = named[3] / 255 }
   end
   r, g, b = input:match("^#(%x%x)(%x%x)(%x%x)$")
   if r then
      return { r = tonumber("0x" .. r) / 255, g = tonumber("0x" .. g) / 255, b = tonumber("0x" .. b) / 255 }
   end
   r, g, b = input:match("^#(%x)(%x)(%x)$")
   if r then
      return { r = tonumber("0x" .. r) / 15, g = tonumber("0x" .. g) / 15, b = tonumber("0x" .. b) / 15 }
   end
   c, m, y, k = input:match("^(%d+%.?%d*)%s+(%d+%.?%d*)%s+(%d+%.?%d*)%s+(%d+%.?%d*)$")
   if c then
      return { c = tonumber(c) / 255, m = tonumber(m) / 255, y = tonumber(y) / 255, k = tonumber(k) / 255 }
   end
   c, m, y, k = input:match("^(%d+%.?%d*)%%%s+(%d+%.?%d*)%%%s+(%d+%.?%d*)%%%s+(%d+%.?%d*)%%$")
   if c then
      return { c = tonumber(c) / 100, m = tonumber(m) / 100, y = tonumber(y) / 100, k = tonumber(k) / 100 }
   end
   r, g, b = input:match("^(%d+%.?%d*)%s+(%d+%.?%d*)%s+(%d+%.?%d*)$")
   if r then
      return { r = tonumber(r) / 255, g = tonumber(g) / 255, b = tonumber(b) / 255 }
   end
   r, g, b = input:match("^(%d+%.?%d*)%%%s+(%d+%.?%d*)%%%s+(%d+%.?%d*)%%$")
   if r then
      return { r = tonumber(r) / 100, g = tonumber(g) / 100, b = tonumber(b) / 100 }
   end
   l = input:match("^(%d+.?%d*)$")
   if l then
      return { l = tonumber(l) / 255 }
   end
   SU.error("Unparsable color " .. input)
end

return color
