/*******************************************************************************
 * Copyright (c) 2010 Robert "Unlogic" Olofsson (unlogic@unlogic.se).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v3
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-3.0-standalone.html
 ******************************************************************************/
package se.unlogic.standardutils.populators;

import se.unlogic.standardutils.dao.BeanResultSetPopulator;
import se.unlogic.standardutils.dao.querys.PreparedStatementQuery;
import se.unlogic.standardutils.enums.EnumUtils;
import se.unlogic.standardutils.reflection.ReflectionUtils;
import se.unlogic.standardutils.string.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;

public class EnumPopulator<EnumType extends Enum<EnumType>> extends BaseStringPopulator<EnumType> implements BeanResultSetPopulator<EnumType>, BeanStringPopulator<EnumType>, QueryParameterPopulator<EnumType> {

	protected Class<EnumType> classType;
	protected String fieldName;

	public EnumPopulator(Class<EnumType> classType) {
		super();

		checkClass(classType);
		fieldName = classType.getSimpleName();
	}

	public EnumPopulator(Class<EnumType> classType, String fieldName) {

		checkClass(classType);

		if (StringUtils.isEmpty(fieldName)) {
			throw new NullPointerException("fieldName can not be null or empty!");
		} else {
			this.fieldName = fieldName;
		}
	}

	private void checkClass(Class<EnumType> classType) {

		if (classType == null) {
			throw new NullPointerException("Classtype can not be null!");
		} else {
			this.classType = classType;
		}
	}

	public EnumType populate(ResultSet rs) throws SQLException {

		return EnumUtils.toEnum(classType, rs.getString(1));
	}

	public EnumType getValue(String value) {

		return EnumUtils.toEnum(classType, value);
	}

	@Override
	public boolean validateDefaultFormat(String value) {

		return EnumUtils.isEnum(classType, value);
	}

	public Class<? extends EnumType> getType() {

		return classType;
	}

	public void populate(PreparedStatementQuery query, int paramIndex, Object bean) throws SQLException {

		if(bean != null){
			
			query.setString(paramIndex, bean.toString());
			
		}else{
			
			query.setString(paramIndex, null);
		}
		
	}

	public static <Type extends Enum<Type>> EnumPopulator<Type> getGenericInstance(Class<Type> type) {

		return new EnumPopulator<Type>(type);
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static EnumPopulator<?> getInstanceFromField(Field field){

		Enum enumInstance = EnumUtils.getInstanceFromField(field);

		return EnumPopulator.getGenericInstance(enumInstance.getClass());
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static EnumPopulator<?> getInstanceFromListField(Field field){

		Object[] enumValues = ((Class<?>)ReflectionUtils.getGenericType(field)).getEnumConstants();

		Enum enumInstance = (Enum) enumValues[0];

		return EnumPopulator.getGenericInstance(enumInstance.getClass());
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static EnumPopulator<?> getInstanceFromMethod(Method method){

		Object[] enumValues = method.getParameterTypes()[0].getEnumConstants();

		Enum enumInstance = (Enum) enumValues[0];

		return EnumPopulator.getGenericInstance(enumInstance.getClass());
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static BeanStringPopulator<?> getInstanceFromListMethod(Method method) {

		Object[] enumValues = ((Class<?>)ReflectionUtils.getGenericType(method)).getEnumConstants();

		Enum enumInstance = (Enum) enumValues[0];

		return EnumPopulator.getGenericInstance(enumInstance.getClass());
	}
}
