/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.esr.common.builder.entity;

// Java Classes
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

// Library Classes

// Framework Classes
import gov.va.med.fw.model.lookup.AbstractLookup;
import gov.va.med.fw.util.builder.AbstractBuilder;
import gov.va.med.fw.util.builder.Builder;
import gov.va.med.fw.util.builder.BuilderException;

// Common Classes
import gov.va.med.esr.common.builder.datatype.metadata.AbstractDataTypeMetaData;
import gov.va.med.esr.common.builder.datatype.metadata.SimpleTypeMetaData;
import gov.va.med.esr.common.builder.datatype.metadata.TS;
import gov.va.med.esr.common.infra.ImpreciseDate;
import gov.va.med.esr.common.infra.TriState;
import gov.va.med.esr.common.model.lookup.VAFacility;

// Messaging Classes

/**
 * @author Martin Francisco
 */
public abstract class EntityBuilder extends AbstractBuilder implements
		EntityBuilderStrategy {
    
    private static final long serialVersionUID = -1370346746640850300L;
	private Builder booleanBuilder;

	private Builder dateBuilder;

	private Builder impreciseDateBuilder;

	private Builder vaFacilityBuilder;

	private Builder indicatorBuilder;
	
	private Builder permanentIndicatorBuilder;

	private EntityBuilderStrategy strategy = null;
	
	/**
	 * A default constructor 
	 */
	public EntityBuilder() {
		super();
	}

	/**
	 * @see gov.va.med.fw.service.AbstractComponent#afterPropertiesSet()
	 */
	public void afterPropertiesSet() throws Exception {
		super.afterPropertiesSet();
		if( this.strategy == null ) {
			this.strategy = new NonNullEntityBuilderStrategy();
		}
	}

	public EntityBuilderStrategy getStrategy() {
		return strategy;
	}

	public void setStrategy(EntityBuilderStrategy strategy) {
		this.strategy = strategy;
	}

	public Builder getBooleanBuilder() {
		return this.booleanBuilder;
	}

	public void setBooleanBuilder(Builder booleanBuilder) {
		this.booleanBuilder = booleanBuilder;
	}

	public Builder getDateBuilder() {
		return this.dateBuilder;
	}

	public void setDateBuilder(Builder dateBuilder) {
		this.dateBuilder = dateBuilder;
	}

	public Builder getImpreciseDateBuilder() {
		return this.impreciseDateBuilder;
	}

	public void setImpreciseDateBuilder(Builder impreciseDateBuilder) {
		this.impreciseDateBuilder = impreciseDateBuilder;
	}

	/**
	 * @return Returns the indicatorBuilder.
	 */
	public Builder getIndicatorBuilder() {
		return indicatorBuilder;
	}

	/**
	 * @param indicatorBuilder
	 *           The indicatorBuilder to set.
	 */
	public void setIndicatorBuilder(Builder indicatorBuilder) {
		this.indicatorBuilder = indicatorBuilder;
	}

	/**
	 * @return Returns the permanentIndicatorBuilder.
	 */
	public Builder gePermanentIndicatorBuilder() {
		return permanentIndicatorBuilder;
	}

	/**
	 * @param indicatorBuilder
	 *           The permanentIndicatorBuilder to set.
	 */
	public void setPermanentIndicatorBuilder(Builder permanentIndicatorBuilder) {
		this.permanentIndicatorBuilder = permanentIndicatorBuilder;
	}
	
	public Builder getVaFacilityBuilder() {
		return this.vaFacilityBuilder;
	}

	public void setVaFacilityBuilder(Builder vaFacilityBuilder) {
		this.vaFacilityBuilder = vaFacilityBuilder;
	}

	/**
	 * @see gov.va.med.esr.common.builder.entity.EntityBuilderStrategy#shouldDelete(gov.va.med.esr.common.builder.datatype.metadata.AbstractDataTypeMetaData)
	 */
	public boolean shouldDelete(AbstractDataTypeMetaData data) {
		return strategy.shouldDelete( data );
	}

	/**
	 * @see gov.va.med.esr.common.builder.entity.EntityBuilderStrategy#shouldDelete(java.lang.String)
	 */
	public boolean shouldDelete(String data) {
		return strategy.shouldDelete( data );
	}

	/**
	 * @see gov.va.med.esr.common.builder.entity.EntityBuilderStrategy#shouldKeep(gov.va.med.esr.common.builder.datatype.metadata.SimpleTypeMetaData)
	 */
	public boolean shouldKeep(SimpleTypeMetaData data) {
		return strategy.shouldKeep( data );
	}

	/**
	 * @see gov.va.med.esr.common.builder.entity.EntityBuilderStrategy#shouldKeep(java.lang.String)
	 */
	public boolean shouldKeep(String data) {
		return strategy.shouldKeep( data );
	}

	/**
	 * @see gov.va.med.esr.common.builder.entity.EntityBuilderStrategy#shouldKeep(java.lang.Object)
	 */
	public boolean shouldKeep(Object data) {
		return strategy.shouldKeep( data );
	}

	protected BigDecimal build(BigDecimal input, String value)
			throws BuilderException {
		return this.shouldDelete(value) ? null : ( this.shouldKeep(value) ? input
				: value != null ? new BigDecimal(value) : null );
	}

	protected Boolean build(Boolean input, String value) throws BuilderException {
		return this.shouldDelete(value) ? null : (this.shouldKeep(value) ? input
				: (Boolean) this.booleanBuilder.build(value));
	}

	protected Date build(Date input, String value) throws BuilderException {
		return this.shouldDelete(value) ? null : (this.shouldKeep(value) ? input
				: (Date) this.dateBuilder.build(value));
	}

	protected ImpreciseDate build(ImpreciseDate input, String value)
			throws BuilderException {
		return (this.shouldDelete(value) || "0000".equals(value) || "00000000"
				.equals(value)) ? null : (this.shouldKeep(value) ? input
				: (ImpreciseDate) this.impreciseDateBuilder.build(value));
	}

	protected ImpreciseDate build(ImpreciseDate input, SimpleTypeMetaData value)
			throws BuilderException {
		return this.shouldDelete(value) ? null : (this.shouldKeep(value) ? input
				: this.build(input, this.getValue(value)));
	}

	protected ImpreciseDate build(ImpreciseDate input, TS value)
			throws BuilderException {
		return this.shouldDelete(value) ? null : this.build(input, value
				.getDateTime());
	}

	protected int build(int input, String value) throws BuilderException {
		Integer temp = this.build(new Integer(input), value);
		return (temp == null) ? input : temp.intValue();
	}

	protected Integer build(Integer input, String value) throws BuilderException {
		return this.shouldDelete(value) ? null : (this.shouldKeep(value) ? input
				: value != null ? new Integer(value) : null);
	}

	protected AbstractLookup build(Builder builder, AbstractLookup input,
			String code) throws BuilderException {
		return this.shouldDelete(code) ? null : (this.shouldKeep(code) ? input
				: (AbstractLookup) builder.build(code));
	}

	protected AbstractLookup build(Builder builder, AbstractLookup input,
			SimpleTypeMetaData code) throws BuilderException {
		return this.shouldDelete(code) ? null : (this.shouldKeep(code) ? input
				: (AbstractLookup) builder.build(this.getValue(code)));
	}

	protected String build(String input, String value) throws BuilderException {
		return this.shouldDelete(value) ? null : (this.shouldKeep(value) ? input
				: value);
	}

	protected String build(String input, SimpleTypeMetaData value)
			throws BuilderException {
		return this.shouldDelete(value) ? null : (this.shouldKeep(value) ? input
				: this.getValue(value));
	}

	protected TriState build(TriState input, String value)
			throws BuilderException {
		if (this.shouldDelete(value)) {
			return null;
		}
		else if (this.shouldKeep(value)) {
			return input;
		}
		else if ("T".equals(value)) {
			return TriState.TRUE;
		}
		else if ("F".equals(value)) {
			return TriState.FALSE;
		}
		else if ("U".equals(value)) {
			return TriState.UNKNOWN;
		}
		else {
			throw new BuilderException("invalid tristate value");
		}
	}

	protected VAFacility build(VAFacility input, String vaFacilityStationNumber)
			throws BuilderException {
		return this.shouldDelete(vaFacilityStationNumber) ? null : (this
				.shouldKeep(vaFacilityStationNumber) ? input
				: (VAFacility) this.vaFacilityBuilder
						.build(vaFacilityStationNumber));
	}

	protected VAFacility build(VAFacility input, SimpleTypeMetaData code)
			throws BuilderException {
		return this.shouldDelete(code) ? null : (this.shouldKeep(code) ? input
				: (VAFacility) this.vaFacilityBuilder.build(this.getValue(code)));
	}

	protected Integer buildYear(Integer input, String value)
			throws BuilderException {
		return this.shouldDelete(value) ? null : (this.shouldKeep(value) ? input
				: new Integer(value.substring(0, 4)));
	}

	protected Set getOfType(Set set, Class clazz) {
		Set result = new HashSet();
		for (Iterator i = set.iterator(); i.hasNext();) {
			Object current = i.next();
			if (clazz.isInstance(current)) {
				result.add(current);
			}
		}
		return result;
	}

	protected String getValue(SimpleTypeMetaData value) {
		return (value == null) ? null : value.getValue();
	}

	protected boolean isEmpty(Collection coll) {
		return ((coll == null) || coll.isEmpty());
	}

	protected boolean isEmpty(Map map) {
		return ((map == null) || map.isEmpty());
	}

}