/**
	 * Decodes a value of type {@link Length}.
	 * 
	 * @param input
	 *            The {@link InputStream} to decode the value from.
	 * @param type
	 *            Since all methods use the same name, a default value must be
	 *            passed to determine the type of the value to decode. The
	 *            {@link Encoding} class provides constants for each type that
	 *            is supported. The name of the constant equals the typename,
	 *            and is written in capital letters.
	 * @return The decoded value.
	 * @throws NoSuchElementException
	 *             Thrown if {@link input} contains no more elements.
	 * @throws NullPointerException
	 *             Thrown if {@link input} is <i>null</i>.
	 */
	public static Length decode(InputStream input, Length type)
			throws NoSuchElementException, NullPointerException {
		Assert.AssertNotNull(input, "input");

		int length = input.peek();

		input.consume();

		if ((length & 0x80) != 0) {
			long bytes = length & 0x7F;

			if (bytes == 0) {
				return Length.INDEFINITE;
			} else {
				length = 0;

				for (/* Nothing */; bytes > 0; bytes--) {
					length = ((length << 8) | input.peek());
					input.consume();
				}
			}
		}

		return new Length(length);
	}
	/**
	 * Decodes a value of type {@link Octets}.
	 * 
	 * @param input
	 *            The {@link InputStream} to decode the value from.
	 * @param encodedLength
	 *            The encoded length of this value.
	 * @param type
	 *            Since all methods use the same name, a default value must be
	 *            passed to determine the type of the value to decode. The
	 *            {@link Encoding} class provides constants for each type that
	 *            is supported. The name of the constant equals the typename,
	 *            and is written in capital letters.
	 * @return The decoded value.
	 * @throws NoSuchElementException
	 *             Thrown if {@link input} contains no more elements.
	 * @throws NullPointerException
	 *             Thrown if {@link input} is <i>null</i>.
	 */
	public static Octets decode(InputStream input, int encodedLength,
			Octets type) throws NoSuchElementException, NullPointerException {
		Assert.AssertNotNull(input, "input");

		final ArrayList<Integer> data = new ArrayList<Integer>(encodedLength);

		for (int i = 0; i < encodedLength; ++i) {
			data.add(input.peek() & 0xFF);
			input.consume();
		}

		return new Octets(data);
	}
	/**
		 * Decodes a {@link Tag}. Since the length is not required, it must not be passed.
		 * @param input The {@link InputStream to decode the value from.
		 * @param type Since all methods use the same name, a default value must be passed to 
		 * 			determine the type of the value to decode. The {@link Encoding} class provides 
		 * 			constants for each type that is supported. The name of the constant equals
		 * 			the typename, and is written in capital letters.
		 * @return The decoded value.
		 * @throws NoSuchElementException Thrown if {@link input} contains no more elements.
		 * @throws NullPointerException Thrown if {@link input} is <i>null</i>. 
		 */
		public static Tag decode(InputStream input, Tag type)
				throws NoSuchElementException, NullPointerException {
			Assert.AssertNotNull(input, "input");
	
			final int peek = input.peek();
	
			input.consume();
	
			final int preamble = peek & 0xE0;
	
			int number = peek & 0x1F;
	
			if (number == 0x1F)
				number = (int) MultiByte.decode(input);
	
			return new Tag(preamble, number);
		}
	/**
	 * Decodes a value of type <i>String</i>.
	 * 
	 * @param input
	 *            The {@link InputStream} to decode the value from.
	 * @param encodedLength
	 *            The encoded length of this value.
	 * @param type
	 *            Since all methods use the same name, a default value must be
	 *            passed to determine the type of the value to decode. The
	 *            {@link Encoding} class provides constants for each type that
	 *            is supported. The name of the constant equals the typename,
	 *            and is written in capital letters.
	 * @return The decoded value.
	 * @throws NoSuchElementException
	 *             Thrown if {@link input} contains no more elements.
	 * @throws NullPointerException
	 *             Thrown if {@link input} is <i>null</i>.
	 */
	public static String decode(InputStream input, int encodedLength,
			String type) throws NoSuchElementException, NullPointerException {
		Assert.AssertNotNull(input, "input");

		final byte[] encodedString = new byte[encodedLength];

		for (int i = 0; i < encodedLength; ++i) {
			encodedString[i] = (byte) input.peek();
			input.consume();
		}

		try {
			return new String(encodedString, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			return "";
		}
	}
	/**
	 * Decodes an integer value.
	 * 
	 * @param input
	 *            The {@link InputStream} to read the encoded data from.
	 * @param length
	 *            The encoded length of the value to decode.
	 * @param isSigned
	 *            Indicates whether the encoded value is signed or unsigned.
	 * @return The decoded value.
	 * @throws NoSuchElementException
	 *             Thrown if {@link input} contains no more elements.
	 */
	private static long decodeLong(InputStream input, int length,
			boolean isSigned) throws NoSuchElementException {
		long value = 0;
		long read = 0;

		for (long byteCount = 0; byteCount < length; byteCount++) {
			read = input.peek();
			input.consume();

			if (byteCount == 0 && (read & 0x80) != 0 && isSigned) {
				read -= 0x100;
			}

			value = (value << 8) | read;
		}

		return value;
	}
	/**
	 * Decodes a value of type <i>long</i>. Since the length is not required, it
	 * must not be passed.
	 * 
	 * @param input
	 *            The {@link InputStream} to decode the value from.
	 * @param type
	 *            Since all methods use the same name, a default value must be
	 *            passed to determine the type of the value to decode. The
	 *            {@link Encoding} class provides constants for each type that
	 *            is supported. The name of the constant equals the typename,
	 *            and is written in capital letters.
	 * @return The decoded value.
	 * @throws NoSuchElementException
	 *             Thrown if {@link input} contains no more elements.
	 * @throws NullPointerException
	 *             Thrown if {@link input} is <i>null</i>.
	 */
	public static long decode(InputStream input, int encodedLength, long type)
			throws NoSuchElementException, NullPointerException {
		Assert.AssertNotNull(input, "input");

		long value = 0;

		for (int i = 0; i < encodedLength; i++) {
			final long part = input.peek();

			if ((i == 0) && (part == 0x80)) {
				value = part;
				value -= 0x100;
			} else {
				value = (value << 8) | part;
			}
			input.consume();
		}

		return value;
	}
	/**
	 * Decodes a value of type <i>double</i>.
	 * 
	 * @param input
	 *            The {@link InputStream} to decode the value from.
	 * @param encodedLength
	 *            The encoded length of this value.
	 * @param type
	 *            Since all methods use the same name, a default value must be
	 *            passed to determine the type of the value to decode. The
	 *            {@link Encoding} class provides constants for each type that
	 *            is supported. The name of the constant equals the typename,
	 *            and is written in capital letters.
	 * @return The decoded value.
	 * @throws NoSuchElementException
	 *             Thrown if {@link input} contains no more elements.
	 * @throws NullPointerException
	 *             Thrown if {@link input} is <i>null</i>.
	 */
	public static double decode(InputStream input, int encodedLength,
			double type) throws NoSuchElementException, NullPointerException {
		Assert.AssertNotNull(input, "input");

		if (encodedLength == 0) {
			return 0.0;
		}

		final int preamble = input.peek();

		input.consume();

		if (encodedLength == 1) {
			if (preamble == 0x40) {
				return Double.POSITIVE_INFINITY;
			} else if (preamble == 0x41) {
				return Double.NEGATIVE_INFINITY;
			}
		}

		final int exponentLength = 1 + (preamble & 3);
		final int sign = (preamble & 0x40);
		final int ff = (preamble >> 2) & 3;

		long exponent = decodeLong(input, exponentLength, true);
		long mantissa = decodeLong(input, encodedLength - exponentLength - 1,
				false) << ff;

		while ((mantissa & 0x7FFFF00000000000L) == 0x0)
			mantissa <<= 8;

		while ((mantissa & 0x7FF0000000000000L) == 0x0)
			mantissa <<= 1;

		mantissa &= 0x0FFFFFFFFFFFFFL;

		final long bits = ((exponent + 1023) << 52) | mantissa
				| (sign != 0 ? 0x8000000000000000L : 0);

		return Double.longBitsToDouble(bits);
	}