/*-
 * Copyright (C) 2021 Erik Larsson
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.catacombae.bplist.types;

import java.io.PrintStream;
import java.math.BigInteger;
import org.catacombae.util.Util;

/** This class was generated by CStructToJavaClass. */
public class BinaryPlistFooter {
    /*
     * struct BinaryPlistFooter
     * size: 32 bytes
     * description:
     *
     * BP  Size   Type   Identifier             Description
     * ----------------------------------------------------
     * 0   1 * 5  u8[5]  reserved
     * 5   1      u8     sortVersion
     * 6   1      u8     offsetTableOffsetSize
     * 7   1      u8     objectRefSize
     * 8   8      be64   numObjects
     * 16  8      be64   topObjectOffset
     * 24  8      be64   offsetTableStart
     */

    public static final int STRUCTSIZE = 32;

    private final byte[] reserved = new byte[1 * 5];
    private byte sortVersion;
    private byte offsetTableOffsetSize;
    private byte objectRefSize;
    private long numObjects;
    private long topObjectOffset;
    private long offsetTableStart;

    public BinaryPlistFooter(byte[] data, int offset) {
        System.arraycopy(data, offset + 0, this.reserved, 0, 1 * 5);
        this.sortVersion = Util.readByteBE(data, offset + 5);
        this.offsetTableOffsetSize = Util.readByteBE(data, offset + 6);
        this.objectRefSize = Util.readByteBE(data, offset + 7);
        this.numObjects = Util.readLongBE(data, offset + 8);
        this.topObjectOffset = Util.readLongBE(data, offset + 16);
        this.offsetTableStart = Util.readLongBE(data, offset + 24);
    }

    public static int length() { return STRUCTSIZE; }

    /**  */
    public final short[] getReserved() {
        return Util.unsign(getRawReserved());
    }

    /**  */
    public final short getSortVersion() {
        return Util.unsign(getRawSortVersion());
    }

    /**  */
    public final short getOffsetTableOffsetSize() {
        return Util.unsign(getRawOffsetTableOffsetSize());
    }

    /**  */
    public final short getObjectRefSize() {
        return Util.unsign(getRawObjectRefSize());
    }

    /**  */
    public final BigInteger getNumObjects() {
        return Util.unsign(getRawNumObjects());
    }

    /**  */
    public final BigInteger getTopObjectOffset() {
        return Util.unsign(getRawTopObjectOffset());
    }

    /**  */
    public final BigInteger getOffsetTableStart() {
        return Util.unsign(getRawOffsetTableStart());
    }

    /**
     * <b>Note that the return value from this function should be interpreted as
     * an unsigned integer, for instance using Util.unsign(...).</b>
     */
    public final byte[] getRawReserved() {
        return Util.readByteArrayBE(this.reserved);
    }

    /**
     * <b>Note that the return value from this function should be interpreted as
     * an unsigned integer, for instance using Util.unsign(...).</b>
     */
    public final byte getRawSortVersion() {
        return this.sortVersion;
    }

    /**
     * <b>Note that the return value from this function should be interpreted as
     * an unsigned integer, for instance using Util.unsign(...).</b>
     */
    public final byte getRawOffsetTableOffsetSize() {
        return this.offsetTableOffsetSize;
    }

    /**
     * <b>Note that the return value from this function should be interpreted as
     * an unsigned integer, for instance using Util.unsign(...).</b>
     */
    public final byte getRawObjectRefSize() {
        return this.objectRefSize;
    }

    /**
     * <b>Note that the return value from this function should be interpreted as
     * an unsigned integer, for instance using Util.unsign(...).</b>
     */
    public final long getRawNumObjects() {
        return this.numObjects;
    }

    /**
     * <b>Note that the return value from this function should be interpreted as
     * an unsigned integer, for instance using Util.unsign(...).</b>
     */
    public final long getRawTopObjectOffset() {
        return this.topObjectOffset;
    }

    /**
     * <b>Note that the return value from this function should be interpreted as
     * an unsigned integer, for instance using Util.unsign(...).</b>
     */
    public final long getRawOffsetTableStart() {
        return this.offsetTableStart;
    }

    public void printFields(PrintStream ps, String prefix) {
        ps.println(prefix + " reserved: ");
        {
            short[] _array = getReserved();
            for(int _i = 0; _i < 5; ++_i) {
                ps.println(prefix + "  [" + _i + "]:");
                ps.println(prefix + "    " + _array[_i]);
            }
        }
        ps.println(prefix + " sortVersion: " + getSortVersion());
        ps.println(prefix + " offsetTableOffsetSize: " + getOffsetTableOffsetSize());
        ps.println(prefix + " objectRefSize: " + getObjectRefSize());
        ps.println(prefix + " numObjects: " + getNumObjects());
        ps.println(prefix + " topObjectOffset: " + getTopObjectOffset());
        ps.println(prefix + " offsetTableStart: " + getOffsetTableStart());
    }

    public void print(PrintStream ps, String prefix) {
        ps.println(prefix + "BinaryPlistFooter:");
        printFields(ps, prefix);
    }

    public byte[] getBytes() {
        byte[] result = new byte[length()];
        getBytes(result, 0);
        return result;
    }

    public int getBytes(byte[] result, int offset) {
        final int startOffset = offset;

        System.arraycopy(this.reserved, 0, result, offset, this.reserved.length); offset += this.reserved.length;
        Util.arrayPutBE(result, offset, this.sortVersion); offset += 1;
        Util.arrayPutBE(result, offset, this.offsetTableOffsetSize); offset += 1;
        Util.arrayPutBE(result, offset, this.objectRefSize); offset += 1;
        Util.arrayPutBE(result, offset, this.numObjects); offset += 8;
        Util.arrayPutBE(result, offset, this.topObjectOffset); offset += 8;
        Util.arrayPutBE(result, offset, this.offsetTableStart); offset += 8;

        return offset - startOffset;
    }
}
