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 EnumIntegerType 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 EnumIntegerType(Class<? extends Enum> enumClass) {
		super(Types.INTEGER);
		this.enumClass = enumClass;
	}

	@SuppressWarnings({ "rawtypes" })
	protected Enum toEnum(Integer ordinal) {
		if (ordinal == 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[] { ordinal });
			}
		}
		return enumClass.getEnumConstants()[ordinal];
	}

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

	public Object getValue(ResultSet resultSet, int index) throws SQLException {
		int ordinal = resultSet.getInt(index);
		if (ordinal == 0 && resultSet.wasNull()) {
			return null;
		}
		return toEnum(resultSet.getInt(index));
	}

	public Object getValue(ResultSet resultSet, String columnName) throws SQLException {
		int ordinal = resultSet.getInt(columnName);
		if (ordinal == 0 && resultSet.wasNull()) {
			return null;
		}
		return toEnum(ordinal);
	}

	public Object getValue(CallableStatement cs, int index) throws SQLException {
		int ordinal = cs.getInt(index);
		if (ordinal == 0 && cs.wasNull()) {
			return null;
		}
		return toEnum(ordinal);
	}

	public Object getValue(CallableStatement cs, String parameterName) throws SQLException {
		int ordinal = cs.getInt(parameterName);
		if (ordinal == 0 && cs.wasNull()) {
			return null;
		}
		return toEnum(ordinal);
	}

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

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

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

}
