"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Symbology
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.ColorDef = void 0;
const core_geometry_1 = require("@itwin/core-geometry");
const ColorByName_1 = require("./ColorByName");
const HSLColor_1 = require("./HSLColor");
const HSVColor_1 = require("./HSVColor");
// cspell: ignore ttbbggrr bbggrr rrggbb aabbggrr abgr rrggbb hsla lerp torgb dhue dsaturation dvalue intpart fractpart cyanish
// portions adapted from Three.js Copyright © 2010-2024 three.js authors
const scratchBytes = new Uint8Array(4);
const scratchUInt32 = new Uint32Array(scratchBytes.buffer);
/** An immutable integer representation of a color.
 *
 * A color consists of 4 components: Red, Blue, Green, and Transparency. Each component is an 8-bit unsigned integer in the range [0..255]. A value of zero means that component contributes nothing
 * to the color: e.g., a color with Red=0 contains no shade of red, and a color with Transparency=0 is fully opaque. A value of 255 means that component contributes its maximum
 * value to the color: e.g., a color with Red=255 is as red as it is possible to be, and a color with Transparency=255 is fully transparent.
 *
 * Internally, these 4 components are combined into a single 32-bit unsigned integer as represented by [[ColorDefProps]]. This representation can result in some confusion regarding:
 *  1. The ordering of the individual components; and
 *  2. Whether to specify transparency or opacity (sometimes referred to as "alpha").
 *
 * ColorDef uses `0xTTBBGGRR` internally, which uses Transparency and puts Red in the low byte and Transparency in the high byte. It can be converted to `0xRRGGBB` format (blue in the low byte)
 * using [[getRgb]] and `0xAABBGGRRx format (red in the low byte, using opacity instead of transparency) using [[getAbgr]].
 *
 * A ColorDef can be created from a numeric [[ColorDefProps]], from a string in one of the common HTML formats (e.g., [[fromString]]), or by specifying values for the individual components
 * (e.g., [[from]]).
 *
 * ColorDef is **immutable**. To obtain a modified copy of a ColorDef, use methods like [[adjustedForContrast]], [[inverse]], or [[withTransparency]]. For example:
 * ```ts
 *  const semiTransparentBlue = ColorDef.blue.withTransparency(100);
 * ```
 * @public
 * @extensions
 */
class ColorDef {
    _tbgr;
    constructor(tbgr) {
        scratchUInt32[0] = tbgr; // Force to be a 32-bit unsigned integer
        this._tbgr = scratchUInt32[0];
    }
    /**
     * Create a new ColorDef.
     * @param val value to use.
     * If a number, it is interpreted as a 0xTTBBGGRR (Red in the low byte, high byte is transparency 0==fully opaque) value.
     * If a string, it must be in one of the forms supported by [[fromString]] - any unrecognized string will produce [[black]].
     */
    static create(val) {
        return this.fromTbgr(this.computeTbgr(val));
    }
    /** Compute the 0xTTBBGGRR value corresponding to the specified representation of a color.
     * @see [[fromString]] for a description of valid string representations.
     */
    static computeTbgr(val) {
        switch (typeof val) {
            case "number":
                return val;
            case "string":
                return this.computeTbgrFromString(val);
            default:
                return 0;
        }
    }
    /** Convert this ColorDef to a 32 bit number representing the 0xTTBBGGRR value */
    toJSON() { return this._tbgr; }
    /** Create a new ColorDef from a json object. If the json object is a number, it is assumed to be a 0xTTBBGGRR value. */
    static fromJSON(json) {
        return this.create(json);
    }
    /** Create a ColorDef from Red, Green, Blue, Transparency values. All inputs should be integers between 0-255. */
    static from(red, green, blue, transparency) {
        return this.fromTbgr(this.computeTbgrFromComponents(red, green, blue, transparency));
    }
    /** Compute the 0xTTBBGGRR value corresponding to the specified Red, Green, Blue, Transparency components. All inputs should be integers between 0-255. */
    static computeTbgrFromComponents(red, green, blue, transparency) {
        scratchBytes[0] = red;
        scratchBytes[1] = green;
        scratchBytes[2] = blue;
        scratchBytes[3] = transparency || 0;
        return scratchUInt32[0];
    }
    /** Create a ColorDef from its 0xTTBBGGRR representation. */
    static fromTbgr(tbgr) {
        switch (tbgr) {
            case ColorByName_1.ColorByName.black:
                return this.black;
            case ColorByName_1.ColorByName.white:
                return this.white;
            case ColorByName_1.ColorByName.red:
                return this.red;
            case ColorByName_1.ColorByName.green:
                return this.green;
            case ColorByName_1.ColorByName.blue:
                return this.blue;
            default:
                return new ColorDef(tbgr);
        }
    }
    /** Create a ColorDef from its 0xAABBGGRR representation. */
    static fromAbgr(abgr) {
        return this.fromTbgr(this.getAbgr(abgr));
    }
    /** Create a ColorDef from a string representation. The following representations are supported:
     * *"rgb(255,0,0)"*
     * *"rgba(255,0,0,.2)"*
     * *"rgb(100%,0%,0%)"*
     * *"hsl(120,50%,50%)"*
     * *"#rrbbgg"*
     * *"blanchedAlmond"* (see possible values from [[ColorByName]]). Case-insensitive.
     *
     * If `val` is not a valid color string, this function returns [[black]].
     * @see [[isValidColor]] to determine if `val` is a valid color string.
     */
    static fromString(val) {
        return this.fromTbgr(this.computeTbgrFromString(val));
    }
    /** Determine whether the input is a valid representation of a ColorDef.
     * @see [[fromString]] for the definition of a valid string representation.
     * @see [[ColorDefProps]] for the definition of a valid numeric representation.
     */
    static isValidColor(val) {
        if (typeof val === "number")
            return val >= 0 && val <= 0xffffffff && Math.floor(val) === val;
        return undefined !== this.tryComputeTbgrFromString(val);
    }
    /** Compute the 0xTTBBGGRR value corresponding to a string representation of a color.
     * If `val` is not a valid color string, this function returns 0 (black).
     * @see [[fromString]] for the definition of a valid color string.
     * @see [[tryComputeTbgrFromString]] to determine if `val` is a valid color string.
     */
    static computeTbgrFromString(val) {
        return this.tryComputeTbgrFromString(val) ?? 0;
    }
    /** Try to compute the 0xTTBBGGRR value corresponding to a string representation of a ColorDef.
     * @returns the corresponding numeric representation, or `undefined` if the input does not represent a color.
     * @see [[fromString]] for the definition of a valid color string.
     */
    static tryComputeTbgrFromString(val) {
        if (typeof val !== "string")
            return undefined;
        val = val.toLowerCase();
        let m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(val);
        if (m) { // rgb / hsl
            let color;
            const name = m[1];
            const components = m[2];
            const hasPercent = (str) => str[str.length - 1] === "%";
            const floatOrPercent = (str) => {
                const v = parseFloat(str);
                return 255 * core_geometry_1.Geometry.clamp(hasPercent(str) ? v / 100 : v, 0, 1);
            };
            const intOrPercent = (str) => {
                const v = hasPercent(str) ? (parseFloat(str) / 100) * 255 : parseInt(str, 10);
                return core_geometry_1.Geometry.clamp(v, 0, 255);
            };
            switch (name) {
                case "rgb":
                case "rgba":
                    color = /^(\d+%*)\s*[, ]\s*(\d+%*)\s*[, ]\s*(\d+%*)\s*([,\/]\s*([0-9]*\.?[0-9]+%*)\s*)?$/.exec(components);
                    if (color) { // rgb(255,0,0) rgba(255,0,0,0.5)
                        return this.computeTbgrFromComponents(intOrPercent(color[1]), intOrPercent(color[2]), intOrPercent(color[3]), typeof color[5] === "string" ? 255 - floatOrPercent(color[5]) : 0);
                    }
                    break;
                case "hsl":
                case "hsla":
                    color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(components);
                    if (color) { // hsl(120,50%,50%) hsla(120,50%,50%,0.5)
                        const h = parseFloat(color[1]) / 360;
                        const s = parseInt(color[2], 10) / 100;
                        const l = parseInt(color[3], 10) / 100;
                        const t = typeof color[5] === "string" ? 255 - floatOrPercent(color[5]) : 0;
                        return this.computeTbgrFromHSL(h, s, l, t);
                    }
                    break;
            }
        }
        else if (m = /^\#([a-f0-9]+)$/.exec(val)) { // hex color
            const hex = m[1];
            const size = hex.length;
            if (size === 3) { // #ff0
                return this.computeTbgrFromComponents(parseInt(hex.charAt(0) + hex.charAt(0), 16), parseInt(hex.charAt(1) + hex.charAt(1), 16), parseInt(hex.charAt(2) + hex.charAt(2), 16), 0);
            }
            if (size === 6) { // #ff0000
                return this.computeTbgrFromComponents(parseInt(hex.charAt(0) + hex.charAt(1), 16), parseInt(hex.charAt(2) + hex.charAt(3), 16), parseInt(hex.charAt(4) + hex.charAt(5), 16), 0);
            }
        }
        if (val && val.length > 0) { // ColorRgb value
            for (const [key, value] of Object.entries(ColorByName_1.ColorByName))
                if (key.toLowerCase() === val)
                    return value;
        }
        return undefined;
    }
    /** Get the red, green, blue, and transparency values from this ColorDef. Values will be integers between 0-255. */
    get colors() {
        return ColorDef.getColors(this._tbgr);
    }
    /** Get the r,g,b,t values encoded in an 0xTTBBGGRR value. Values will be integers between 0-255. */
    static getColors(tbgr) {
        scratchUInt32[0] = tbgr;
        return {
            b: scratchBytes[2],
            g: scratchBytes[1],
            r: scratchBytes[0],
            t: scratchBytes[3],
        };
    }
    /** The color value of this ColorDef as an integer in the form 0xTTBBGGRR (red in the low byte) */
    get tbgr() { return this._tbgr; }
    /** Get the value of the color as a number in 0xAABBGGRR format (i.e. red is in low byte). Transparency (0==fully opaque) converted to alpha (0==fully transparent).  */
    getAbgr() {
        return ColorDef.getAbgr(this._tbgr);
    }
    /** Get the value of a 0xTTBBGGRR color as a number in 0xAABBGGRR format (i.e. red is in low byte). Transparency (0==fully opaque) converted to alpha (0==fully transparent).  */
    static getAbgr(tbgr) {
        scratchUInt32[0] = tbgr;
        scratchBytes[3] = 255 - scratchBytes[3];
        return scratchUInt32[0];
    }
    /** Get the RGB value of the color as a number in 0xRRGGBB format (i.e blue is in the low byte). Transparency is ignored. Value will be from 0 to 2^24 */
    getRgb() {
        return ColorDef.getRgb(this._tbgr);
    }
    /** Get the RGB value of the 0xTTBBGGRR color as a number in 0xRRGGBB format (i.e blue is in the low byte). Transparency is ignored. Value will be from 0 to 2^24 */
    static getRgb(tbgr) {
        scratchUInt32[0] = tbgr;
        return (scratchBytes[0] << 16) + (scratchBytes[1] << 8) + scratchBytes[2];
    }
    /** Return a copy of this ColorDef with the specified alpha component.
     * @param alpha the new alpha value as an integer between 0-255.
     * @returns A ColorDef with equivalent red, green, and blue components to this one but with the specified alpha.
     */
    withAlpha(alpha) {
        const tbgr = ColorDef.withAlpha(this._tbgr, alpha);
        return tbgr === this._tbgr ? this : ColorDef.fromTbgr(tbgr);
    }
    /** Return a color equivalent to the specified 0xTTBBGGRR but with modified alpha component.
     * @param alpha the new alpha value as an integer between 0-255.
     * @returns The 0xTTBBGGRR value equivalent to `tbgr` but with the specified alpha.
     */
    static withAlpha(tbgr, alpha) {
        scratchUInt32[0] = tbgr;
        scratchBytes[3] = 255 - (alpha | 0);
        return scratchUInt32[0];
    }
    /** Get the alpha value for this ColorDef. Will be between 0-255 */
    getAlpha() {
        return ColorDef.getAlpha(this._tbgr);
    }
    /** Extract the alpha value from a 0xTTBBGGRR color. */
    static getAlpha(tbgr) {
        scratchUInt32[0] = tbgr;
        return 255 - scratchBytes[3];
    }
    /** True if this ColorDef is fully opaque. */
    get isOpaque() {
        return ColorDef.isOpaque(this._tbgr);
    }
    /** True if the specified 0xTTBBGGRR color is fully opaque. */
    static isOpaque(tbgr) {
        return 255 === this.getAlpha(tbgr);
    }
    /** Get the transparency value for this ColorDef (inverse of alpha). Will be between 0-255. */
    getTransparency() {
        return ColorDef.getTransparency(this._tbgr);
    }
    /** Extract the transparency component from a 0xTTBBGGRR color as an integer between 0-255.. */
    static getTransparency(tbgr) {
        scratchUInt32[0] = tbgr;
        return scratchBytes[3];
    }
    /** Create a copy of this ColorDef with the specified transparency.
     * @param transparency the new transparency value. Must be between 0-255, where 0 means 'fully opaque' and 255 means 'fully transparent'.
     * @returns a new ColorDef with the same color as this one and the specified transparency.
     */
    withTransparency(transparency) {
        const tbgr = ColorDef.withTransparency(this._tbgr, transparency);
        return tbgr === this._tbgr ? this : ColorDef.fromTbgr(tbgr);
    }
    /** Compute the 0xTTBBGGRR value of the specified color and transparency.
     * @param transparency the new transparency as an integer between 0-255.
     * @returns The 0xTTBBGGRR value equivalent to `tbgr` but with the specified transparency.
     */
    static withTransparency(tbgr, transparency) {
        return this.withAlpha(tbgr, 255 - transparency);
    }
    /** The "known name" for this ColorDef. Will be undefined if color value is not in [[ColorByName]] list */
    get name() {
        return ColorDef.getName(this.tbgr);
    }
    /** Obtain the name of the color in the [[ColorByName]] list associated with the specified 0xTTBBGGRR value, or undefined if no such named color exists.
     * @note A handful of colors (like "aqua" and "cyan") have identical tbgr values; in such cases the first match will be returned.
     */
    static getName(tbgr) {
        for (const [key, value] of Object.entries(ColorByName_1.ColorByName))
            if (value === tbgr)
                return key;
        return undefined;
    }
    /** Convert this ColorDef to a string in the form "#rrggbb" where values are hex digits of the respective colors */
    toHexString() {
        return ColorDef.toHexString(this.tbgr);
    }
    /** Convert the 0xTTBBGGRR value to a string in the form "#rrggbb". */
    static toHexString(tbgr) {
        return `#${(`000000${this.getRgb(tbgr).toString(16)}`).slice(-6)}`;
    }
    static getColorsString(tbgr) {
        const c = this.getColors(tbgr);
        return `${c.r},${c.g},${c.b}`;
    }
    /** Convert this ColorDef to a string in the form "rgb(r,g,b)" where values are decimal digits of the respective colors. */
    toRgbString() {
        return ColorDef.toRgbString(this.tbgr);
    }
    /** Convert the 0xTTBBGGRR color to a string in the form "rgb(r,g,b)" where each component is specified in decimal. */
    static toRgbString(tbgr) {
        return `rgb(${this.getColorsString(tbgr)})`;
    }
    /** Convert this ColorDef to a string in the form "rgba(r,g,b,a)" where color values are decimal digits and a is a fraction */
    toRgbaString() {
        return ColorDef.toRgbaString(this.tbgr);
    }
    /** Convert the 0xTTBBGGRR color to a string of the form "rgba(r,g,b,a)" where the color components are specified in decimal and the alpha component is a fraction. */
    static toRgbaString(tbgr) {
        return `rgba(${this.getColorsString(tbgr)},${this.getAlpha(tbgr) / 255.})`;
    }
    /** Create a ColorDef that is the linear interpolation of this ColorDef and another ColorDef, using a weighting factor.
     * @param color2 The other color
     * @param weight The weighting factor for color2. 0.0 = this color, 1.0 = color2.
     * @param result Optional ColorDef to hold result. If undefined, a new ColorDef is created.
     */
    lerp(color2, weight) {
        return ColorDef.fromTbgr(ColorDef.lerp(this.tbgr, color2.tbgr, weight));
    }
    /** Interpolate between two 0xTTBBGGRR colors using a weighting factor.
     * @param tbgr1 The first color
     * @param tbgr2 The other color
     * @param weight The weighting factor in [0..1]. A value of 0.0 selects `tbgr1`; 1.0 selects `tbgr2`; 0.5 mixes them evenly; etc.
     * @returns The linear interpolation between `tbgr1` and `tbgr2` using the specified weight.
     */
    static lerp(tbgr1, tbgr2, weight) {
        const c = this.getColors(tbgr1);
        const color = this.getColors(tbgr2);
        c.r += (color.r - c.r) * weight;
        c.g += (color.g - c.g) * weight;
        c.b += (color.b - c.b) * weight;
        return this.computeTbgrFromComponents(c.r, c.g, c.b, c.t);
    }
    /** Create a new ColorDef that is the inverse (all colors set to 255 - this) of this color. Ignores transparency - result has 0 transparency. */
    inverse() {
        return ColorDef.fromTbgr(ColorDef.inverse(this.tbgr));
    }
    /** Return a 0xTTBBGGRR color whose color components are the inverse of the input color. The result has 0 transparency. */
    static inverse(tbgr) {
        const colors = this.getColors(tbgr);
        return this.computeTbgrFromComponents(255 - colors.r, 255 - colors.g, 255 - colors.b);
    }
    /** Create a ColorDef from hue, saturation, lightness values */
    static fromHSL(h, s, l, transparency = 0) {
        return this.fromTbgr(this.computeTbgrFromHSL(h, s, l, transparency));
    }
    /** Compute the 0xTTBBGGRR color corresponding to the specified hue, saturation, lightness values. */
    static computeTbgrFromHSL(h, s, l, transparency = 0) {
        const torgb = (p1, q1, t) => {
            if (t < 0)
                t += 1;
            if (t > 1)
                t -= 1;
            if (t < 1 / 6)
                return p1 + (q1 - p1) * 6 * t;
            if (t < 1 / 2)
                return q1;
            if (t < 2 / 3)
                return p1 + (q1 - p1) * 6 * (2 / 3 - t);
            return p1;
        };
        const hue2rgb = (p1, q1, t) => Math.round(torgb(p1, q1, t) * 255);
        const modulo = (n, m) => ((n % m) + m) % m;
        // h,s,l ranges are in 0.0 - 1.0
        h = modulo(h, 1);
        s = core_geometry_1.Geometry.clamp(s, 0, 1);
        l = core_geometry_1.Geometry.clamp(l, 0, 1);
        if (s === 0) {
            l *= 255;
            return this.computeTbgrFromComponents(l, l, l, transparency);
        }
        const p = l <= 0.5 ? l * (1 + s) : l + s - (l * s);
        const q = (2 * l) - p;
        return this.computeTbgrFromComponents(hue2rgb(q, p, h + 1 / 3), hue2rgb(q, p, h), hue2rgb(q, p, h - 1 / 3), transparency);
    }
    /** Create an [[HSLColor]] from this ColorDef */
    toHSL() {
        // h,s,l ranges are in 0.0 - 1.0
        const col = this.colors;
        col.r /= 255;
        col.g /= 255;
        col.b /= 255;
        const max = Math.max(col.r, col.g, col.b);
        const min = Math.min(col.r, col.g, col.b);
        let hue = 0;
        let saturation;
        const lightness = (min + max) / 2.0;
        if (min === max) {
            saturation = 0;
        }
        else {
            const delta = max - min;
            saturation = lightness <= 0.5 ? delta / (max + min) : delta / (2 - max - min);
            switch (max) {
                case col.r:
                    hue = (col.g - col.b) / delta + (col.g < col.b ? 6 : 0);
                    break;
                case col.g:
                    hue = (col.b - col.r) / delta + 2;
                    break;
                case col.b:
                    hue = (col.r - col.g) / delta + 4;
                    break;
            }
            hue /= 6;
        }
        return new HSLColor_1.HSLColor(hue, saturation, lightness);
    }
    /** Create an [[HSVColor]] from this ColorDef */
    toHSV() {
        const { r, g, b } = this.colors;
        let min = (r < g) ? r : g;
        if (b < min)
            min = b;
        let max = (r > g) ? r : g;
        if (b > max)
            max = b;
        /* amount of "blackness" present */
        const v = Math.floor((max / 255.0 * 100) + 0.5);
        const deltaRgb = max - min;
        const s = (max !== 0.0) ? Math.floor((deltaRgb / max * 100) + 0.5) : 0;
        let h = 0;
        if (s) {
            const redDistance = (max - r) / deltaRgb;
            const greenDistance = (max - g) / deltaRgb;
            const blueDistance = (max - b) / deltaRgb;
            let intermediateHue;
            if (r === max) /* color between yellow & magenta */
                intermediateHue = blueDistance - greenDistance;
            else if (g === max) /* color between cyan & yellow */
                intermediateHue = 2.0 + redDistance - blueDistance;
            else /* color between magenta & cyan */
                intermediateHue = 4.0 + greenDistance - redDistance;
            /* intermediate hue is [0..6] */
            intermediateHue *= 60;
            if (intermediateHue < 0.0)
                intermediateHue += 360;
            h = Math.floor(intermediateHue + 0.5);
            if (h >= 360)
                h = 0;
        }
        else {
            h = 0;
        }
        return new HSVColor_1.HSVColor(h, s, v);
    }
    /** Create a ColorDef from an HSVColor */
    static fromHSV(hsv, transparency = 0) {
        // Check for simple case first.
        if ((!hsv.s) || (hsv.h === -1)) {
            // hue must be undefined, have no color only white
            const white = 0xff & Math.floor(((255.0 * hsv.v) / 100.0) + 0.5 + 3.0e-14);
            return ColorDef.from(white, white, white, 0);
        }
        let dhue = hsv.h, dsaturation = hsv.s, dvalue = hsv.v;
        if (dhue === 360)
            dhue = 0.0;
        dhue /= 60; // hue is now [0..6]
        const hueIntpart = Math.floor(dhue); // convert double -> int
        const hueFractpart = dhue - hueIntpart;
        dvalue /= 100;
        dsaturation /= 100;
        const p = 0xff & Math.floor((dvalue * (1.0 - dsaturation) * 255.0) + 0.5);
        const q = 0xff & Math.floor((dvalue * (1.0 - (dsaturation * hueFractpart)) * 255.0) + 0.5);
        const t = 0xff & Math.floor((dvalue * (1.0 - (dsaturation * (1.0 - hueFractpart))) * 255.0) + 0.5);
        const v = 0xff & Math.floor(dvalue * 255 + 0.5);
        let r = 0, b = 0, g = 0;
        switch (hueIntpart) {
            case 0:
                r = v;
                g = t;
                b = p;
                break; // reddish
            case 1:
                r = q, g = v;
                b = p;
                break; // yellowish
            case 2:
                r = p, g = v;
                b = t;
                break; // greenish
            case 3:
                r = p, g = q;
                b = v;
                break; // cyanish
            case 4:
                r = t, g = p;
                b = v;
                break; // bluish
            case 5:
                r = v, g = p;
                b = q;
                break; // magenta-ish
        }
        return ColorDef.from(r, g, b, transparency);
    }
    visibilityCheck(other) {
        const fg = this.colors;
        const bg = other.colors;
        // Compute luminosity
        const red = Math.abs(fg.r - bg.r);
        const green = Math.abs(fg.g - bg.g);
        const blue = Math.abs(fg.b - bg.b);
        return (0.30 * red) + (0.59 * green) + (0.11 * blue);
    }
    /**
     * Create a new ColorDef that is adjusted from this ColorDef for maximum contrast against another color. The color will either be lighter
     * or darker, depending on which has more visibility against the other color.
     * @param other the color to contrast with
     * @param alpha optional alpha value for the adjusted color. If not supplied alpha from this color is used.
     */
    adjustedForContrast(other, alpha) {
        const visibility = this.visibilityCheck(other);
        if (HSVColor_1.HSVConstants.VISIBILITY_GOAL <= visibility) {
            return undefined !== alpha ? this.withAlpha(alpha) : this;
        }
        const adjPercent = Math.floor(((HSVColor_1.HSVConstants.VISIBILITY_GOAL - visibility) / 255.0) * 100.0);
        let darkerHSV = this.toHSV();
        let brightHSV = darkerHSV.clone();
        darkerHSV = darkerHSV.adjusted(true, adjPercent);
        brightHSV = brightHSV.adjusted(false, adjPercent);
        if (undefined === alpha)
            alpha = this.getAlpha();
        const darker = ColorDef.fromHSV(darkerHSV).withAlpha(alpha);
        const bright = ColorDef.fromHSV(brightHSV).withAlpha(alpha);
        if (bright.getRgb() === other.getRgb()) // Couldn't adjust brighter...
            return darker;
        if (darker.getRgb() === other.getRgb()) // Couldn't adjust darker...
            return bright;
        // NOTE: Best choice is the one most visible against the other color...
        return (bright.visibilityCheck(other) >= darker.visibilityCheck(other)) ? bright : darker;
    }
    /** True if the value of this ColorDef is the same as another ColorDef. */
    equals(other) {
        return this._tbgr === other._tbgr;
    }
    /** pure black */
    static black = new ColorDef(ColorByName_1.ColorByName.black);
    /** pure white */
    static white = new ColorDef(ColorByName_1.ColorByName.white);
    /** pure red */
    static red = new ColorDef(ColorByName_1.ColorByName.red);
    /** pure green */
    static green = new ColorDef(ColorByName_1.ColorByName.green);
    /** pure blue */
    static blue = new ColorDef(ColorByName_1.ColorByName.blue);
}
exports.ColorDef = ColorDef;
//# sourceMappingURL=ColorDef.js.map