"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ColorPalette = exports.Color = exports.rgb2hsl = exports.hsla2rgba = exports.hsl2rgb = void 0;
const gl_matrix_1 = require("gl-matrix");
const math_1 = require("./math");
const mathvm_1 = require("./mathvm");
const utils_1 = require("./utils");
const hsl2rgb = (out, h, s, l) => {
    const C = (1 - Math.abs(2 * l - 1)) * s;
    const hh = h * 6;
    const X = C * (1 - Math.abs((hh % 2) - 1));
    const m = l - C * 0.5;
    let r = 0;
    let g = 0;
    let b = 0;
    if (hh >= 0 && hh < 1) {
        r = C;
        g = X;
    }
    else if (hh >= 1 && hh < 2) {
        r = X;
        g = C;
    }
    else if (hh >= 2 && hh < 3) {
        g = C;
        b = X;
    }
    else if (hh >= 3 && hh < 4) {
        g = X;
        b = C;
    }
    else if (hh >= 4 && hh < 5) {
        r = X;
        b = C;
    }
    else {
        r = C;
        b = X;
    }
    out[0] = r + m;
    out[1] = g + m;
    out[2] = b + m;
};
exports.hsl2rgb = hsl2rgb;
const hsla2rgba = (out, h, s, l, a) => {
    exports.hsl2rgb(out, h, s, l);
    out[3] = a;
};
exports.hsla2rgba = hsla2rgba;
const rgb2hsl = (out, r255, g255, b255) => {
    const r = r255 / 255;
    const g = g255 / 255;
    const b = b255 / 255;
    const max = Math.max(r, g, b);
    const min = Math.min(r, g, b);
    const l = (max + min) * 0.5;
    let h = 0;
    let s = 0;
    if (max === min) {
        h = s = 0;
    }
    else {
        const d = max - min;
        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
        switch (max) {
            case r:
                h = (g - b) / d + (g < b ? 6 : 0);
                break;
            case g:
                h = (b - r) / d + 2;
                break;
            case b:
                h = (r - g) / d + 4;
                break;
        }
        h = h / 6;
    }
    out[0] = h;
    out[1] = s;
    out[2] = l;
};
exports.rgb2hsl = rgb2hsl;
class Color {
    constructor(colorHSLA) {
        this.hsla = gl_matrix_1.vec4.create();
        this.rgba = gl_matrix_1.vec4.create();
        gl_matrix_1.vec4.copy(this.hsla, colorHSLA);
        this.update();
    }
    static fromRGBA(r, g, b, a) {
        const c = new Color(gl_matrix_1.vec4.fromValues(0, 0, 0, 0));
        c.setRGBA(gl_matrix_1.vec4.fromValues(r, g, b, a));
        return c;
    }
    static fromHSLA(h, s = 1.0, l = 0.5, a = 1.0) {
        const c = new Color(gl_matrix_1.vec4.fromValues(h, s, l, a));
        return c;
    }
    static random() {
        return new Color(gl_matrix_1.vec4.fromValues(math_1.lqrandomSync(), math_1.lqrandomSync() * 0.3 + 0.3, 0.4 + math_1.lqrandomSync() * 0.15, 1));
    }
    setHSLA(colorHSLA) {
        gl_matrix_1.vec4.copy(this.hsla, colorHSLA);
        this.update();
    }
    setRGBA(colorRGBA) {
        gl_matrix_1.vec4.copy(this.rgba, colorRGBA);
        exports.rgb2hsl(this.hsla, colorRGBA[0], colorRGBA[1], colorRGBA[2]);
        this.hsla[3] = this.rgba[3];
    }
    set(color) {
        gl_matrix_1.vec4.copy(this.hsla, color.hsla);
        gl_matrix_1.vec4.copy(this.rgba, color.rgba);
    }
    setAlpha(color, alpha) {
        gl_matrix_1.vec4.copy(this.hsla, color.hsla);
        gl_matrix_1.vec4.copy(this.rgba, color.rgba);
        this.hsla[3] = alpha;
        this.rgba[3] = alpha;
    }
    h(hue) {
        this.hsla[0] = hue;
        this.update();
    }
    s(saturation) {
        this.hsla[0] = saturation;
        this.update();
    }
    l(lightness) {
        this.hsla[0] = lightness;
        this.update();
    }
    a(alpha) {
        this.hsla[3] = alpha;
        this.rgba[3] = alpha;
    }
    update() {
        const [h, s, l, a] = this.hsla;
        exports.hsl2rgb(this.rgba, h, s, l);
        this.rgba[3] = a;
    }
    lighter(out, by) {
        gl_matrix_1.vec4.copy(out, this.hsla);
        out[2] = math_1.addClamp(out[2], by);
        return out;
    }
    lighterRGBA(out, by) {
        gl_matrix_1.vec4.copy(out, this.hsla);
        out[2] = math_1.addClamp(out[2], by);
        exports.hsla2rgba(out, out[0], out[1], out[2], out[3]);
        return out;
    }
    shift(by) {
        this.hsla[0] = math_1.addClamp(this.hsla[0], by);
        this.update();
    }
    saturate(by) {
        this.hsla[1] = math_1.addClamp(this.hsla[1], by);
        this.update();
    }
    lighten(by) {
        this.hsla[2] = math_1.addClamp(this.hsla[2], by);
        this.update();
    }
    clone() {
        return new Color(this.hsla);
    }
}
exports.Color = Color;
const mainScript = mathvm_1.MathScript.parse(`
lighter() => {
  s += 0~0.1;
  l += 0.3~0.4
}
darker() => {
  s -= 0~0.1;
  l -= 0.1~0.15
}
`);
class ColorPalette {
    constructor(base) {
        this.seed = null;
        this.colors = [];
        this.lighter = [];
        this.darker = [];
        this.base = base;
    }
    static random(color = null) {
        const seed = math_1.generateSeed();
        const p = new ColorPalette(color !== null ? color : Color.random());
        p.seed = seed;
        return p;
    }
    static fromColorSeed(color, seed, style) {
        const p = new ColorPalette(color);
        p.seed = seed;
        p.randomize(style);
        return p;
    }
    randomize(style) {
        const c = gl_matrix_1.vec4.clone(this.base.hsla);
        c[3] = 1;
        this.colors.length = 0;
        math_1.setSeed(this.seed);
        const environment = new Map();
        const functions = new Map();
        mainScript.run([], {
            h: c[0],
            s: c[1],
            l: c[2],
        }, environment, functions, math_1.lqrandomSeed);
        if (utils_1.objHas(style, 'init')) {
            environment.set('init', mathvm_1.MathScript.parse(style.init).run([], {
                h: c[0],
                s: c[1],
                l: c[2],
            }, environment, functions, math_1.lqrandomSeed));
        }
        for (let i = 0; i < style.rules.length; i++) {
            const ms = mathvm_1.MathScript.parse(style.rules[i]);
            gl_matrix_1.vec4.copy(c, this.base.hsla);
            ms.run([], {
                h: c[0],
                s: c[1],
                l: c[2],
            }, environment, functions, math_1.lqrandomSeed);
            c[0] = environment.get('h');
            c[0] = c[0] % 1;
            if (c[0] < 0) {
                c[0] = c[0] + 1;
            }
            c[1] = Math.max(Math.min(environment.get('s'), 1), 0);
            c[2] = Math.max(Math.min(environment.get('l'), 1), 0);
            this.colors.push(new Color(c));
        }
        this.shade(0.15, 0.15);
    }
    shade(_darker, _lighter) {
        const c = gl_matrix_1.vec4.create();
        this.darker.length = 0;
        this.lighter.length = 0;
        for (let i = 0; i < this.colors.length; i++) {
            gl_matrix_1.vec4.copy(c, this.colors[i].hsla);
            c[2] = c[2] * 0.5;
            this.darker.push(new Color(c));
            gl_matrix_1.vec4.copy(c, this.colors[i].hsla);
            c[2] = c[2] * 0.5 + 0.5;
            this.lighter.push(new Color(c));
        }
    }
}
exports.ColorPalette = ColorPalette;
//# sourceMappingURL=color.js.map