# colorHelper.js

    // @formatter:off
    /**
     * Definition of CSS color names
     * @type {Array}
     */
    const colorNames = {
    		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",            darkkhaki: "#bdb76b",
    		darkmagenta: "#8b008b",        darkolivegreen: "#556b2f",       darkorange: "#ff8c00",
    		darkorchid: "#9932cc",         darkred: "#8b0000",              darksalmon: "#e9967a",
    		darkseagreen: "#8fbc8f",       darkslateblue: "#483d8b",        darkslategray: "#2f4f4f",
    		darkturquoise: "#00ced1",      darkviolet: "#9400d3",           deeppink: "#ff1493",
    		deepskyblue: "#00bfff",        dimgray: "#696969",              dodgerblue: "#1e90ff",
    		feldspar: "#d19275",           firebrick: "#b22222",            floralwhite: "#fffaf0",
    		forestgreen: "#228b22",        fuchsia: "#ff00ff",              gainsboro: "#dcdcdc",
    		ghostwhite: "#f8f8ff",         gold: "#ffd700",                 goldenrod: "#daa520",
    		gray: "#808080",               green: "#008000",                greenyellow: "#adff2f",
    		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", lightgrey: "#d3d3d3",
    		lightgreen: "#90ee90",         lightpink: "#ffb6c1",            lightsalmon: "#ffa07a",
    		lightseagreen: "#20b2aa",      lightskyblue: "#87cefa",         lightslateblue: "#8470ff",
    		lightslategray: "#778899",     lightsteelblue: "#b0c4de",       lightyellow: "#ffffe0",
    		lime: "#00ff00",               limegreen: "#32cd32",            linen: "#faf0e6",
    		magenta: "#ff00ff",            maroon: "#800000",               mediumaquamarine: "#66cdaa",
    		mediumblue: "#0000cd",         mediumorchid: "#ba55d3",         mediumpurple: "#9370d8",
    		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: "#d87093",
    		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",            snow: "#fffafa",
    		springgreen: "#00ff7f",        steelblue: "#4682b4",            tan: "#d2b48c",
    		teal: "#008080",               thistle: "#d8bfd8",              tomato: "#ff6347",
    		turquoise: "#40e0d0",          violet: "#ee82ee",               violetred: "#d02090",
    		wheat: "#f5deb3",              white: "#ffffff",                whitesmoke: "#f5f5f5",
    		yellow: "#ffff00",             yellowgreen: "#9acd32"
    	};
    // @formatter:on

    /**
     * Color Name to Hex
     *
     * @param {string} colorName
     * @returns {boolean|*}
     */
    function colourNameToHex(colorName) {
    	if (typeof colorNames[colorName.toLowerCase()] !== "undefined") {
    		return colorNames[colorName.toLowerCase()];
    	}
    	return false;
    }

    /**
     * Color Component to Hex
     *
     * @param {number} c
     * @returns {string}
     */
    function componentToHex(c) {
    	const hex = c.toString(16);
    	return hex.length === 1 ? "0" + hex : hex;
    }

    /**
     * Color RGB to Hex
     *
     * @param {number} r
     * @param {number} g
     * @param {number} b
     * @returns {string}
     */
    function rgbToHex(r, g, b) {
    	return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
    }

    /**
     * RGB Colour to Hex Converter
     *
     * @param {string} rgbStr - RGB colour string (e.g. "rgb(155, 102, 102)").
     * @returns {string} - Hex Color (e.g. "#9b6666").
     */
    function rgb2Hex(rgbStr) {
    	const [red, green, blue] = rgbStr.substring(4, rgbStr.length - 1).replace(/ /g, "").split(",");
    	let rgb = blue | (green << 8) | (red << 16); // eslint-disable-line no-bitwise
    	return "#" + (0x1000000 + rgb).toString(16).slice(1);
    }

    /**
     * Color Hex to RGB
     *
     * @param {string} hex
     * @returns {*}
     */
    function hexToRgb(hex) {
    	const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    	return result ? {
    		r: parseInt(result[1], 16),
    		g: parseInt(result[2], 16),
    		b: parseInt(result[3], 16)
    	} : null;
    }

    /**
     * Color Hex to X3D RGB
     *
     * @param {string} hex
     * @returns {string}
     */
    function hexToX3d(hex) {
    	const rgb = hexToRgb(hex);
    	return `${rgb.r / 255} ${rgb.g / 255} ${rgb.b / 255}`;
    }

    /**
     * Color Name to X3D RGB
     *
     * @param {string} colorName
     * @returns {string}
     */
    function colourNameToX3d(colorName) {
    	const rgb = hexToRgb(colourNameToHex(colorName));
    	return `${rgb.r / 255} ${rgb.g / 255} ${rgb.b / 255}`;
    }

    /**
     * X3D Color Parser
     *
     * @param {Rgb|Hsl|null} color
     * @returns {string}
     */
    export function colorParse(color) {
    	let red = 0;
    	let green = 0;
    	let blue = 0;
    	let alpha = 0;

    	// Already matches X3D RGB
    	const x3dMatch = /^(0+\.?\d*|1\.?0*)\s+(0+\.?\d*|1\.?0*)\s+(0+\.?\d*|1\.?0*)$/.exec(color);
    	if (x3dMatch !== null) {
    		red = +x3dMatch[1];
    		green = +x3dMatch[2];
    		blue = +x3dMatch[3];
    	}

    	// Matches CSS rgb() function
    	const rgbMatch = /^rgb\((\d{1,3}),\s{0,1}(\d{1,3}),\s{0,1}(\d{1,3})\)$/.exec(color);
    	if (rgbMatch !== null) {
    		red = rgbMatch[1] / 255.0;
    		green = rgbMatch[2] / 255.0;
    		blue = rgbMatch[3] / 255.0;
    	}

    	// Matches CSS color name
    	if (colorNames[color]) {
    		color = colorNames[color];
    	}

    	// Hexadecimal color codes
    	if (color.substr && color.substr(0, 1) === "#") {
    		const hex = color.substr(1);
    		const len = hex.length;

    		if (len === 8) {
    			red = parseInt("0x" + hex.substr(0, 2), 16) / 255.0;
    			green = parseInt("0x" + hex.substr(2, 2), 16) / 255.0;
    			blue = parseInt("0x" + hex.substr(4, 2), 16) / 255.0;
    			alpha = parseInt("0x" + hex.substr(6, 2), 16) / 255.0;
    		} else if (len === 6) {
    			red = parseInt("0x" + hex.substr(0, 2), 16) / 255.0;
    			green = parseInt("0x" + hex.substr(2, 2), 16) / 255.0;
    			blue = parseInt("0x" + hex.substr(4, 2), 16) / 255.0;
    			alpha = 1.0;
    		} else if (len === 4) {
    			red = parseInt("0x" + hex.substr(0, 1), 16) / 15.0;
    			green = parseInt("0x" + hex.substr(1, 1), 16) / 15.0;
    			blue = parseInt("0x" + hex.substr(2, 1), 16) / 15.0;
    			alpha = parseInt("0x" + hex.substr(3, 1), 16) / 15.0;
    		} else if (len === 3) {
    			red = parseInt("0x" + hex.substr(0, 1), 16) / 15.0;
    			green = parseInt("0x" + hex.substr(1, 1), 16) / 15.0;
    			blue = parseInt("0x" + hex.substr(2, 1), 16) / 15.0;
    			alpha = 1.0;
    		}
    	}

    	red = red.toFixed(4);
    	green = green.toFixed(4);
    	blue = blue.toFixed(4);

    	return `${red} ${green} ${blue}`;
    }