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

// Package
package gov.va.med.fw.model;

// Java Classes
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

// Library Classes
import org.apache.commons.lang.builder.ToStringBuilder;

// Framework Classes
import gov.va.med.fw.security.Principal;
import gov.va.med.fw.model.lookup.TransactionType;

/**
 * An abstract class that can be used as a base class for modifiable (versioned) entity classes.
 *
 * @author Vu Le
 * @version 1.0
 */
public abstract class AbstractVersionedEntity extends AbstractEntity
{
    private static final long serialVersionUID = -7758974447945480434L;

    // The principal that created the object.
    private Principal createdBy = null;

    // The date/time when the object was created.
    private Date createdOn = null;

    // The principal that modified the object last.
    private Principal modifiedBy = null;

    // The date/time when the object was last modified.
    private Date modifiedOn = null;

    // The version of the object's data.
    private Integer version = null;

    // Transaction type Insert/delete/update
    private TransactionType transactionType = null;

    /**
     * The previous version of this versioned entity
     */
    private AbstractVersionedEntity previousVersion;

    /**
     * id of the history table
     */
    private Serializable historyId;


    /**
     * A default constructor
     */
    protected AbstractVersionedEntity()
    {
        super();
    }

    /**
     * A constructor initialized with the specific values
     *
     * @param createdOn The date/time when the object was created.
     * @param modifiedOn The date/time when the object was last modified.
     * @param version The version of the object's data.
     */
    public AbstractVersionedEntity(Date createdOn, Date modifiedOn,
        Integer version)
    {
        super();
        this.createdOn = createdOn;
        this.modifiedOn = modifiedOn;
        this.version = version;
    }

    /**
     * Returns the principal that created the object.
     *
     * @return The principal that created the object.
     */
    public Principal getCreatedBy()
    {
        return this.createdBy;
    }

    /**
     * Returns the date/time when the object was created.
     *
     * @return The date/time when the object was created.
     */
    public Date getCreatedOn()
    {
        return this.createdOn;
    }

    /**
     * Sets the date/time when the object was created.
     *
     * @param createdOn The date/time when the object was created.
     */
    private void setCreatedOn(Date createdOn)
    {
        this.createdOn = createdOn;
    }

    /**
     * Returns the principal that modified the object last.
     *
     * @return The principal that modified the object last.
     */
    public Principal getModifiedBy()
    {
        return this.modifiedBy;
    }

    /**
     * Returns the date/time when the object was last modified.
     *
     * @return The date/time when the object was last modified.
     */
    public Date getModifiedOn()
    {
        return this.modifiedOn;
    }

    /**
     * Sets the date/time when the object was last modified.
     * <p/>
     * NOTE: This method should not be called directly since Hibernate will automatically call it when loading an object.
     * However, it is public because there are certain cases when we want to build an entity manually (e.g. Building a
     * Person with only PSIM traits for Identity Traits History).
     *
     * @param modifiedOn The date/time when the object was last modified.
     */
    public void setModifiedOn(Date modifiedOn)
    {
        this.modifiedOn = modifiedOn;
    }

    /**
     * Returns the version of the object's data.
     *
     * @return The version of the object's data.
     */
    public Integer getVersion()
    {
        return this.version;
    }

    /**
     * Sets the version of the object's data.
     *
     * @param version The version of the object's data.
     */
    private void setVersion(Integer version)
    {
        this.version = version;
    }

    /**
     * @param createdBy The createdBy to set.
     */
    public void setCreatedBy(Principal createdBy)
    {
        this.createdBy = createdBy;
    }

    /**
     * @param modifiedBy The modifiedBy to set.
     */
    public void setModifiedBy(Principal modifiedBy)
    {
        this.modifiedBy = modifiedBy;
    }

    /**
     * @return Returns the previousVersion.
     */
    public AbstractVersionedEntity getPreviousVersion()
    {
        return previousVersion;
    }

    /**
     * @param previousVersion The previousVersion to set.
     */
    public void setPreviousVersion(AbstractVersionedEntity previousVersion)
    {
        this.previousVersion = previousVersion;
    }

    /**
     * get  Transaction type Insert/Update/Delete
     *
     * @return the transaction type
     */
    public TransactionType getTransactionType()
    {
        return transactionType;
    }

    /**
     * @param transactionType the transaction type
     */
    private void setTransactionType(TransactionType transactionType)
    {
        this.transactionType = transactionType;
    }


    public Serializable getHistoryId()
    {
        return historyId;
    }

    private void setHistoryId(Serializable historyId)
    {
        this.historyId = historyId;
    }

    public Boolean isDeleted()
    {
        return (transactionType == null ?
            Boolean.FALSE : transactionType.isDeleted());
    }

    /**
     * Returns an ordered iterator of all loaded versions where the first element is current object.
     * @return the iterator of versions
     */
    public Iterator versions()
    {
        List orderedVersions = new ArrayList();
        AbstractVersionedEntity current = this;
        while (current != null)
        {
            orderedVersions.add(current);
            current = current.getPreviousVersion();
        }
        return orderedVersions.iterator();
    }

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

        this.createdBy = null;
        this.modifiedBy = null;
        this.modifiedOn = null;
        
        this.setVersion( null );
        this.setTransactionType( null );
        this.setHistoryId( null );
        this.setCreatedOn( null );
    }

    /**
     * @see gov.va.med.fw.model.AbstractEntity#buildToString(org.apache.commons.lang.builder.ToStringBuilder)
     */
    protected void buildToString(ToStringBuilder builder)
    {
        builder.append("createdBy", this.createdBy);
        builder.append("createdOn", this.createdOn);
        builder.append("modifiedBy", this.modifiedBy);
		builder.append("modifiedOn", this.modifiedOn);
		builder.append("version", this.version);
		builder.append("historyId", this.historyId);
	}
}