/*
 * 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
 */


// Contains the output from the Inflation process.
// We need to have a window so that we can refer backwards into the output stream
// to repeat stuff.<br/>
class OutputWindow {
    
    constructor() {
        this.window = new Uint8Array(OutputWindow.windowSize);
        this.windowEnd = 0;
        this.windowFilled = 0;
    }
    
    write(value) {
        this.windowFilled++;
        if ((this.windowFilled - 1) === OutputWindow.windowSize) 
            throw new Error("Window full");
        this.window[this.windowEnd++] = value;
        this.windowEnd &= OutputWindow.windowMask;
    }
    
    slowRepeat(repStart, length, distance) {
        while ((length--) > 0) {
            this.window[this.windowEnd++] = this.window[repStart++];
            this.windowEnd &= OutputWindow.windowMask;
            repStart &= OutputWindow.windowMask;
        }
    }
    
    repeat(length, distance) {
        if (((this.windowFilled += length)) > OutputWindow.windowSize) 
            throw new Error("Window full");
        let repStart = ((this.windowEnd - distance)) & OutputWindow.windowMask;
        let border = OutputWindow.windowSize - length;
        if ((repStart <= border) && ((this.windowEnd < border))) {
            if (length <= distance) {
                for(let iii = 0; iii < (length); iii++) this.window[(this.windowEnd) + iii] = this.window[(repStart) + iii];
                this.windowEnd += length;
            }
            else 
                while ((length--) > 0) {
                    this.window[this.windowEnd++] = this.window[repStart++];
                }
        }
        else 
            this.slowRepeat(repStart, length, distance);
    }
    
    copyStored(input, length) {
        length = Math.min(Math.min(length, OutputWindow.windowSize - this.windowFilled), input.availableBytes);
        let copied = 0;
        let tailLen = OutputWindow.windowSize - this.windowEnd;
        if (length > tailLen) {
            copied = input.copyBytes(this.window, this.windowEnd, tailLen);
            if (copied === tailLen) 
                copied += input.copyBytes(this.window, 0, length - tailLen);
        }
        else 
            copied = input.copyBytes(this.window, this.windowEnd, length);
        this.windowEnd = ((this.windowEnd + copied)) & OutputWindow.windowMask;
        this.windowFilled += copied;
        return copied;
    }
    
    copyDict(dictionary, offset, length) {
        if (dictionary === null) 
            throw new Error("dictionary");
        if (this.windowFilled > 0) 
            throw new Error();
        if (length > OutputWindow.windowSize) {
            offset += (length - OutputWindow.windowSize);
            length = OutputWindow.windowSize;
        }
        for(let iii = 0; iii < (length); iii++) this.window[(0) + iii] = dictionary[(offset) + iii];
        this.windowEnd = length & OutputWindow.windowMask;
    }
    
    getFreeSpace() {
        return OutputWindow.windowSize - this.windowFilled;
    }
    
    getAvailable() {
        return this.windowFilled;
    }
    
    copyOutput(output, offset, len) {
        let copyEnd = this.windowEnd;
        if (len > this.windowFilled) 
            len = this.windowFilled;
        else 
            copyEnd = (((this.windowEnd - this.windowFilled) + len)) & OutputWindow.windowMask;
        let copied = len;
        let tailLen = len - copyEnd;
        if (tailLen > 0) {
            for(let iii = 0; iii < (tailLen); iii++) output[(offset) + iii] = this.window[(OutputWindow.windowSize - tailLen) + iii];
            offset += tailLen;
            len = copyEnd;
        }
        for(let iii = 0; iii < (len); iii++) output[(offset) + iii] = this.window[(copyEnd - len) + iii];
        this.windowFilled -= copied;
        if (this.windowFilled < 0) 
            throw new Error();
        return copied;
    }
    
    reset() {
        this.windowFilled = (this.windowEnd = 0);
    }
    
    static static_constructor() {
        OutputWindow.windowSize = 1 << 15;
        OutputWindow.windowMask = OutputWindow.windowSize - 1;
    }
}


OutputWindow.static_constructor();

module.exports = OutputWindow