/**
 * LOGICAL-PARADOX.ORG
 * Copyright (C)2004 satoshi akabane(akabane@logical-paradox.org)
 *
 */
package org.logical_paradox.common.lang;

import java.io.Serializable;

import org.logical_paradox.common.io.ByteStream;

/**
 * 可変長形式でバイト列変換が可能なNumber
 * @author satoshi akabane@logical-paradox.org
 * @version 1.0
 */
public class VariableFormatNumber extends Number implements Serializable, ByteStream {
	private final long value;
	
	/**
	 * コンストラクタ
	 * 指定されたバイト列から可変長整数を復元する
	 * @param bstream バイト列(可変長形式)
	 */
	public VariableFormatNumber(byte[] bstream) {
		value = byteStreamToLongValue(bstream, 0);
	}
	/**
	 * コンストラクタ
	 * 指定されたバイト列から可変長整数を復元する
	 * @param bstream バイト列(可変長形式)
	 * @param offset 開始オフセット
	 */
	public VariableFormatNumber(byte[] bstream, int offset) {
		value = byteStreamToLongValue(bstream, offset);
	}
	/**
	 * コンストラクタ
	 * @param intval 整数
	 */
	public VariableFormatNumber(int intval) {
		value = (long)intval & 0x00000000ffffffff;
	}
	/**
	 * コンストラクタ
	 * @param longval 整数
	 */
	public VariableFormatNumber(long longval) {
		value = longval;
	}
	/**
	 * コンストラクタ
	 * @param floatval 単精度実数値
	 */
	public VariableFormatNumber(float floatval) {
		value = (long)floatval;
	}
	/**
	 * コンストラクタ
	 * @param doubleval 倍精度実数値
	 */
	public VariableFormatNumber(double doubleval) {
		value = (long)doubleval;
	}
	/**
	 * int値を返す
	 * @return 整数値
	 */
	public int intValue() {
		return (int)value & 0x00000000ffffffff;
	}
	/**
	 * long値を返す
	 * @return 整数値
	 */
	public long longValue() {
		return value;
	}
	/**
	 * float値を返す
	 * @return 単精度実数値
	 */
	public float floatValue() {
		return (float)value;
	}
	/**
	 * doubleを返す
	 * @return 倍精度実数値
	 */
	public double doubleValue() {
		return (double)value;
	}
	/**
	 * 可変長形式のバイト列を返す
	 * @return バイト列(可変長形式)
	 */
	public byte[] byteStream() {
		byte[] tmp = new byte[16];
		int cnt = 15;
		long copy = value;

		while(copy != 0) {
			tmp[cnt] = (byte)(copy & 0x7f);
			copy /= 128;
			if(cnt != 15) {
				tmp[cnt] |= 0x80;
			}
			cnt--;
		}
		byte[] result = new byte[15-cnt];
		if(result.length == 0) {
			// 0の場合
			return new byte[1];
		}
		// それ以外の場合
		System.arraycopy(tmp, cnt+1, result, 0, 15-cnt);
		return result;
	}
	/**
	 * バイト列から整数を復元する
	 * @param bstream バイト列
	 * @param offset 開始オフセット
	 * @return 整数値
	 */
	private long byteStreamToLongValue(byte[] bstream,int offset) {
		long value = 0;
		int i = offset;
		boolean loopf = true;
		
		while(loopf) {
			value += bstream[i] & 0x7f;
			if((bstream[i] & 0x80) == 0) {
				// 最上位ビットが0なので，これが最後のバイトだった
				loopf = false;
			} else {
				// 次のバイトがあるはずなので，7bitシフトする
				value <<= 7;
			}
			i++;
		}

		return value;
	}
}
