package jp.agentec.adf.security.cryptography;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import jp.agentec.adf.util.StringUtil;

/**
 * MD5アルゴリズムを使って、文字列をハッシュする機能を提供します。
 * @author Taejin Hong
 * @version　1.0.0 
 */
public class MD5 {
	/**
	 * 指定した文字列のMD5ハッシュを取得します。
	 * @param input ハッシュ化する文字列です。
	 * @return MD5ハッシュ化した文字列を返します。inputがnull又は空文字の場合、空文字を返します。
	 * @since 1.0.0
	 */
	public static String getMd5Hash(String input) throws NoSuchAlgorithmException {
		StringBuffer sb = new StringBuffer();

		if (!StringUtil.isNullOrEmpty(input)) {
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.reset();

			byte[] bytesOfPassword = input.getBytes();
			byte[] bytesOfEncryptedPassword = md.digest(bytesOfPassword);

			if (bytesOfEncryptedPassword != null && bytesOfEncryptedPassword.length > 0) {
				for (byte b : bytesOfEncryptedPassword) {
					sb.append((Integer.toHexString((b & 0xFF | 0x100)).substring(1, 3)));
				}
			}
		}

		return sb.toString();
	}

	/**
	 * 指定した文字列 input と、ハッシュ文字列 hash を比較します。大文字・小文字の区別はありません。
	 * @param input hashと比較する文字列です。
	 * @param hash MD5ハッシュ文字列です。
	 * @return inputとhashが同じであればtrueを返します。
	 * @since 1.0.0
	 */
	public static boolean verifyMd5Hash(String input, String hash) throws NoSuchAlgorithmException {
		return verifyMd5Hash(input, hash, true);
	}

	/**
	 * 指定した文字列 input と、ハッシュ文字列 hash を比較します。大文字・小文字の区別はありません。
	 * @param input hashと比較する文字列です。
	 * @param hash MD5ハッシュ文字列です。
	 * @param ignoreCase falseに設定すると、比較する際、大文字・小文字を区別します。
	 * @return inputとhashが同じであればtrueを返します。
	 * @since 1.0.0
	 */
	public static boolean verifyMd5Hash(String input, String hash, boolean ignoreCase) throws NoSuchAlgorithmException {
		boolean result;

		String hashOfInput = StringUtil.Empty;

		if (!StringUtil.isNullOrEmpty(input)) {
			hashOfInput = getMd5Hash(input);
		}

		if (ignoreCase) {
			result = hashOfInput.equalsIgnoreCase(hash);
		} else {
			result = hashOfInput.equals(hash);
		}

		return result;
	}

	/**
	 * 引数に指定したファイルのハッシュ値を返す
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public static String getMD5Hash(File file) throws IOException {
		MessageDigest digest;
		try {
			digest = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) { // コーディング上のエラーはそのままthrowしない
			throw new RuntimeException(e);
		}

		InputStream in = null;
		try {
			in = new FileInputStream(file);
			byte[] buff = new byte[4096];
			int len;
			while ((len = in.read(buff, 0, buff.length)) >= 0) {
				digest.update(buff, 0, len);
			}
		} catch (IOException e) {
			throw e;
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
				}
			}
		}
		byte[] hash = digest.digest();

		StringBuffer sb = new StringBuffer();
		if (hash != null && hash.length > 0) {
			for (byte b : hash) {
				sb.append((Integer.toHexString((b & 0xFF | 0x100)).substring(1, 3)));
			}
		}
		return sb.toString();
	}

}
