package net.waltzstudio.base.framework.seasar.extension.jdbc.types;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.seasar.extension.jdbc.types.AbstractValueType;
import org.seasar.extension.jdbc.util.BindVariableUtil;
import org.seasar.framework.beans.BeanDesc;
import org.seasar.framework.beans.factory.BeanDescFactory;

public class EnumStringType extends AbstractValueType {
	public static final String METHOD_NAME = "convert";
	public static final String PROPERTY_NAME = "value";

	@SuppressWarnings("rawtypes")
	private final Class<? extends Enum> enumClass;

	@SuppressWarnings("rawtypes")
	public EnumStringType(Class<? extends Enum> enumClass) {
		super(Types.VARCHAR);
		this.enumClass = enumClass;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected Enum toEnum(String name) {
		if (name == null) {
			return null;
		}
		if (Enum.class.isAssignableFrom(enumClass)) {
			BeanDesc b = BeanDescFactory.getBeanDesc(enumClass);
			if (b.hasMethod(METHOD_NAME)) {
				return (Enum) b.invoke(null, METHOD_NAME, new Object[] { name });
			}
		}
		return Enum.valueOf(enumClass, name);
	}

	protected String fromEnum(Object value) {
		if (Enum.class.isAssignableFrom(enumClass)) {
			BeanDesc b = BeanDescFactory.getBeanDesc(enumClass);
			if (b.hasPropertyDesc(PROPERTY_NAME)) {
				return (String) b.getPropertyDesc(PROPERTY_NAME).getValue(value);
			}
		}
		return Enum.class.cast(value).name();
	}

	public Object getValue(ResultSet rs, int index) throws SQLException {
		return toEnum(rs.getString(index));
	}

	public Object getValue(ResultSet rs, String columnName) throws SQLException {
		return toEnum(rs.getString(columnName));
	}

	public Object getValue(CallableStatement cs, int index) throws SQLException {
		return toEnum(cs.getString(index));
	}

	public Object getValue(CallableStatement cs, String parameterName) throws SQLException {
		return toEnum(cs.getString(parameterName));
	}

	public void bindValue(PreparedStatement ps, int index, Object value) throws SQLException {
		if (value == null) {
			setNull(ps, index);
		} else {
			ps.setString(index, fromEnum(value));
		}
	}

	public void bindValue(CallableStatement cs, String parameterName, Object value) throws SQLException {
		if (value == null) {
			setNull(cs, parameterName);
		} else {
			cs.setString(parameterName, fromEnum(value));
		}
	}

	public String toText(Object value) {
		if (value == null) {
			return BindVariableUtil.nullText();
		}
		return BindVariableUtil.toText(fromEnum(value));
	}

}
