/*
 * This file is part of Nuts Framework.
 * Copyright(C) 2009-2012 Nuts Develop Team.
 *
 * Nuts Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License any later version.
 *
 * Nuts Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Nuts Framework. If not, see <http://www.gnu.org/licenses/>.
 */
package nuts.core.bind;

import nuts.core.bean.BeanHandler;
import nuts.core.bean.Beans;
import nuts.core.castor.Castor;
import nuts.core.castor.Castors;
import nuts.core.lang.Arrays;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public abstract class AbstractBinder {
	private Castors castors = Castors.me();

	private boolean ignoreNullProperty = true;

	private Set<String> excludePropertyNames;
	
	private Set<Class<?>> excludePropertyTypes;

	private Map<Type, PropertyFilter> propertyFilters = new HashMap<Type, PropertyFilter>();

	/**
	 * Constructor 
	 */
	public AbstractBinder() {
		getExcludePropertyTypes().addAll(Arrays.asList(Beans.RESERVED_PROPERTY_TYPES));
	}

	public boolean isIgnoreNullProperty() {
		return ignoreNullProperty;
	}

	public void setIgnoreNullProperty(boolean ignoreNullProperty) {
		this.ignoreNullProperty = ignoreNullProperty;
	}

	public Castors getCastors() {
		return castors;
	}

	public void setCastors(Castors castors) {
		this.castors = castors;
	}

	//----------------------------------------------------------
	public Set<String> getExcludePropertyNames() {
		if (excludePropertyNames == null) {
			excludePropertyNames = new HashSet<String>();
		}
		return excludePropertyNames;
	}
	public void addExcludeProperty(String exclude) {
		getExcludePropertyNames().add(exclude);
	}
	public void removeExcludeProperty(String exclude) {
		getExcludePropertyNames().remove(exclude);
	}

	public Set<Class<?>> getExcludePropertyTypes() {
		if (excludePropertyTypes == null) {
			excludePropertyTypes = new HashSet<Class<?>>();
		}
		return excludePropertyTypes;
	}
	public void addExcludeProperty(Class<?> exclude) {
		getExcludePropertyTypes().add(exclude);
	}
	public void removeExcludeProperty(Class<?> exclude) {
		getExcludePropertyTypes().remove(exclude);
	}

	//----------------------------------------------------------
	public Map<Type, PropertyFilter> getPropertyFilters() {
		return propertyFilters;
	}
	@SuppressWarnings("unchecked")
	public <T> PropertyFilter<T> getPropertyFilter(Type type) {
		return getPropertyFilters().get(type);
	}
	public void registerPropertyFilter(Type type, PropertyFilter propertyFilter) {
		getPropertyFilters().put(type, propertyFilter);
	}
	public void removePropertyFilter(Type type) {
		getPropertyFilters().remove(type);
	}
	public void clearPropertyFilters() {
		getPropertyFilters().clear();
	}

	//----------------------------------------------------------
	protected Beans getBeans() {
		return castors.getBeans();
	}

	protected <T> BeanHandler<T> getBeanHandler(Type type) {
		return getBeans().getBeanHandler(type);
	}
	
	protected <S, T> Castor<S, T> getCastor(Type fromType, Type toType) {
		return castors.getCastor(fromType, toType);
	}
	
	@SuppressWarnings("unchecked")
	protected <T> T convertValue(Object value, Type toType) {
		if (toType == null) {
			return null;
		}
		return (T)castors.cast(value, toType);
	}
	
	protected boolean isExcludeProperty(String name) {
		return excludePropertyNames != null && excludePropertyNames.contains(name);
	}
	
	protected boolean isExcludeProperty(Class type) {
		return excludePropertyTypes != null && excludePropertyTypes.contains(type);
	}
}
