#! perl

use v5.26;
use Object::Pad;
use utf8;

class SVGPDF::Colour;

field $colour   :accessor :param = undef;
field $red	:accessor :param = undef;
field $green	:accessor :param = undef;
field $blue	:accessor :param = undef;
field $alpha	:accessor :param = undef;

my @colours = qw( red green blue alpha );

use constant GREY => 128;

# The official 147 SVG coulr names.
my %colours =
  ( aliceblue		  => "#F0F8FF",
    antiquewhite	  => "#FAEBD7",
    aqua		  => "#00FFFF",
    aquamarine		  => "#7FFFD4",
    azure		  => "#F0FFFF",
    beige		  => "#F5F5DC",
    bisque		  => "#FFE4C4",
    black		  => "#000000",
    blanchedalmond	  => "#FFEBCD",
    blue		  => "#0000FF",
    blueviolet		  => "#8A2BE2",
    brown		  => "#A52A2A",
    burlywood		  => "#DEB887",
    cadetblue		  => "#5F9EA0",
    chartreuse		  => "#7FFF00",
    chocolate		  => "#D2691E",
    coral		  => "#FF7F50",
    cornflowerblue	  => "#6495ED",
    cornsilk		  => "#FFF8DC",
    crimson		  => "#DC143C",
    cyan		  => "#00FFFF",
    darkblue		  => "#00008B",
    darkcyan		  => "#008B8B",
    darkgoldenrod	  => "#B8860B",
    darkgray		  => "#A9A9A9",
    darkgreen		  => "#006400",
    darkgrey		  => "#A9A9A9",
    darkkhaki		  => "#BDB76B",
    darkmagenta		  => "#8B008B",
    darkolivegreen	  => "#556B2F",
    darkorange		  => "#FF8C00",
    darkorchid		  => "#9932CC",
    darkred		  => "#8B0000",
    darksalmon		  => "#E9967A",
    darkseagreen	  => "#8FBC8F",
    darkslateblue	  => "#483D8B",
    darkslategray	  => "#2F4F4F",
    darkslategrey	  => "#2F4F4F",
    darkturquoise	  => "#00CED1",
    darkviolet		  => "#9400D3",
    deeppink		  => "#FF1493",
    deepskyblue		  => "#00BFFF",
    dimgray		  => "#696969",
    dimgrey		  => "#696969",
    dodgerblue		  => "#1E90FF",
    firebrick		  => "#B22222",
    floralwhite		  => "#FFFAF0",
    forestgreen		  => "#228B22",
    fuchsia		  => "#FF00FF",
    gainsboro		  => "#DCDCDC",
    ghostwhite		  => "#F8F8FF",
    gold		  => "#FFD700",
    goldenrod		  => "#DAA520",
    gray		  => "#808080",
    green		  => "#008000",
    greenyellow		  => "#ADFF2F",
    grey		  => "#808080",
    honeydew		  => "#F0FFF0",
    hotpink		  => "#FF69B4",
    indianred		  => "#CD5C5C",
    indigo		  => "#4B0082",
    ivory		  => "#FFFFF0",
    khaki		  => "#F0E68C",
    lavender		  => "#E6E6FA",
    lavenderblush	  => "#FFF0F5",
    lawngreen		  => "#7CFC00",
    lemonchiffon	  => "#FFFACD",
    lightblue		  => "#ADD8E6",
    lightcoral		  => "#F08080",
    lightcyan		  => "#E0FFFF",
    lightgoldenrodyellow  => "#FAFAD2",
    lightgray		  => "#D3D3D3",
    lightgreen		  => "#90EE90",
    lightgrey		  => "#D3D3D3",
    lightpink		  => "#FFB6C1",
    lightsalmon		  => "#FFA07A",
    lightseagreen	  => "#20B2AA",
    lightskyblue	  => "#87CEFA",
    lightslategray	  => "#778899",
    lightslategrey	  => "#778899",
    lightsteelblue	  => "#B0C4DE",
    lightyellow		  => "#FFFFE0",
    lime		  => "#00FF00",
    limegreen		  => "#32CD32",
    linen		  => "#FAF0E6",
    magenta		  => "#FF00FF",
    maroon		  => "#800000",
    mediumaquamarine	  => "#66CDAA",
    mediumblue		  => "#0000CD",
    mediumorchid	  => "#BA55D3",
    mediumpurple	  => "#9370DB",
    mediumseagreen	  => "#3CB371",
    mediumslateblue	  => "#7B68EE",
    mediumspringgreen	  => "#00FA9A",
    mediumturquoise	  => "#48D1CC",
    mediumvioletred	  => "#C71585",
    midnightblue	  => "#191970",
    mintcream		  => "#F5FFFA",
    mistyrose		  => "#FFE4E1",
    moccasin		  => "#FFE4B5",
    navajowhite		  => "#FFDEAD",
    navy		  => "#000080",
    oldlace		  => "#FDF5E6",
    olive		  => "#808000",
    olivedrab		  => "#6B8E23",
    orange		  => "#FFA500",
    orangered		  => "#FF4500",
    orchid		  => "#DA70D6",
    palegoldenrod	  => "#EEE8AA",
    palegreen		  => "#98FB98",
    paleturquoise	  => "#AFEEEE",
    palevioletred	  => "#DB7093",
    papayawhip		  => "#FFEFD5",
    peachpuff		  => "#FFDAB9",
    peru		  => "#CD853F",
    pink		  => "#FFC0CB",
    plum		  => "#DDA0DD",
    powderblue		  => "#B0E0E6",
    purple		  => "#800080",
    red			  => "#FF0000",
    rosybrown		  => "#BC8F8F",
    royalblue		  => "#4169E1",
    saddlebrown		  => "#8B4513",
    salmon		  => "#FA8072",
    sandybrown		  => "#F4A460",
    seagreen		  => "#2E8B57",
    seashell		  => "#FFF5EE",
    sienna		  => "#A0522D",
    silver		  => "#C0C0C0",
    skyblue		  => "#87CEEB",
    slateblue		  => "#6A5ACD",
    slategray		  => "#708090",
    slategrey		  => "#708090",
    snow		  => "#FFFAFA",
    springgreen		  => "#00FF7F",
    steelblue		  => "#4682B4",
    tan			  => "#D2B48C",
    teal		  => "#008080",
    thistle		  => "#D8BFD8",
    tomato		  => "#FF6347",
    turquoise		  => "#40E0D0",
    violet		  => "#EE82EE",
    wheat		  => "#F5DEB3",
    white		  => "#FFFFFF",
    whitesmoke		  => "#F5F5F5",
    yellow		  => "#FFFF00",
    yellowgreen		  => "#9ACD32",
  );

use Carp;

ADJUST {
    my ( $r, $g, $b, $a );
    if ( defined $colour ) {
	( $r, $g, $b, $a ) = $self->_parse($colour);
    }
    $red   //= $r // 0;
    $green //= $g // 0;
    $blue  //= $b // 0;
    $alpha //= $a // 0;
    $self->_check();
};

method _parse( $col ) {
    $col =~ s/\s+//g;
    $col = lc($col);
    my ( $r, $g, $b, $a ) = ( GREY, GREY, GREY, GREY );
    if ( $col =~ /^rgb\((.+?),(.+?),(.+?)\)$/ ) {
	( $r, $g, $b, $a ) = ( $1, $2, $3, 0 );
    }
    elsif ( $col =~ /^rgba\((.+?),(.+?),(.+?),(.+?)\)$/ ) {
	( $r, $g, $b, $a ) = ( $1, $2, $3, $4 );
    }
    elsif ( $col =~ /^\#([a-f0-9]+)$/ ) {
	if ( length($1) == 6 || length($1) == 8 ) {
	    # HEX: RRGGBB of RRGGBBAA.
	    $r = hex(substr( $1, 0, 2 ));
	    $g = hex(substr( $1, 2, 2 ));
	    $b = hex(substr( $1, 4, 2 ));
	    $a = hex(substr( $1, 6, 2 )) if length($1) == 8;
	}
	elsif ( length($1) == 3 || length($1) == 4 ) {
	    # Shorthand HEX: RGB => RRGGBB.
	    $r = hex(substr( $1, 0, 1 ).substr( $1, 0, 1 ));
	    $g = hex(substr( $1, 1, 1 ).substr( $1, 1, 1 ));
	    $b = hex(substr( $1, 2, 1 ).substr( $1, 2, 1 ));
	    $a = hex(substr( $1, 3, 1 ).substr( $1, 3, 1 )) if length($1) == 4;
	}
    }
    elsif ( defined $colours{$col} ) {
	# Known. Parse HEX.
	return $self->_parse($colours{$col});
    }
    elsif ( $col =~ /^url\(/ ) {
	return $self->_parse($colours{"grey"});
    }
    else {
	carp("Illegal colour \"$col\"");
    }
    my $i = 0;
    for ( $r, $g, $b, $a ) {
	if ( /^(\d+(?:\.\d+)?)\%$/ ) {	# 98.27%
	    $_ = $1 / 100 * 255;
	}
	elsif ( /^\d+$/ ) {		# 124
	    # ok
	}
	else {
	    carp("Illegal colour value $colours[$i]: $_");
	    $_ = GREY;
	}
	$i++;
    }
    return ( $r, $g, $b, $a );
}

method _check() {
    my $i = 0;
    for ( $red, $green, $blue, $alpha ) {
	next if $_ >= 0 && $_ <= 255;
	carp("Illegal colour value $colours[$i]: $_");
	$_ = GREY,
    }
}

method parse( $col = $colour ) {
    ( $red, $green, $blue, $alpha ) = _parse($col);
    $self->_check;
}

method rgb() {
    sprintf( "#%02X%02X%02X", $red, $green, $blue );
}

method rgba() {
    sprintf( "#%02X%02X%02X%02X", $red, $green, $blue, $alpha );
}

1;
