/*
 * Copyright (c) 2016 Audi AG
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */

package org.eclipse.mdm.mdfsorter.mdf3;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * @author EU2IYD9
 *
 */
public abstract class MDF3Util {

	/**
	 * Returns the expected number of links for a specific MDF3 Blocktype.
	 *
	 * @param blockID
	 *            The ID-String of the block, e.g. "HD", "DT"...
	 * @return The number of Links, return[0] = number of links in the link
	 *         section, return[1] = total number of links
	 */
	public static int getLinkcount(String blockID) {
		if (blockID.length() != 2) {
			throw new IllegalArgumentException("ID-Length = " + blockID.length());
		}

		switch (blockID) {
		case "HD":
			return 3;
		case "TX":
			return 0;
		case "PR":
			return 0;
		case "TR":
			return 1;
		case "SR":
			return 2;
		case "DG":
			return 4; // special case: pointer to data
		case "CG":
			return 3; // includes link to SR-BLOCK
		case "CN":
			return 5;
		case "CD":
			return 0;
		case "CE":
			return 0;
		case "CC":
			return 0;
		default:
			System.err.println("Unknown blocktype: " + blockID);
			return 0;
		}
	}

	/**
	 * Read an 8-bit signed integer from the byte buffer.
	 *
	 * @param bb
	 *            The byte buffer.
	 * @return The value.
	 */
	public static int readUInt8(ByteBuffer bb) {
		return bb.get() & 0xff;
	}

	/**
	 * Read an 16-bit unsigned integer from the byte buffer.
	 *
	 * @param bb
	 *            The byte buffer.
	 * @param bigendian
	 *            True, if this number is in BigEndian order, false if
	 *            LittleEndian.
	 * @return The value.
	 */
	public static int readUInt16(ByteBuffer bb, boolean bigendian) {
		setByteOrder(bb, bigendian);
		return bb.getShort() & 0xffff;
	}

	/**
	 * Get a byte array from an 16-bit unsigned integer. (Little Endian)
	 *
	 * @param val
	 *            The number to convert.
	 * @param bigendian
	 *            True, if this number is in BigEndian order, false if
	 *            LittleEndian.
	 * @return The bytes.
	 */
	public static byte[] getBytesUInt16(int val, boolean bigendian) {
		ByteBuffer b = ByteBuffer.allocate(2);
		setByteOrder(b, bigendian);
		b.putShort((short) val);
		return b.array();
	}

	/**
	 * Read an 16-bit signed integer from the byte buffer.
	 *
	 * @param bb
	 *            The byte buffer.
	 * @param bigendian
	 *            True, if this number is in BigEndian order, false if
	 *            LittleEndian.
	 * @return The value.
	 */
	public static short readInt16(ByteBuffer bb, boolean bigendian) {
		setByteOrder(bb, bigendian);
		return bb.getShort();
	}

	/**
	 * Get a byte array from an 16-bit signed integer. (Little Endian)
	 *
	 * @param val
	 *            The number to convert.
	 * @param bigendian
	 *            True, if this number is in BigEndian order, false if
	 *            LittleEndian.
	 * @return The bytes.
	 */
	public static byte[] getBytesInt16(short val, boolean bigendian) {
		ByteBuffer b = ByteBuffer.allocate(2);
		setByteOrder(b, bigendian);
		b.putShort(val);
		return b.array();
	}

	/**
	 * Read an 32-bit unsigned integer from the byte buffer.
	 *
	 * @param bb
	 *            The byte buffer.
	 * @param bigendian
	 *            True, if this number is in BigEndian order, false if
	 *            LittleEndian.
	 * @return The value.
	 */
	public static long readUInt32(ByteBuffer bb, boolean bigendian) {
		setByteOrder(bb, bigendian);
		return bb.getInt() & 0xffffffffL;
	}

	/**
	 * Get a byte array form an 32-bit unsigned integer. (Little Endian)
	 *
	 * @param val
	 *            The number to convert.
	 * @param bigendian
	 *            True, if this number is in BigEndian order, false if
	 *            LittleEndian.
	 * @return The bytes.
	 */
	public static byte[] getBytesUInt32(long val, boolean bigendian) {
		ByteBuffer b = ByteBuffer.allocate(4);
		setByteOrder(b, bigendian);
		b.putInt((int) val);
		return b.array();
	}

	public static long readUInt64(ByteBuffer bb, boolean bigendian) {
		setByteOrder(bb, bigendian);
		return bb.getLong();
	}

	public static byte[] getBytesUInt64(long val, boolean bigendian) {
		ByteBuffer b = ByteBuffer.allocate(8);
		setByteOrder(b, bigendian);
		b.putLong(val);
		return b.array();
	}

	public static boolean readBool(ByteBuffer bb, boolean bigendian) {
		return readUInt16(bb, bigendian) != 0;
	}

	public static byte[] getBytesBool(boolean val, boolean bigendian) {
		if (val) {
			return getBytesInt16((short) 1, bigendian);
		} else {
			return getBytesInt16((short) 0, bigendian);
		}
	}

	private static void setByteOrder(ByteBuffer buf, boolean bigendian) {
		if (bigendian) {
			buf.order(ByteOrder.BIG_ENDIAN);
		} else {
			buf.order(ByteOrder.LITTLE_ENDIAN);
		}
	}

	/**
	 * Read a LINK.
	 *
	 * @param bb
	 *            The ByteBuffer to read from.
	 * @param bigendian
	 *            True, if this number is in BigEndian order, false if
	 *            LittleEndian.
	 * @return The value of this link.
	 */
	public static long readLink(ByteBuffer bb, boolean bigendian) {
		return readUInt32(bb, bigendian);
	}

	/**
	 * Get bytes from a link address.
	 *
	 * @param val
	 *            The value.
	 * @param bigendian
	 *            True, if this number is in BigEndian order, false if
	 *            LittleEndian.
	 * @return The link address as byte array.
	 */
	public static byte[] getBytesLink(long val, boolean bigendian) {
		return getBytesUInt32(val, bigendian);
	}

	/**
	 * Read a String from ISO8859 encoded bytes
	 *
	 * @param bb
	 *            The ByteBuffer to use.
	 * @param length
	 *            Number of chars to read.
	 * @return The result as String.
	 * @throws IOException
	 *             If an reading error occurs.
	 */
	public static String readCharsISO8859(ByteBuffer bb, int length) throws IOException {
		byte[] b = new byte[length];
		bb.get(b);
		return new String(b, 0, length, "ISO-8859-1");
	}

	public static byte[] getBytesCharsISO8859(String s) throws IOException {
		return s.getBytes("ISO-8859-1");
	}

}
