/********************************************************************
 * Copyright © 2005 VHA. All rights reserved
 ********************************************************************/

package gov.va.med.fw.io;

import org.apache.commons.lang.Validate;

import gov.va.med.fw.service.AbstractComponent;
import gov.va.med.fw.util.InvalidConfigurationException;
import gov.va.med.fw.util.StringUtils;

/**
 * Contains metadata about a field in a File, either for input or output.
 *
 * Created Feb 15, 2006 2:13:14 PM
 *
 * @author DNS   BOHMEG
 */
public class FileFieldMetaData extends AbstractComponent {
	private String name;

	private int length;

	private int maxLength;

	private int minLength;

	private int startPosition;

	private int endPosition;

	private boolean required;

	private FieldTransformer transformer;


	/**
	 * @return Returns the endPosition.
	 */
	public int getEndPosition() {
		return endPosition;
	}

	/**
	 * @param endPosition
	 *            The endPosition to set.
	 */
	public void setEndPosition(int endPosition) {
		this.endPosition = endPosition;
	}

	/**
	 * @return Returns the length.
	 */
	public int getLength() {
		return length;
	}

	/**
	 * @param length
	 *            The length to set.
	 */
	public void setLength(int length) {
		this.length = length;
	}

	/**
	 * @return Returns the name.
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name
	 *            The name to set.
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * @return Returns the required.
	 */
	public boolean isRequired() {
		return required;
	}

	/**
	 * @param required
	 *            The required to set.
	 */
	public void setRequired(boolean required) {
		this.required = required;
	}

	/**
	 * @return Returns the startPosition.
	 */
	public int getStartPosition() {
		return startPosition;
	}

	/**
	 * @param startPosition
	 *            The startPosition to set.
	 */
	public void setStartPosition(int startPosition) {
		this.startPosition = startPosition;
	}

	public int getFixedFieldWidth() {
		return getEndPosition() != 0 ? (getEndPosition() - getStartPosition()) + 1 : 0;
	}

	public String validate(String rawValue) {
		String strValue = rawValue.trim();
		if (isRequired() && StringUtils.isEmpty(strValue))
			throw new IllegalStateException(getName() + " is required");
		if (getLength() > 0 && !StringUtils.isEmpty(strValue)
				&& strValue.length() != getLength())
			throw new IllegalStateException(getName() + " does not equal size "
					+ getLength());
		if (!StringUtils.isEmpty(strValue) && getMaxLength() > 0
				&& strValue.length() > getMaxLength())
			throw new IllegalStateException(getName() + " must have max size "
					+ getMaxLength());
		if (!StringUtils.isEmpty(strValue) && getMinLength() > 0
				&& strValue.length() < getMinLength())
			throw new IllegalStateException(getName() + " must have min size "
					+ getMinLength());

		return strValue;
	}

	public Object transform(Object rawValue) {
		Object transformedValue = rawValue;
		if(transformer != null) {
			try {
				transformedValue = transformer.transformData(name, rawValue);
			} catch(Exception e) {
				if (logger.isErrorEnabled())
	            {
	                logger.error("Unable to transform data: " + rawValue);
	            }
				RuntimeException e1 = new IllegalArgumentException("Unable to transform data: ");
				e1.initCause(e);
				throw e1;
			}
		}
		return transformedValue;
	}

	/**
	 * @return Returns the maxLength.
	 */
	public int getMaxLength() {
		return maxLength;
	}

	/**
	 * @param maxLength
	 *            The maxLength to set.
	 */
	public void setMaxLength(int maxLength) {
		this.maxLength = maxLength;
	}

	public void afterPropertiesSet() {
		Validate.notNull(name, "A FileFieldMetaData needs a name");
		verifySettings();
	}

	protected void verifySettings() {
		if (getLength() < 0 || getMinLength() < 0 || getMaxLength() < 0
				|| getStartPosition() < 0 || getEndPosition() < 0)
			throw new InvalidConfigurationException(
					"Can not negative values for properties of FileFieldMetaData");
		if (getLength() > 0 && getMaxLength() > 0)
			throw new InvalidConfigurationException(
					"Can not have a fixed length and max length at the same time");
		if (getLength() > 0 && getMinLength() > 0)
			throw new InvalidConfigurationException(
					"Can not have a fixed length and min length at the same time");
		if (getStartPosition() > 0 && getEndPosition() == 0
				|| getStartPosition() == 0 && getEndPosition() > 0)
			throw new InvalidConfigurationException(
					"Must have positive values for start and end position");
	}



	/**
	 * @return Returns the minLength.
	 */
	public int getMinLength() {
		return minLength;
	}

	/**
	 * @param minLength
	 *            The minLength to set.
	 */
	public void setMinLength(int minLength) {
		this.minLength = minLength;
	}

	protected boolean isFixedWidthFormat() {
		return getStartPosition() > 0 || getEndPosition() > 0;
	}

	/**
	 * @return Returns the transformer.
	 */
	public FieldTransformer getTransformer() {
		return transformer;
	}

	/**
	 * @param transformer The transformer to set.
	 */
	public void setTransformer(FieldTransformer transformer) {
		this.transformer = transformer;
	}
}
