/*
 * SDK Pullenti Unitext, version 4.33, fabruary 2026. Copyright (c) 2013-2026, Pullenti. All rights reserved. 
 * Non-Commercial Freeware and Commercial Software. 
 * This class is generated using the converter UniSharping (www.unisharping.ru) from Pullenti C# project. 
 * The latest version of the code is available on the site www.pullenti.ru
 */

const Utils = require("./../../../unisharp/Utils");
const Stream = require("./../../../unisharp/Stream");
const MemoryStream = require("./../../../unisharp/MemoryStream");

const ArchiveHelper = require("./../../../util/ArchiveHelper");
const PngChunk = require("./PngChunk");
const PngHead = require("./PngHead");

class PngWrapper {
    
    constructor(width, height, isGray, colorMap, createGrayImage = false) {
        this.m_Head = null;
        this.m_GrayImage = null;
        this.m_RowSize = 0;
        this.m_ColorMap = null;
        this.m_Data = null;
        this.m_Row = null;
        this.m_RowPos = 0;
        this.m_Chunks = null;
        this.m_Data = new Array();
        this.m_RowSize = width;
        if (!isGray) {
            if (colorMap === null) 
                this.m_RowSize *= 3;
        }
        this.m_RowSize++;
        this.m_Chunks = new Array();
        this.m_Head = new PngHead();
        this.m_Chunks.push(this.m_Head);
        this.m_Head.width = width;
        this.m_Head.height = height;
        this.m_Head.colorType = (isGray ? 0 : 2);
        if (colorMap !== null) {
            this.m_ColorMap = colorMap;
            if (!isGray) {
                this.m_Head.colorType = 3;
                let mmm = new PngChunk("PLTE");
                mmm.data = colorMap;
                if (!isGray && ((colorMap.length % 3)) !== 0 && colorMap.length >= 6) {
                    let ii = colorMap.length % 3;
                    let dat = new Uint8Array(colorMap.length - ii);
                    for (let j = 0; j < dat.length; j++) {
                        dat[j] = colorMap[j];
                    }
                    mmm.data = dat;
                }
                this.m_Chunks.push(mmm);
            }
        }
        if (createGrayImage) {
            this.m_GrayImage = new Array();
            for (let i = 0; i < height; i++) {
                this.m_GrayImage.push(new Uint8Array(width));
            }
        }
    }
    
    beginRow() {
        this.m_Row = new Uint8Array(this.m_RowSize);
        this.m_RowPos = 1;
    }
    
    endRow() {
        this.m_Data.push(this.m_Row);
    }
    
    addPixelRgb(r, g, b) {
        if ((this.m_RowPos + 2) >= this.m_RowSize) 
            return;
        this.m_Row[this.m_RowPos] = r;
        if (this.m_Head.colorType === (0)) 
            this.m_RowPos += 1;
        else {
            this.m_Row[this.m_RowPos + 1] = g;
            this.m_Row[this.m_RowPos + 2] = b;
            this.m_RowPos += 3;
        }
    }
    
    addPixelGray(gr) {
        if (this.m_RowPos >= this.m_RowSize) 
            return;
        if (this.m_GrayImage !== null && (this.m_Data.length < this.m_GrayImage.length)) {
            if (this.m_RowPos <= this.m_GrayImage[this.m_Data.length].length) 
                this.m_GrayImage[this.m_Data.length][this.m_RowPos - 1] = gr;
        }
        this.m_Row[this.m_RowPos] = gr;
        this.m_RowPos += 1;
    }
    
    getPixelGray(w, h) {
        if (this.m_GrayImage === null || h >= this.m_GrayImage.length) 
            return 0;
        if (w < this.m_GrayImage[h].length) 
            return this.m_GrayImage[h][w];
        return 0;
    }
    
    addPixelIndex(gr) {
        if (this.m_RowPos >= this.m_RowSize) 
            return;
        if (this.m_ColorMap !== null && this.m_Head.colorType === (0)) {
            let i = gr;
            if (i >= 0 && (i < this.m_ColorMap.length)) {
                this.m_Row[this.m_RowPos] = this.m_ColorMap[i];
                this.m_RowPos += 1;
            }
        }
        else {
            this.m_Row[this.m_RowPos] = gr;
            this.m_RowPos += 1;
        }
    }
    
    commit() {
        let dat = new PngChunk("IDAT");
        let body = new MemoryStream(); 
        try {
            for (let r = 0; r < this.m_Data.length; r++) {
                body.write(this.m_Data[r], 0, this.m_RowSize);
            }
            let src0 = body.toByteArray();
            dat.data = ArchiveHelper.compressZlib(src0);
            this.m_Head.height = this.m_Data.length;
        }
        finally {
            body.close();
        }
        this.m_Chunks.push(dat);
        this.m_Chunks.push(new PngChunk("IEND"));
    }
    
    getBytes() {
        if (this.m_Chunks.length < 1) 
            this.commit();
        let res = new MemoryStream(); 
        try {
            res.writeByte(137);
            res.writeByte(80);
            res.writeByte(78);
            res.writeByte(71);
            res.writeByte(13);
            res.writeByte(10);
            res.writeByte(26);
            res.writeByte(10);
            for (const ch of this.m_Chunks) {
                ch.write(res);
            }
            return res.toByteArray();
        }
        finally {
            res.close();
        }
    }
    
    static filterByte(typ, encode, x, a, b, c) {
        if (typ === 1) 
            return (encode ? ((x) - (a)) : ((x) + (a)));
        if (typ === 2) 
            return (encode ? ((x) - (b)) : ((x) + (b)));
        if (typ === 3) {
            let i = a;
            i += (b);
            i = Utils.intDiv(i, 2);
            return (encode ? ((x) - i) : ((x) + i));
        }
        if (typ === 4) {
            let p = a;
            p += (b);
            p -= (c);
            let pa = p - (a);
            if (pa < 0) 
                pa = -pa;
            let pb = p - (b);
            if (pb < 0) 
                pb = -pb;
            let pc = p - (c);
            if (pc < 0) 
                pc = -pc;
            let i = 0;
            if (pa <= pb && pa <= pc) 
                i = a;
            else if (pb <= pc) 
                i = b;
            else 
                i = c;
            return (encode ? ((x) - i) : ((x) + i));
        }
        return x;
    }
}


module.exports = PngWrapper