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

package com.pullenti.unitext.internal.zip;

// 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/>
public class OutputWindow {

    private static final int windowSize;

    private static final int windowMask;

    private byte[] window = new byte[windowSize];

    private int windowEnd;

    private int windowFilled;

    public void write(int value) throws UnsupportedOperationException {
        windowFilled++;
        if ((windowFilled - 1) == windowSize) 
            throw new UnsupportedOperationException("Window full");
        window[windowEnd++] = (byte)value;
        windowEnd &= windowMask;
    }

    private void slowRepeat(int repStart, int length, int distance) {
        while ((length--) > 0) {
            window[windowEnd++] = window[repStart++];
            windowEnd &= windowMask;
            repStart &= windowMask;
        }
    }

    public void repeat(int length, int distance) throws UnsupportedOperationException {
        if (((windowFilled += length)) > windowSize) 
            throw new UnsupportedOperationException("Window full");
        int repStart = ((windowEnd - distance)) & windowMask;
        int border = windowSize - length;
        if ((repStart <= border) && ((windowEnd < border))) {
            if (length <= distance) {
                for(int iii = 0; iii < (length); iii++) window[(windowEnd) + iii] = window[(repStart) + iii];
                windowEnd += length;
            }
            else 
                while ((length--) > 0) {
                    window[windowEnd++] = window[repStart++];
                }
        }
        else 
            this.slowRepeat(repStart, length, distance);
    }

    public int copyStored(StreamManipulator input, int length) throws IndexOutOfBoundsException, UnsupportedOperationException {
        length = Math.min(Math.min(length, windowSize - windowFilled), input.getAvailableBytes());
        int copied;
        int tailLen = windowSize - windowEnd;
        if (length > tailLen) {
            copied = input.copyBytes(window, windowEnd, tailLen);
            if (copied == tailLen) 
                copied += input.copyBytes(window, 0, length - tailLen);
        }
        else 
            copied = input.copyBytes(window, windowEnd, length);
        windowEnd = ((windowEnd + copied)) & windowMask;
        windowFilled += copied;
        return copied;
    }

    public void copyDict(byte[] dictionary, int offset, int length) throws IllegalArgumentException, UnsupportedOperationException {
        if (dictionary == null) 
            throw new IllegalArgumentException("dictionary");
        if (windowFilled > 0) 
            throw new UnsupportedOperationException();
        if (length > windowSize) {
            offset += (length - windowSize);
            length = windowSize;
        }
        for(int iii = 0; iii < (length); iii++) window[(0) + iii] = dictionary[(offset) + iii];
        windowEnd = length & windowMask;
    }

    public int getFreeSpace() {
        return windowSize - windowFilled;
    }

    public int getAvailable() {
        return windowFilled;
    }

    public int copyOutput(byte[] output, int offset, int len) throws UnsupportedOperationException {
        int copyEnd = windowEnd;
        if (len > windowFilled) 
            len = windowFilled;
        else 
            copyEnd = (((windowEnd - windowFilled) + len)) & windowMask;
        int copied = len;
        int tailLen = len - copyEnd;
        if (tailLen > 0) {
            for(int iii = 0; iii < (tailLen); iii++) output[(offset) + iii] = window[(windowSize - tailLen) + iii];
            offset += tailLen;
            len = copyEnd;
        }
        for(int iii = 0; iii < (len); iii++) output[(offset) + iii] = window[(copyEnd - len) + iii];
        windowFilled -= copied;
        if (windowFilled < 0) 
            throw new UnsupportedOperationException();
        return copied;
    }

    public void reset() {
        windowFilled = (windowEnd = 0);
    }

    public OutputWindow() {
    }
    
    static {
        windowSize = 1 << 15;
        windowMask = windowSize - 1;
    }
}
