package jp.co.ase.izpack.util;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

import com.izforge.izpack.installer.AutomatedInstallData;
import com.izforge.izpack.installer.DataValidator;

public class LDAPConnectValidator implements DataValidator {
	protected DirContext ctx;

	/**
	 * 指定された情報でLDAP接続できるかチェックする。
	 *
	 * @param idata
	 * @return
	 */
	public boolean canCconnect(AutomatedInstallData idata) {
		String host = idata.getVariable("ldap_host");
		String port = idata.getVariable("ldap_port");
		String baseDn = idata.getVariable("ldap_base_dn");
		String bindDn = idata.getVariable("ldap_bind_dn");
		String bindPassword = idata.getVariable("ldap_bind_password");
		Hashtable<String, String> env = getLdapEnv(host, port, baseDn, bindDn, bindPassword);
		boolean result = canCertify(env);
		return result;
	}

	/**
	 * 認証できるかチェックする。
	 *
	 * @param env
	 * @return
	 */
	public boolean canCertify(Hashtable<String, String> env) {
		try {
			ctx = new InitialDirContext(env);
		} catch (NamingException e) {
			return false;
		}
		return true;
	}

	/**
	 * 匿名バインドが許可されていないのでBind認証情報のある環境情報を返却する。
	 *
	 * @param host
	 * @param port
	 * @param dn
	 * @param bindDn
	 * @param bindPassword
	 * @return
	 */
	public Hashtable<String, String> getLdapEnv(String host, String port, String dn, String bindDn,
	        String bindPassword) {
		Hashtable<String, String> env = new Hashtable<String, String>();

		// JNDIでLDAPを使うという設定
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");

		// URL
		StringBuilder urlBuf = new StringBuilder();
		urlBuf.append("ldap://");
		urlBuf.append(host);
		if (port != null) {
			urlBuf.append(":").append(port);
		}
		env.put(Context.PROVIDER_URL, urlBuf.toString());

		// 接続タイムアウトの設定(10秒)
		env.put("com.sun.jndi.ldap.read.timeout", "10000");
		env.put("com.sun.jndi.ldap.connect.timeout", "10000");

		if ((bindDn != null && bindDn.length() != 0)
		        && (bindPassword != null && bindPassword.length() != 0)) {
			env.put(Context.SECURITY_AUTHENTICATION, "simple");
			env.put(Context.SECURITY_PRINCIPAL, bindDn);
			env.put(Context.SECURITY_CREDENTIALS, bindPassword);
		} else {
			env.put(Context.SECURITY_PRINCIPAL, dn);
			env.put(Context.SECURITY_AUTHENTICATION, "none");
		}

		return env;
	}

	public boolean getDefaultAnswer() {
		return true;
	}

	/**
	 * エラーメッセージを返却する。
	 */
	public String getErrorMessageId() {
		return "接続に失敗しました。再度入力内容をご確認ください。";
	}

	/**
	 * ここにくることはないが、とりあえずエラーメッセージと同じにしておく。
	 */
	public String getWarningMessageId() {
		return "接続に失敗しました。再度入力内容をご確認ください。";
	}

	/**
	 * validate処理を行う。
	 */
	public Status validateData(AutomatedInstallData idata) {
		Status status = Status.ERROR;
		String ldap_setting = idata.getVariable("ldap_setting");
		if ("1".equals(ldap_setting) || "true".equals(ldap_setting)) {
			// 外部LDAPの設定を行うとき
			boolean canCconnect = canCconnect(idata);
			if (canCconnect == true) {
				status = Status.OK;
			}
			if (ctx != null) {
				try {
					ctx.close();
				} catch (Exception e) {
				}
			}
		} else {
			// 外部LDAPを使わないとき
			status = Status.OK;
		}
		return status;
	}
}
