package jp.agentec.abook.abv.bl.common.util;

import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.apache.commons.codec.binary.Base64;

import jp.agentec.abook.abv.bl.common.exception.ABVRuntimeException;
import jp.agentec.adf.security.cryptography.AES;
import jp.agentec.adf.security.cryptography.MD5;
import jp.agentec.adf.util.StringUtil;

public class SecurityUtil {
	private static final String[] RegexAllowSymbols = new String[] {"-", "_"};
	
	/**
	 * 指定したユーザIDが有効な形式か確認します。
	 * @param loginId ユーザIDです。
	 * @throws IllegalArgumentException パラメータが有効ではありません。
	 * @since 1.0.0
	 */
	public static void validateLoginId(String loginId) throws IllegalArgumentException {
		if (!StringUtil.isHankaku(loginId, true, true, RegexAllowSymbols)) {
			throw new IllegalArgumentException("argument loginId must be hankaku, '_' or '-'. ");
		}
	}
	
	/**
	 * 指定したパスワードが有効な形式か確認します。
	 * @param password パスワードです。
	 * @throws IllegalArgumentException パラメータが有効ではありません。
	 * @since 1.0.0
	 */
	public static void validatePassword(String password) throws IllegalArgumentException {
		if (!StringUtil.isHankaku(password, true, true, RegexAllowSymbols)) {
			throw new IllegalArgumentException("argument password must be hankaku, '_' or '-'. ");
		}
	}
	
	/**
	 * 指定したudidが有効な形式か確認します。
	 * @param udid 端末のudidです。
	 * @throws IllegalArgumentException パラメータが有効ではありません。
	 * @since 1.0.0
	 */
	@Deprecated
	public static void validateUdid(String udid) throws IllegalArgumentException {
		if (!StringUtil.isHankaku(udid, true, true, RegexAllowSymbols)) {
			throw new IllegalArgumentException("argument udid must be hankaku, '_' or '-'. ");
		}
	}
	
	/**
	 * 指定したユーザID、パスワード、UDIDが有効な形式か確認します。
	 * @param loginId ユーザIDです。
	 * @param password パスワードです。
	 * @param udid 端末のudidです。
	 * @throws IllegalArgumentException パラメータが有効ではありません。
	 * @since 1.0.0
	 */
	@Deprecated
	public static void validateLoginInformation(String loginId, String password, String udid) throws IllegalArgumentException {
		String msg = "";
		
		try {
			validateLoginId(loginId);
		} catch (Exception e) {
			msg += e.getMessage();
		}
		
		try {
			validatePassword(password);
		} catch (Exception e) {
			msg += e.getMessage();
		}
		
		try {
			validateUdid(udid);
		} catch (Exception e) {
			msg += e.getMessage();
		}
		
		if (!StringUtil.isNullOrEmpty(msg)) {
			throw new IllegalArgumentException(msg);
		}
	}
	
	/**
	 * 指定したユーザID、パスワード、UDIDが有効な形式か確認します。
	 * @param loginId ユーザIDです。
	 * @param password パスワードです。
	 * @throws IllegalArgumentException パラメータが有効ではありません。
	 * @since 1.0.0
	 */
	public static void validateLoginInformation(String loginId, String password) throws IllegalArgumentException {
		String msg = "";
		
		try {
			validateLoginId(loginId);
		} catch (Exception e) {
			msg += e.getMessage();
		}
		
		try {
			validatePassword(password);
		} catch (Exception e) {
			msg += e.getMessage();
		}
		
		if (!StringUtil.isNullOrEmpty(msg)) {
			throw new IllegalArgumentException(msg);
		}
	}
	
	/**
	 * パスワードをAESアルゴリズムで暗号化します。
	 * @param password　パスワードです。
	 * @param keyString AESのキー文字列です。
	 * @return 暗号化したパスワードを返します。
	 * @since 1.0.0
	 */
	public static String encryptPassword(String password, String keyString) {
		if (!StringUtil.isNullOrEmpty(password) && !StringUtil.isNullOrEmpty(keyString)) {
			try {
				return new String(AES.encrypt(password, AES.generateKey(keyString)));
			} catch (InvalidKeyException e) {
				throw new ABVRuntimeException(e);
			} catch (NoSuchAlgorithmException e) {
				throw new ABVRuntimeException(e);
			} catch (NoSuchPaddingException e) {
				throw new ABVRuntimeException(e);
			} catch (IllegalBlockSizeException e) {
				throw new ABVRuntimeException(e);
			} catch (BadPaddingException e) {
				throw new ABVRuntimeException(e);
			}
		} else {
			return null;
		}
	}
	
	/**
	 * コンテンツのZIPファイルのパスワードを取得します。
	 * @param contentId コンテンツIDです。
	 * @param passwordPrefix パスワードのprefixです。この値は決まっています。
	 * @return ZIPファイルのパスワードを返します。
	 * @since 1.0.0
	 */
	public static String getZipPassword(long contentId, String passwordPrefix) throws NoSuchAlgorithmException {
		String password = null;
		
		if (!StringUtil.isNullOrWhiteSpace(passwordPrefix)) {
			password = MD5.getMd5Hash(passwordPrefix + StringUtil.toString(contentId)).toUpperCase();
		}
		
		return password;
	}
	
	public static String getZipPassword(String passwordPrefix, String userPassword) throws NoSuchAlgorithmException {
		String password = null;
		
		if (!StringUtil.isNullOrWhiteSpace(passwordPrefix)) {
			password = MD5.getMd5Hash(passwordPrefix + userPassword).toUpperCase();
		}
		
		return password;
	}
	

	public static byte[] encrypt(String name, String generateKey) {
		try {
			return AES.encrypt(name, AES.generateKey(generateKey));
		} catch (Exception e) {
			throw new ABVRuntimeException(e);
		}
	}

	public static String getOutZipPassword(String loginId, String passwordPrefix) throws NoSuchAlgorithmException {
		String password = null;
		
		if (!StringUtil.isNullOrWhiteSpace(passwordPrefix)) {
			password = MD5.getMd5Hash(passwordPrefix + StringUtil.toString(loginId)).toUpperCase();
		}
		
		return password;
	}
	
	/**
	 * AES.encryptECB()のラッパー
	 * ExceptionをRuntimeに変えてスロー
	 * 
	 * @param input
	 * @param secureKey
	 * @return
	 */
	public static byte[] encryptECB(String input, Key secureKey) {
		try {
			return AES.encryptECB(input, secureKey);
		} catch (InvalidKeyException e) {
			throw new ABVRuntimeException(e);
		} catch (NoSuchAlgorithmException e) {
			throw new ABVRuntimeException(e);
		} catch (NoSuchPaddingException e) {
			throw new ABVRuntimeException(e);
		} catch (IllegalBlockSizeException e) {
			throw new ABVRuntimeException(e);
		} catch (BadPaddingException e) {
			throw new ABVRuntimeException(e);
		}
	}

	/**
	 * AES.generateKey()のラッパー
	 * ExceptionをRuntimeに変えてスロー
	 * 
	 * @param keyString
	 * @return
	 */
	public static Key generateKey(String keyString) {
		try {
			return AES.generateKey(keyString);
		} catch (NoSuchAlgorithmException e) {
			throw new ABVRuntimeException(e);
		}
	}
	
	public static String getMd5Hash(String input) {
		try {
			return MD5.getMd5Hash(input);
		} catch (NoSuchAlgorithmException e) {
			throw new ABVRuntimeException(e);
		}
	}

	public static String getEncryptString(String keyString, String val, boolean urlEncode) {
		Key key = SecurityUtil.generateKey(keyString);
		byte[] encrypted = SecurityUtil.encryptECB(val, key);
		String result = new String(Base64.encodeBase64(encrypted));
		if (urlEncode) {
			return StringUtil.urlEncode(result, "UTF-8");
		}
		else {
			return result;
		}
	}

}
