package org.phosphoresce.commons.util;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

/**
 * バイト操作関連ユーティリティクラス<br>
 *
 * @author Kitagawa<br>
 *
 *<!--
 * 更新日		更新者			更新内容
 * 2008/10/31	Kitagawa		新規作成
 * 2010/07/20	Kitagawa		printByteTrace(byte[], Writer)追加
 *-->
 */
public final class ByteUtil {

	/**
	 * コンストラクタ<br>
	 */
	private ByteUtil() {
		//
	}

	/**
	 * 指定されたバイト情報を詳細ログ出力します。<br>
	 * @param bytes バイト配列
	 * @param writer ログ出力Writerオブジェクト
	 * @throws IOException ログ出力時に入出力例外が発生した場合にスローされます
	 */
	public static void printByteTrace(byte[] bytes, Writer writer) throws IOException {
		if (bytes == null) {
			writer.write("Bytes is null");
			writer.write("\n");
		} else {
			int length = bytes.length;
			writer.write("Byte Length : " + length);
			writer.write("\n");
			if (length == 0) {
				return;
			}
			for (int r = 0; r <= length / 16; r++) {
				if (r * 16 == length) {
					break;
				}

				StringBuffer line = new StringBuffer();

				// 行番号出力
				String row = Integer.toHexString(r * 16);
				while (row.length() < 8) {
					row = "0" + row;
				}
				line.append(row);
				line.append(": ");

				// 16バイト毎の行出力
				byte[] buffer = new byte[16];
				for (int i = r * 16, s = 0, c = 0; i <= r * 16 + 16 - 1; i++, c++) {
					if (i > bytes.length - 1) {
						// バイト長が末尾に達した場合も出力位置を揃える
						line.append("   ");
					} else {
						// Hex値が1byteの場合に2byte補正出力
						String hex = Integer.toHexString(bytes[i]).replaceAll("ffffff", "");
						while (hex.length() < 2) {
							hex = "0" + hex;
						}
						line.append(hex);
						line.append(" ");
					}

					// 8byte毎にセパレート
					if (s == 7) {
						line.append(" ");
						s = 0;
					} else {
						s++;
					}

					// 16byte分のバッファ
					buffer[c] = (i > bytes.length - 1) ? " ".getBytes()[0] : bytes[i];
					if ((buffer[c] >= 0 && buffer[c] <= 31) || buffer[c] == 127) {
						// 制御文字は.(ピリオドで出力)
						buffer[c] = ".".getBytes()[0];
					}
				}
				writer.write(line.toString() + new String(buffer));
				writer.write("\n");
				writer.flush();
			}
		}
		writer.flush();
	}

	/**
	 * 指定されたバイト情報を詳細ログ出力します。<br>
	 * @param bytes バイト配列
	 * @param stream ログ出力OutputStreamオブジェクト
	 * @throws IOException ログ出力時に入出力例外が発生した場合にスローされます
	 */
	public static void printByteTrace(byte[] bytes, OutputStream stream) throws IOException {
		printByteTrace(bytes, new OutputStreamWriter(stream));
	}
}
