/*-
 * Copyright (C) 2013 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.hfs.types.hfs;

import java.io.PrintStream;
import java.lang.reflect.Field;
import java.math.BigInteger;
import org.catacombae.csjc.PrintableStruct;
import org.catacombae.csjc.StaticStruct;
import org.catacombae.csjc.StructElements;
import org.catacombae.csjc.structelements.Dictionary;
import org.catacombae.csjc.structelements.IntegerFieldRepresentation;
import org.catacombae.util.Util;

/**
 * This class was generated by CStructToJavaClass.
 *
 * @author <a href="https://catacombae.org" target="_top">Erik Larsson</a>
 */
public class HFSVolumeFinderInfo
        implements StaticStruct, PrintableStruct, StructElements
{
    /*
     * struct HFSVolumeFinderInfo
     * size: 32 bytes
     * description:
     *
     * BP  Size  Type  Identifier                          Description
     * ---------------------------------------------------------------
     * 0   4     be32  blessedSystemFolder
     * 4   4     be32  startupApplicationParentFolder
     * 8   4     be32  openFolderList
     * 12  4     be32  alternateMacOSBlessedSystemFolder
     * 16  4     be32  reserved
     * 20  4     be32  alternateMacOSXBlessedSystemFolder
     * 24  8     be64  volumeUUID
     */

    public static final int STRUCTSIZE = 32;

    private int blessedSystemFolder;
    private int startupApplicationParentFolder;
    private int openFolderList;
    private int alternateMacOSBlessedSystemFolder;
    private int reserved;
    private int alternateMacOSXBlessedSystemFolder;
    private long volumeUUID;

    public HFSVolumeFinderInfo(byte[] data, int offset) {
        this.blessedSystemFolder = Util.readIntBE(data, offset+0);
        this.startupApplicationParentFolder = Util.readIntBE(data, offset+4);
        this.openFolderList = Util.readIntBE(data, offset+8);
        this.alternateMacOSBlessedSystemFolder = Util.readIntBE(data,
                offset+12);
        this.reserved = Util.readIntBE(data, offset+16);
        this.alternateMacOSXBlessedSystemFolder = Util.readIntBE(data,
                offset+20);
        this.volumeUUID = Util.readLongBE(data, offset+24);
    }

    public static int length() { return STRUCTSIZE; }

    public int size() { return length(); }

    public final long getBlessedSystemFolder() {
        return Util.unsign(getRawBlessedSystemFolder());
    }

    public final long getStartupApplicationParentFolder() {
        return Util.unsign(getRawStartupApplicationParentFolder());
    }

    public final long getOpenFolderList() {
        return Util.unsign(getRawOpenFolderList());
    }

    public final long getAlternateMacOSBlessedSystemFolder() {
        return Util.unsign(getRawAlternateMacOSBlessedSystemFolder());
    }

    public final long getReserved() {
        return Util.unsign(getRawReserved());
    }

    public final long getAlternateMacOSXBlessedSystemFolder() {
        return Util.unsign(getRawAlternateMacOSXBlessedSystemFolder());
    }

    public final BigInteger getVolumeUUID() {
        return Util.unsign(getRawVolumeUUID());
    }

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

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

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

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

    /**
     * <b>Note that the return value from this function should be interpreted as
     * an unsigned integer, for instance using Util.unsign(...).</b>
     */
    public final int getRawReserved() {
        return 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 int getRawAlternateMacOSXBlessedSystemFolder() {
        return this.alternateMacOSXBlessedSystemFolder;
    }

    /**
     * <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 getRawVolumeUUID() {
        return this.volumeUUID;
    }

    public void printFields(PrintStream ps, String prefix) {
        ps.println(prefix + " blessedSystemFolder: " + getBlessedSystemFolder());
        ps.println(prefix + " startupApplicationParentFolder: " +
                getStartupApplicationParentFolder());
        ps.println(prefix + " openFolderList: " + getOpenFolderList());
        ps.println(prefix + " alternateMacOSBlessedSystemFolder: " +
                getAlternateMacOSBlessedSystemFolder());
        ps.println(prefix + " reserved: " + getReserved());
        ps.println(prefix + " alternateMacOSXBlessedSystemFolder: " +
                getAlternateMacOSXBlessedSystemFolder());
        ps.println(prefix + " volumeUUID: " + getVolumeUUID());
    }

    public void print(PrintStream ps, String prefix) {
        ps.println(prefix + "HFSVolumeFinderInfo:");
        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;

        Util.arrayPutBE(result, offset, this.blessedSystemFolder);
        offset += 4;

        Util.arrayPutBE(result, offset, this.startupApplicationParentFolder);
        offset += 4;

        Util.arrayPutBE(result, offset, this.openFolderList);
        offset += 4;

        Util.arrayPutBE(result, offset, this.alternateMacOSBlessedSystemFolder);
        offset += 4;

        Util.arrayPutBE(result, offset, this.reserved);
        offset += 4;

        Util.arrayPutBE(result, offset,
                this.alternateMacOSXBlessedSystemFolder);
        offset += 4;

        Util.arrayPutBE(result, offset, this.volumeUUID);
        offset += 8;

        return offset - startOffset;
    }

    private Field getPrivateField(String name) throws NoSuchFieldException {
        Field f = getClass().getDeclaredField(name);
        f.setAccessible(true);
        return f;
    }

    public Dictionary getStructElements() {
        DictionaryBuilder db =
                new DictionaryBuilder(MasterDirectoryBlock.class.
                getSimpleName());

        try {
            db.addUIntBE("blessedSystemFolder",
                    getPrivateField("blessedSystemFolder"),
                    this,
                    "System folder ID",
                    IntegerFieldRepresentation.DECIMAL);

            db.addUIntBE("startupApplicationParentFolder",
                    getPrivateField("startupApplicationParentFolder"),
                    this,
                    "Startup application's parent folder ID",
                    IntegerFieldRepresentation.DECIMAL);

            db.addUIntBE("openFolderList",
                    getPrivateField("openFolderList"),
                    this,
                    "Folder ID of first folder in open folder list",
                    IntegerFieldRepresentation.DECIMAL);

            db.addUIntBE("alternateMacOSBlessedSystemFolder",
                    getPrivateField("alternateMacOSBlessedSystemFolder"),
                    this,
                    "Alternate Mac OS Classic system folder ID",
                    IntegerFieldRepresentation.DECIMAL);

            db.addUIntBE("reserved",
                    getPrivateField("reserved"),
                    this,
                    "Reserved",
                    IntegerFieldRepresentation.HEXADECIMAL);

            db.addUIntBE("alternateMacOSXBlessedSystemFolder",
                    getPrivateField("alternateMacOSXBlessedSystemFolder"),
                    this,
                    "Alternate Mac OS X system folder ID",
                    IntegerFieldRepresentation.DECIMAL);

            db.addUIntBE("volumeUUID",
                    getPrivateField("volumeUUID"),
                    this,
                    "Volume UUID",
                    IntegerFieldRepresentation.HEXADECIMAL);
        } catch(NoSuchFieldException e) {
            throw new RuntimeException(e);
        }

        return db.getResult();
    }

    public static class Mutable extends HFSVolumeFinderInfo {

        public Mutable(byte[] data, int offset) {
            super(data, offset);
        }

        public void set(HFSVolumeFinderInfo header) {
            super.blessedSystemFolder = header.blessedSystemFolder;
            super.blessedSystemFolder = header.blessedSystemFolder;
            super.openFolderList = header.openFolderList;
            super.alternateMacOSBlessedSystemFolder =
                    header.alternateMacOSBlessedSystemFolder;
            super.reserved = header.reserved;
            super.alternateMacOSXBlessedSystemFolder =
                    header.alternateMacOSXBlessedSystemFolder;
            super.volumeUUID = header.volumeUUID;
        }

        public final void setBlessedSystemFolder(int rawBlessedSystemFolder) {
            super.blessedSystemFolder = rawBlessedSystemFolder;
        }

        public final void setStartupApplicationParentFolder(
                int rawStartupApplicationParentFolder)
        {
            super.startupApplicationParentFolder =
                    rawStartupApplicationParentFolder;
        }

        public final void setOpenFolderList(int rawOpenFolderList) {
            super.openFolderList = rawOpenFolderList;
        }

        public final void setAlternateMacOSBlessedSystemFolder(
                int rawAlternateMacOSBlessedSystemFolder)
        {
            super.alternateMacOSBlessedSystemFolder =
                    rawAlternateMacOSBlessedSystemFolder;
        }

        public final void setReserved(int rawReserved) {
            super.reserved = rawReserved;
        }

        public final void setAlternateMacOSXBlessedSystemFolder(
                int rawAlternateMacOSXBlessedSystemFolder)
        {
            super.alternateMacOSXBlessedSystemFolder =
                    rawAlternateMacOSXBlessedSystemFolder;
        }

        public final void setVolumeUUID(long rawVolumeUUID) {
            super.volumeUUID = rawVolumeUUID;
        }
    }
}
