import fractions
import re


_WHITESPACE = "[ \t\n\r\f]"
_HEX_DIGIT = "[0-9a-fA-F]"
_INTEGER = "[+-]?[0-9]+"
_NUMBER = rf"(?:{_INTEGER}|[+-]?[0-9]*\.[0-9]+)"
_PERCENTAGE = f"{_NUMBER}%"
_FLAGS = re.ASCII | re.IGNORECASE
THREE_DIGIT_HEX_PATTERN = re.compile(
    "#{}{}{}".format(f"({_HEX_DIGIT})", f"({_HEX_DIGIT})", f"({_HEX_DIGIT})"),
    flags=_FLAGS)
SIX_DIGIT_HEX_PATTERN = re.compile(
    "#{}{}{}".format(
        f"({_HEX_DIGIT}{{2}})", f"({_HEX_DIGIT}{{2}})",
        f"({_HEX_DIGIT}{{2}})"),
    flags=_FLAGS)
INTEGER_RGB_FUNCTION_PATTERN = re.compile(
    r"rgb\({},{},{}\)".format(
        f"{_WHITESPACE}*({_INTEGER}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_INTEGER}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_INTEGER}){_WHITESPACE}*"),
    flags=_FLAGS)
PERCENTAGE_RGB_FUNCTION_PATTERN = re.compile(
    r"rgb\({},{},{}\)".format(
        f"{_WHITESPACE}*({_PERCENTAGE}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_PERCENTAGE}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_PERCENTAGE}){_WHITESPACE}*"),
    flags=_FLAGS)
INTEGER_RGBA_FUNCTION_PATTERN = re.compile(
    r"rgba\({},{},{},{}\)".format(
        f"{_WHITESPACE}*({_INTEGER}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_INTEGER}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_INTEGER}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_NUMBER}){_WHITESPACE}*"),
    flags=_FLAGS)
PERCENTAGE_RGBA_FUNCTION_PATTERN = re.compile(
    r"rgba\({},{},{},{}\)".format(
        f"{_WHITESPACE}*({_PERCENTAGE}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_PERCENTAGE}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_PERCENTAGE}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_NUMBER}){_WHITESPACE}*"),
    flags=_FLAGS)
HSL_FUNCTION_PATTERN = re.compile(
    r"hsl\({},{},{}\)".format(
        f"{_WHITESPACE}*({_NUMBER}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_PERCENTAGE}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_PERCENTAGE}){_WHITESPACE}*"),
    flags=_FLAGS)
HSLA_FUNCTION_PATTERN = re.compile(
    r"hsla\({},{},{},{}\)".format(
        f"{_WHITESPACE}*({_NUMBER}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_PERCENTAGE}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_PERCENTAGE}){_WHITESPACE}*",
        f"{_WHITESPACE}*({_NUMBER}){_WHITESPACE}*"),
    flags=_FLAGS)


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