/*
 * AppleCommander - An Apple ][ image utility.
 * Copyright (C) 2003-2022 by Robert Greene
 * robgreene at users.sourceforge.net
 *
 * 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 2 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, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
package com.webcodepro.applecommander.storage.physical;

import com.webcodepro.applecommander.storage.Disk;
import com.webcodepro.applecommander.storage.StorageBundle;
import com.webcodepro.applecommander.storage.os.dos33.DosSectorAddress;
import com.webcodepro.applecommander.util.TextBundle;

/**
 * Supports disk images stored in DOS physical order.
 * <p>
 * @author Rob Greene (RobGreene@users.sourceforge.net)
 */
public class DosOrder extends ImageOrder {
	private TextBundle textBundle = StorageBundle.getInstance();
	/**
	 * Construct a DosOrder.
	 */
	public DosOrder(ByteArrayImageLayout diskImageManager) {
		super(diskImageManager);
	}

	/**
	 * Indicates that this device is block ordered.
	 */
	public boolean isBlockDevice() {
		return false;
	}

	/**
	 * Indicates that this device is track and sector ordered.
	 */
	public boolean isTrackAndSectorDevice() {
		return true;
	}

	/**
	 * Retrieve the specified sector.
	 */
	public byte[] readSector(int track, int sector) throws IllegalArgumentException {
		return readBytes(getOffset(track, sector), Disk.SECTOR_SIZE);
	}

	/**
	 * Write the specified sector.
	 */
	public void writeSector(int track, int sector, byte[] bytes)
			throws IllegalArgumentException {
		writeBytes(getOffset(track, sector), bytes);
	}

	/**
	 * Compute the track and sector offset into the disk image.
	 * This takes into account what type of format is being dealt
	 * with.
	 */
	protected int getOffset(int track, int sector) throws IllegalArgumentException {
		if (!isSizeApprox(Disk.APPLE_140KB_DISK)
				&& !isSizeApprox(Disk.APPLE_800KB_DISK)
				&& !isSizeApprox(Disk.APPLE_800KB_2IMG_DISK)
				&& track != 0 && sector != 0) {		// HACK: Allows boot sector writing
			throw new IllegalArgumentException(
					textBundle.get("DosOrder.UnrecognizedFormatError")); //$NON-NLS-1$
		}
		int offset = (track * getSectorsPerTrack() + sector) * Disk.SECTOR_SIZE;
		if (offset > getPhysicalSize()) {
			throw new IllegalArgumentException(
					textBundle.format("DosOrder.InvalidSizeError", //$NON-NLS-1$
							track, sector));
		}
		return offset;
	}

	/**
	 * Read the block from the disk image.
	 * Note: Defined in terms of reading sectors.
	 */
	public byte[] readBlock(int block) {
		DosSectorAddress[] sectors = blockToSectors525(block);
		byte[] blockData = new byte[Disk.BLOCK_SIZE];
		System.arraycopy(readSector(sectors[0].track, sectors[0].sector), 0, blockData, 0, Disk.SECTOR_SIZE);
		System.arraycopy(readSector(sectors[1].track, sectors[1].sector), 0, blockData, Disk.SECTOR_SIZE, Disk.SECTOR_SIZE);
		return blockData;
	}

	/**
	 * Write the block to the disk image.
	 * Note: Defined in terms of reading sectors.
	 */
	public void writeBlock(int block, byte[] data) {
		DosSectorAddress[] sectors = blockToSectors525(block);
		byte[] sectorData = new byte[Disk.SECTOR_SIZE];
		System.arraycopy(data, 0, sectorData, 0, Disk.SECTOR_SIZE);
		writeSector(sectors[0].track, sectors[0].sector, sectorData);
		System.arraycopy(data, Disk.SECTOR_SIZE, sectorData, 0, Disk.SECTOR_SIZE);
		writeSector(sectors[1].track, sectors[1].sector, sectorData);
	}

	/**
	 * Return the name of this image order.
	 */
	public String getName() {
		return textBundle.get("DosOrder.OrderName"); //$NON-NLS-1$
	}

	public static DosSectorAddress[] blockToSectors525(int block) {
		int track = block / 8;
		int sectorIndex = block % 8;
		int[] sectorMapping1 = { 0, 13, 11, 9, 7, 5, 3, 1 };
		int[] sectorMapping2 = { 14, 12, 10, 8, 6, 4, 2, 15 };
		int sector1 = sectorMapping1[sectorIndex];
		int sector2 = sectorMapping2[sectorIndex];
		return new DosSectorAddress[] {
				new DosSectorAddress(track, sector1),
				new DosSectorAddress(track, sector2)
		};
	}
}
