package gov.va.med.fw.model.lookup;

// Java Classes
import java.lang.reflect.Method;
import java.util.Date;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;

import gov.va.med.fw.model.AbstractEntity;
import gov.va.med.fw.util.InvalidConfigurationException;

/**
 * @author DNS   LEV
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
public abstract class AbstractLookup extends AbstractEntity implements Lookup {

	private static final long serialVersionUID = 8255942734754635021L;

	private Long identifier = null;
	private String code;
	private String name;
	private String description;
	private Date startDate = null;
	private Date endDate = null;

	/**
	 * Default constructor.
	 */
	public AbstractLookup() {
		super();
	}

	/**
	 * Returns the unique identifier for this object.
	 * 
	 * @return The unique identifier for this object.
	 */
	public Long getIdentifier() {
		return this.identifier;
	}

	/**
	 * Sets the unique identifier for this object.
	 * 
	 * @param identifier
	 *            The unique identifier for this object.
	 */
	private void setIdentifier(Long identifier) {
		this.identifier = identifier;
	}

	/**
	 * Returns the unique business code for this object.
	 * 
	 * @return The unique business code for this object.
	 */
	public String getCode() {
		return this.code;
	}

	@SuppressWarnings("unchecked")
	public AbstractCode getCodeObject() {
		String className = getClass().getName() + "$Code";
		try {
			Class<? extends AbstractCode> clazz = (Class<? extends AbstractCode>) Class
					.forName(className);
			Method m = clazz.getMethod("getByCode", new Class[] { String.class });
			return (AbstractCode) m.invoke(this, new Object[] { code });
		} catch (ClassNotFoundException e) {
			throw new InvalidConfigurationException(className
					+ " is not defined in the concrete lookup class");
		} catch (NoSuchMethodException e) {
			throw new InvalidConfigurationException(className
					+ " does not define getByCode(String) method");
		} catch (Exception e) {
			throw new InvalidConfigurationException(className
					+ " .getByCode(String) method can not be invoked");
		}
	}

	/**
	 * Sets the unique business code for this object.
	 * 
	 * @param code
	 *            The unique business code for this object.
	 */
	public void setCode(String code) {
		this.code = code;
	}

	/**
	 * Returns the unique business description for this object.
	 * 
	 * @return The unique business description for this object.
	 */
	public String getDescription() {
		return this.description;
	}

	/**
	 * Sets the unique business description for this object.
	 * 
	 * @param description
	 *            The unique business description for this object.
	 */
	public void setDescription(String description) {
		this.description = description;
	}

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

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

	/**
	 * Returns the start date when this object becomes valid.
	 * 
	 * @return The start date when this object becomes valid.
	 */
	public Date getStartDate() {
		return this.startDate;
	}

	/**
	 * Sets the start date when this object becomes valid.
	 * 
	 * @param startDate
	 *            The start date when this object becomes valid.
	 */
	public void setStartDate(Date startDate) {
		this.startDate = startDate;
	}

	/**
	 * Returns the end date when this object becomes invalid.
	 * 
	 * @return The end date when this object becomes invalid.
	 */
	public Date getEndDate() {
		return this.endDate;
	}

	/**
	 * Sets the end date when this object becomes invalid.
	 * 
	 * @param endDate
	 *            The end date when this object becomes invalid.
	 */
	public void setEndDate(Date endDate) {
		this.endDate = endDate;
	}

	/**
	 * @see gov.va.med.fw.model.AbstractEntity#hashCode()
	 */
	public int hashCode() {
		return new HashCodeBuilder().append(this.identifier).toHashCode();
	}

	/**
	 * @see gov.va.med.fw.model.AbstractEntity#equals(java.lang.Object)
	 */
	public boolean equals(Object o) {
		return ((o instanceof AbstractLookup) && this.equals((AbstractLookup) o));
	}

	/**
	 * @see gov.va.med.fw.model.AbstractEntity#buildToString(org.apache.commons.lang.builder.ToStringBuilder)
	 */
	protected void buildToString(ToStringBuilder builder) {
		builder.append("identifier", this.identifier).append("code", this.code).append("startDate",
				this.startDate).append("endDate", this.endDate).append("name", this.name).append(
				"description", this.description);
	}

	/**
	 * @see java.lang.Object#finalize()
	 */
	protected void finalize() throws Throwable {
		super.finalize();

		this.setIdentifier(null);
		this.setCode(null);
		this.setStartDate(null);
		this.setEndDate(null);
		this.setDescription(null);
		this.setName(null);
	}

	/**
	 * @param o
	 * @return
	 */
	private boolean equals(AbstractLookup o) {
		return new EqualsBuilder().append(this.getClass(), o.getClass()).append(this.identifier,
				o.identifier).append(this.code, o.code).isEquals();
	}

}