/*
 * 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.word;

// Base stream for retrival data from a Compound File.
public abstract class CompoundFileStream extends com.pullenti.unisharp.Stream {

    private CompoundFileStorage m_Storage;

    public CompoundFileStorage getStorage() {
        return m_Storage;
    }


    public CompoundFileSystem getSystem() {
        return getStorage().getSystem();
    }


    private int m_Position;

    private int m_Length;

    private int m_PageSize;

    public int getPageSize() {
        return m_PageSize;
    }


    private byte[] m_Page = null;

    private int m_PageIndex = -1;

    public CompoundFileStream(CompoundFileStorage _storage, int _pageSize) {
        super();
        this.m_Storage = _storage;
        this.m_Position = 0;
        this.m_Length = _storage.getLength();
        this.m_PageSize = _pageSize;
    }

    @Override
    public boolean canRead() {
        return true;
    }


    @Override
    public boolean canSeek() {
        return true;
    }


    @Override
    public boolean canWrite() {
        return false;
    }


    @Override
    public void flush() {
    }

    @Override
    public long length() {
        return (long)m_Length;
    }


    @Override
    public long getPosition() {
        return (long)m_Position;
    }

    @Override
    public long setPosition(long value) {
        this.seek(value, 0);
        return value;
    }


    @Override
    public int read(byte[] buffer, int offset, int count) {
        if (count <= 0) 
            return count;
        if (m_Position >= m_Length) 
            return 0;
        int _canRead = (count > ((m_Length - m_Position)) ? (m_Length - m_Position) : count);
        try {
            int pageStartPosition = m_PageSize * m_PageIndex;
            int pageEndPosition = pageStartPosition;
            if (m_Page != null) 
                pageEndPosition += m_Page.length;
            if ((m_Position < pageStartPosition) || (m_Position + _canRead) > pageEndPosition) {
                byte[] cachedPage = this.m_Page;
                int cachedPageIndex = this.m_PageIndex;
                int startPageIndex = (m_Position / m_PageSize);
                int lastPageIndex = ((((m_Position + _canRead) - 1)) / m_PageSize);
                if (startPageIndex != cachedPageIndex) {
                    this.m_Page = this.getPageData(startPageIndex);
                    this.m_PageIndex = startPageIndex;
                }
                int startPageOffset = (m_Position - (startPageIndex * m_PageSize));
                int startPageTail = m_Page.length - startPageOffset;
                if (startPageTail >= _canRead) {
                    for(int iii = 0; iii < (_canRead); iii++) buffer[(offset) + iii] = m_Page[(startPageOffset) + iii];
                    m_Position += _canRead;
                }
                else {
                    for(int iii = 0; iii < (startPageTail); iii++) buffer[(offset) + iii] = m_Page[(startPageOffset) + iii];
                    offset += startPageTail;
                    m_Position += startPageTail;
                    int leftToRead = _canRead - startPageTail;
                    for (int i = startPageIndex + 1; i < lastPageIndex; i++) {
                        if (cachedPageIndex == i) {
                            this.m_Page = cachedPage;
                            this.m_PageIndex = cachedPageIndex;
                        }
                        else {
                            this.m_Page = this.getPageData(i);
                            this.m_PageIndex = i;
                        }
                        for(int iii = 0; iii < (m_Page.length); iii++) buffer[(offset) + iii] = m_Page[(0) + iii];
                        offset += m_Page.length;
                        m_Position += m_Page.length;
                        leftToRead -= m_Page.length;
                    }
                    if (cachedPageIndex == lastPageIndex) {
                        this.m_Page = cachedPage;
                        this.m_PageIndex = cachedPageIndex;
                    }
                    else {
                        this.m_Page = this.getPageData(lastPageIndex);
                        this.m_PageIndex = lastPageIndex;
                    }
                    for(int iii = 0; iii < (leftToRead); iii++) buffer[(offset) + iii] = m_Page[(0) + iii];
                    m_Position += leftToRead;
                }
            }
            else {
                for(int iii = 0; iii < (_canRead); iii++) buffer[(offset) + iii] = m_Page[((m_Position - pageStartPosition)) + iii];
                m_Position += _canRead;
            }
        } catch (Exception ex) {
            return -1;
        }
        return _canRead;
    }

    protected abstract byte[] getPageData(int pageIndex);

    @Override
    public long seek(long offset, int origin) {
        switch (origin) { 
        case 0:
            m_Position = (int)offset;
            break;
        case 1:
            m_Position += ((int)offset);
            break;
        case 2:
            m_Position = (int)((this.length() + offset));
            break;
    }
    return (long)m_Position;
    }

    @Override
    public void setLength(long value) {
    }

    @Override
    public void write(byte[] buffer, int offset, int count) {
    }

    @Override
    protected void dispose(boolean disposing) {
        super.dispose(disposing);
        if (disposing) {
            m_Storage = null;
            m_Page = null;
        }
    }
    public CompoundFileStream() {
        super();
    }
}
