"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const stream = require("stream");
const Parser = require("./parser");
const Packer = require("./packer");
var EDeflateStrategy;
(function (EDeflateStrategy) {
    EDeflateStrategy[EDeflateStrategy["DEFAULT_STRATEGY"] = 0] = "DEFAULT_STRATEGY";
    EDeflateStrategy[EDeflateStrategy["FILTERED"] = 1] = "FILTERED";
    EDeflateStrategy[EDeflateStrategy["HUFFMAN_ONLY"] = 2] = "HUFFMAN_ONLY";
    EDeflateStrategy[EDeflateStrategy["RLE"] = 3] = "RLE";
    EDeflateStrategy[EDeflateStrategy["FIXED"] = 4] = "FIXED";
})(EDeflateStrategy = exports.EDeflateStrategy || (exports.EDeflateStrategy = {}));
var EFilterType;
(function (EFilterType) {
    EFilterType[EFilterType["Auto"] = -1] = "Auto";
    EFilterType[EFilterType["None"] = 0] = "None";
    EFilterType[EFilterType["Sub"] = 1] = "Sub";
    EFilterType[EFilterType["Up"] = 2] = "Up";
    EFilterType[EFilterType["Average"] = 3] = "Average";
    EFilterType[EFilterType["Paeth"] = 4] = "Paeth";
})(EFilterType = exports.EFilterType || (exports.EFilterType = {}));
function createImage(option) {
    return new Image(option);
}
exports.createImage = createImage;
class Image extends stream.Duplex {
    constructor(option = {}) {
        super();
        this.width = option.width || 0;
        this.height = option.height || 0;
        if (this.width > 0 && this.height > 0) {
            this.data = Buffer.alloc(4 * this.width * this.height);
            if (option.fill) {
                this.data.fill(0);
            }
        }
        else {
            this.data = null;
        }
        this.gamma = 0;
        this.writable = true;
        this._parser = new Parser(option || {});
        this._parser.on("error", this.emit.bind(this, "error"));
        this._parser.on("close", this._handleClose.bind(this));
        this._parser.on("metadata", this._metadata.bind(this));
        this._parser.on("gamma", this._gamma.bind(this));
        this._parser.on("parsed", (data) => {
            this.data = data;
            this.emit("parsed", data);
        });
        this._packer = new Packer(option);
        this._packer.on("data", this.emit.bind(this, "data"));
        this._packer.on("end", this.emit.bind(this, "end"));
        this._packer.on("close", this._handleClose.bind(this));
        this._packer.on("error", this.emit.bind(this, "error"));
    }
    pack() {
        setImmediate(() => {
            this._packer.pack(this.data, this.width, this.height);
            this.readable = true;
        });
        return this;
    }
    parse(data, callback) {
        if (callback) {
            let onParsed = null, onError = null;
            this.once("parsed", onParsed = (data) => {
                this.removeListener("error", onError);
                this.data = data;
                callback(null, this);
            });
            this.once("error", onError = (err) => {
                this.removeListener("parsed", onParsed);
                callback(err, null);
            });
        }
        this.end(data);
        return this;
    }
    _write(data, encoding, callback) {
        return this._parser._write(data, encoding, callback);
    }
    end(data) {
        return this._parser.end(data);
    }
    bitblt(dst, sx, sy, w, h, dx, dy) {
        if (sx > this.width || sy > this.height || sx + w > this.width || sy + h > this.height) {
            throw new Error("bitblt reading outside image");
        }
        if (dx > dst.width || dy > dst.height || dx + w > dst.width || dy + h > dst.height) {
            throw new Error("bitblt writing outside image");
        }
        for (let y = 0; y < h; y++) {
            this.data.copy(dst.data, ((dy + y) * dst.width + dx) << 2, ((sy + y) * this.width + sx) << 2, ((sy + y) * this.width + sx + w) << 2);
        }
        return this;
    }
    _read() {
    }
    _metadata(metadata) {
        this.width = metadata.width;
        this.height = metadata.height;
        this.data = metadata.data;
        delete metadata.data;
        this.emit("metadata", metadata);
    }
    _gamma(gamma) {
        this.gamma = gamma;
    }
    _handleClose() {
        if (!this._parser.writable && !this._packer.readable) {
            this.emit("close");
        }
    }
}
exports.Image = Image;
//# sourceMappingURL=index.js.map