import { VisualProperties, VisualUniforms } from "./visual";
import { get_pattern } from "./patterns";
import * as p from "../properties";
import * as mixins from "../property_mixins";
import { dict } from "../util/object";
export class Hatch extends VisualProperties {
    static __name__ = "Hatch";
    _hatch_image;
    _update_iteration = 0;
    update() {
        this._update_iteration++;
        this._hatch_image = null;
        if (!this.doit) {
            return;
        }
        const color = this.get_hatch_color();
        const alpha = this.get_hatch_alpha();
        const scale = this.get_hatch_scale();
        const pattern = this.get_hatch_pattern();
        const weight = this.get_hatch_weight();
        const finalize = (image) => {
            this._hatch_image = image;
        };
        const textures = dict(this.get_hatch_extra());
        const texture = textures.get(pattern);
        if (texture != null) {
            const image = texture.get_pattern(color, alpha, scale, weight);
            if (image instanceof Promise) {
                const { _update_iteration } = this;
                void image.then((image) => {
                    if (this._update_iteration == _update_iteration) {
                        finalize(image);
                        this.obj.request_paint();
                    }
                });
            }
            else {
                finalize(image);
            }
        }
        else {
            const layer = this.obj.canvas.create_layer();
            const image = get_pattern(layer, pattern, color, alpha, scale, weight);
            finalize(image);
        }
    }
    get doit() {
        const color = this.get_hatch_color();
        const alpha = this.get_hatch_alpha();
        const pattern = this.get_hatch_pattern();
        return !(color == null || alpha == 0 || pattern == " " || pattern == "blank" || pattern == null);
    }
    apply(ctx, rule) {
        const { doit } = this;
        if (doit) {
            this.set_value(ctx);
            ctx.layer.undo_transform(() => ctx.fill(rule));
        }
        return doit;
    }
    set_value(ctx) {
        const pattern = this.pattern(ctx);
        ctx.fillStyle = pattern ?? "transparent";
    }
    pattern(ctx) {
        const image = this._hatch_image;
        if (image == null) {
            return null;
        }
        else {
            return ctx.createPattern(image, this.repetition());
        }
    }
    repetition() {
        const pattern = this.get_hatch_pattern();
        const textures = dict(this.get_hatch_extra());
        const texture = textures.get(pattern);
        if (texture == null) {
            return "repeat";
        }
        else {
            switch (texture.repetition) {
                case "repeat": return "repeat";
                case "repeat_x": return "repeat-x";
                case "repeat_y": return "repeat-y";
                case "no_repeat": return "no-repeat";
            }
        }
    }
    get_hatch_color() {
        const css_color = this._get_css_value("hatch-color");
        if (css_color != "") {
            return css_color;
        }
        return this.hatch_color.get_value();
    }
    get_hatch_alpha() {
        const css_alpha = this._get_css_value("hatch-alpha");
        if (css_alpha != "") {
            const alpha = Number(css_alpha);
            if (isFinite(alpha)) {
                return alpha;
            }
        }
        return this.hatch_alpha.get_value();
    }
    get_hatch_scale() {
        const css_scale = this._get_css_value("hatch-scale");
        if (css_scale != "") {
            const scale = Number(css_scale);
            if (isFinite(scale)) {
                return scale;
            }
        }
        return this.hatch_scale.get_value();
    }
    get_hatch_pattern() {
        const css_pattern = this._get_css_value("hatch-pattern");
        if (css_pattern != "") {
            if (css_pattern == "none") {
                return null;
            }
            else {
                return css_pattern;
            }
        }
        return this.hatch_pattern.get_value();
    }
    get_hatch_weight() {
        const css_weight = this._get_css_value("hatch-weight");
        if (css_weight != "") {
            const weight = Number(css_weight);
            if (isFinite(weight)) {
                return weight;
            }
        }
        return this.hatch_weight.get_value();
    }
    get_hatch_extra() {
        return this.hatch_extra.get_value();
    }
}
export class HatchScalar extends VisualUniforms {
    static __name__ = "HatchScalar";
    _hatch_image;
    _static_doit = false;
    _compute_static_doit() {
        const color = this.hatch_color.value;
        const alpha = this.hatch_alpha.value;
        const pattern = this.hatch_pattern.value;
        return !(color == 0 || alpha == 0 || pattern == " " || pattern == "blank" || pattern == null);
    }
    _update_iteration = 0;
    update() {
        this._update_iteration++;
        const n = this.hatch_color.length;
        this._hatch_image = new p.UniformScalar(null, n);
        this._static_doit = this._compute_static_doit();
        if (!this._static_doit) {
            return;
        }
        const color = this.hatch_color.value;
        const alpha = this.hatch_alpha.value;
        const scale = this.hatch_scale.value;
        const pattern = this.hatch_pattern.value;
        const weight = this.hatch_weight.value;
        const finalize = (image) => {
            this._hatch_image = new p.UniformScalar(image, n);
        };
        const textures = dict(this.hatch_extra.value);
        const texture = textures.get(pattern);
        if (texture != null) {
            const image = texture.get_pattern(color, alpha, scale, weight);
            if (image instanceof Promise) {
                const { _update_iteration } = this;
                void image.then((image) => {
                    if (this._update_iteration == _update_iteration) {
                        finalize(image);
                        this.obj.request_paint();
                    }
                });
            }
            else {
                finalize(image);
            }
        }
        else {
            const layer = this.obj.canvas.create_layer();
            const image = get_pattern(layer, pattern, color, alpha, scale, weight);
            finalize(image);
        }
    }
    get doit() {
        return this._static_doit;
    }
    apply(ctx, rule) {
        const { doit } = this;
        if (doit) {
            this.set_value(ctx);
            ctx.layer.undo_transform(() => ctx.fill(rule));
        }
        return doit;
    }
    set_value(ctx) {
        ctx.fillStyle = this.pattern(ctx) ?? "transparent";
    }
    pattern(ctx) {
        const image = this._hatch_image.value;
        if (image == null) {
            return null;
        }
        else {
            return ctx.createPattern(image, this.repetition());
        }
    }
    repetition() {
        const pattern = this.hatch_pattern.value;
        if (pattern != null) {
            const textures = dict(this.hatch_extra.value);
            const texture = textures.get(pattern);
            if (texture != null) {
                switch (texture.repetition) {
                    case "repeat": return "repeat";
                    case "repeat_x": return "repeat-x";
                    case "repeat_y": return "repeat-y";
                    case "no_repeat": return "no-repeat";
                }
            }
        }
        return "repeat";
    }
}
export class HatchVector extends VisualUniforms {
    static __name__ = "HatchVector";
    _hatch_image;
    _static_doit = false;
    _compute_static_doit() {
        const { hatch_color } = this;
        if (hatch_color.is_Scalar() && hatch_color.value == 0) {
            return false;
        }
        const { hatch_alpha } = this;
        if (hatch_alpha.is_Scalar() && hatch_alpha.value == 0) {
            return false;
        }
        const { hatch_pattern } = this;
        if (hatch_pattern.is_Scalar()) {
            const pattern = hatch_pattern.value;
            if (pattern == " " || pattern == "blank" || pattern == null) {
                return false;
            }
        }
        return true;
    }
    _update_iteration = 0;
    update() {
        this._update_iteration++;
        const n = this.hatch_color.length;
        this._hatch_image = new p.UniformScalar(null, n);
        this._static_doit = this._compute_static_doit();
        if (!this._static_doit) {
            return;
        }
        const resolve_image = (pattern, color, alpha, scale, weight, finalize) => {
            const textures = dict(this.hatch_extra.value);
            const texture = textures.get(pattern);
            if (texture != null) {
                const image = texture.get_pattern(color, alpha, scale, weight);
                if (image instanceof Promise) {
                    const { _update_iteration } = this;
                    void image.then((image) => {
                        if (this._update_iteration == _update_iteration) {
                            finalize(image);
                            this.obj.request_paint();
                        }
                    });
                }
                else {
                    finalize(image);
                }
            }
            else {
                const layer = this.obj.canvas.create_layer();
                const image = get_pattern(layer, pattern, color, alpha, scale, weight);
                finalize(image);
            }
        };
        if (this.hatch_color.is_Scalar() &&
            this.hatch_alpha.is_Scalar() &&
            this.hatch_scale.is_Scalar() &&
            this.hatch_pattern.is_Scalar() &&
            this.hatch_weight.is_Scalar()) {
            const color = this.hatch_color.value;
            const alpha = this.hatch_alpha.value;
            const scale = this.hatch_scale.value;
            const pattern = this.hatch_pattern.value;
            const weight = this.hatch_weight.value;
            resolve_image(pattern, color, alpha, scale, weight, (image) => {
                this._hatch_image = new p.UniformScalar(image, n);
            });
        }
        else {
            const images = new Array(n);
            images.fill(null);
            this._hatch_image = new p.UniformVector(images);
            for (let i = 0; i < n; i++) {
                const color = this.hatch_color.get(i);
                const alpha = this.hatch_alpha.get(i);
                const scale = this.hatch_scale.get(i);
                const pattern = this.hatch_pattern.get(i);
                const weight = this.hatch_weight.get(i);
                resolve_image(pattern, color, alpha, scale, weight, (image) => {
                    images[i] = image;
                });
            }
        }
    }
    get doit() {
        return this._static_doit;
    }
    v_doit(i) {
        if (!this.doit) {
            return false;
        }
        if (this.hatch_color.get(i) == 0) {
            return false;
        }
        if (this.hatch_alpha.get(i) == 0) {
            return false;
        }
        const pattern = this.hatch_pattern.get(i);
        if (pattern == " " || pattern == "blank" || pattern == null) {
            return false;
        }
        return true;
    }
    apply(ctx, i, rule) {
        const doit = this.v_doit(i);
        if (doit) {
            this.set_vectorize(ctx, i);
            ctx.layer.undo_transform(() => ctx.fill(rule));
        }
        return doit;
    }
    set_vectorize(ctx, i) {
        ctx.fillStyle = this.pattern(ctx, i) ?? "transparent";
    }
    pattern(ctx, i) {
        const image = this._hatch_image.get(i);
        if (image == null) {
            return null;
        }
        else {
            return ctx.createPattern(image, this.repetition(i));
        }
    }
    repetition(i) {
        const pattern = this.hatch_pattern.get(i);
        if (pattern != null) {
            const textures = dict(this.hatch_extra.value);
            const texture = textures.get(pattern);
            if (texture != null) {
                switch (texture.repetition) {
                    case "repeat": return "repeat";
                    case "repeat_x": return "repeat-x";
                    case "repeat_y": return "repeat-y";
                    case "no_repeat": return "no-repeat";
                }
            }
        }
        return "repeat";
    }
}
Hatch.prototype.type = "hatch";
Hatch.prototype.attrs = Object.keys(mixins.Hatch);
HatchScalar.prototype.type = "hatch";
HatchScalar.prototype.attrs = Object.keys(mixins.HatchScalar);
HatchVector.prototype.type = "hatch";
HatchVector.prototype.attrs = Object.keys(mixins.HatchVector);
//# sourceMappingURL=hatch.js.map