Container.java

package com.tradecloud.domain.container;

import com.tradecloud.common.base.PersistenceBase;
import com.tradecloud.domain.comment.AddedComment;
import com.tradecloud.domain.comment.CommentType;
import com.tradecloud.domain.comment.Commentable;
import com.tradecloud.domain.event.ContainerEvent;
import com.tradecloud.domain.event.Event;
import com.tradecloud.domain.state.Stateful;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import java.math.BigDecimal;
import java.util.*;

@Entity
@Table(name = "container")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "containerSubType", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("CONTAINER")
public class Container extends PersistenceBase implements TypeOfContainer, Comparable<Container>, Stateful<ContainerState, ContainerEvent>,
        Commentable<AddedComment> {

    /**
     * Serial ID.
     */
    private static final long serialVersionUID = 1L;

    /**
     * The container type selected on the consignment.
     * Can have 1 or multiple container types on a consignment.
     * The drop-down list will contain all the container types
     */
    @XmlElement(name = "ContainerType")
    @ManyToOne
    @NotNull
    private ContainerType containerType;

    @XmlElement(name = "ShippingType")
    @ManyToOne
    private ShippingType shippingType;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    @Fetch(value = FetchMode.SUBSELECT)
    @XmlElementWrapper(name = "ContainerUsages")
    @XmlElement(name = "ContainerUsage")
    private List<ContainerUsage> containerUsages = new ArrayList<ContainerUsage>();

    /**
     * ContainerState INITIALISED after object initialisation. (This is an internal state only)
     */
    @XmlAttribute
    @Enumerated(EnumType.STRING)
    private ContainerState state = ContainerState.INITIALISED;

    /**
     * The purchase order events, used to keep track of the history.
     */
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @Fetch(value = FetchMode.SUBSELECT)
    @XmlElementWrapper(name = "ContainerEvents")
    @XmlElement(name = "ContainerEvent")
    @OrderBy("createDateTime")
    private List<ContainerEvent> events = new LinkedList<ContainerEvent>();

    /**
     * The quantity of the selected container type that will be used on the consignment.
     * <p>
     * Decimal values can be specified because of LCL container types and for future container allocation. Value must be larger than 0
     */
    @XmlAttribute
    @NotNull
    private BigDecimal quantity;

    @Embedded
    @XmlElement(name = "ContainerDates")
    private ContainerDates containerDates;

    @Column(name = "volumem3")
    private BigDecimal volumeM3 = BigDecimal.ZERO;

    @Column(name = "weightkg")
    private BigDecimal weightKG = BigDecimal.ZERO;

    @Column(name = "chargeableweightkg")
    private BigDecimal chargeableWeightKG = BigDecimal.ZERO;

    @XmlElement
    protected BigDecimal cartonsPerContainer = BigDecimal.ZERO;

    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "container_freetextcomments", joinColumns = {@JoinColumn(name = "container_id", unique = false)})
    @Column(name = "reason", unique = true)
    @org.hibernate.annotations.ForeignKey(name = "fk_container")
    @Fetch(value = FetchMode.SUBSELECT)
    @XmlElementWrapper(name = "FreeTextComments")
    @XmlElement(name = "FreeTextComment")
    private List<AddedComment> comments = new ArrayList<AddedComment>();


    private Date ataFdLspNotifiedDate;

    /**
     * For JPA only.
     */
    protected Container() {
    }

    /**
     * Constructor.
     *
     * @param containerType The container type
     */
    public Container(ContainerType containerType) {
        this.containerType = containerType;
    }

    public Container(ContainerType containerType, BigDecimal quantity) {
        this(containerType);
        this.quantity = quantity;
    }

    /**
     * Convenience method that adds the supplied containerUsage into the member collection of containersUsages.  The container reference is set onto
     * this containerUsage also.
     *
     * @param containerUsage The container usage to add to the collection
     */
    public void addContainerUsage(ContainerUsage containerUsage) {
        containerUsage.setContainer(this);
        containerUsages.add(containerUsage);
    }

    /**
     * Convenience method that removes the supplied containerUsage from the member collection of containerUsages.  The container reference on the
     * containerUsage is set to null and then the containerUsage is removed from the member collection.
     *
     * @param containerUsage The container usage to remove from the member collection
     */
    public void removeContainerUsage(ContainerUsage containerUsage) {
        containerUsage.setContainer(null);
        containerUsages.remove(containerUsage);
    }

    public List<ContainerUsage> getContainerUsages() {
        return containerUsages;
    }

    public List<ContainerUsage> getSortedContainerUsages() {
        if (containerUsages != null) {
            Collections.sort(containerUsages, new Comparator<ContainerUsage>() {

                @Override
                public int compare(ContainerUsage o1, ContainerUsage o2) {
                    return o1.getOrder().getNumber().compareTo(o2.getOrder().getNumber());
                }
            });
            return containerUsages;
        } else {
            return Collections.EMPTY_LIST;
        }
    }

    public void setContainerUsages(List<ContainerUsage> containerUsages) {
        this.containerUsages = containerUsages;
    }

    public ContainerType getContainerType() {
        return containerType;
    }

    public void setContainerType(ContainerType containerType) {
        this.containerType = containerType;
    }

    public BigDecimal getQuantity() {
        return quantity;
    }

    public void setQuantity(BigDecimal quantity) {
        this.quantity = quantity;
    }

    public ContainerState getState() {
        return state;
    }

    public void setState(ContainerState state) {
        this.state = state;
    }

    public List<ContainerEvent> getEvents() {
        return events;
    }

    @Override
    public boolean inNonEditableState() {
        return false;
    }

    public void setEvents(List<ContainerEvent> events) {
        this.events = events;
    }

    public ContainerDates getContainerDates() {
        if (containerDates == null) {
            // Necessary workaround, see http://blogs.sourceallies.com/2010/01/hibernate-embeddable-objects/
            containerDates = new ContainerDates();
        }
        return containerDates;
    }

    public void setContainerDates(ContainerDates containerDates) {
        if (containerDates != null) {
            this.containerDates = containerDates;
        } else {
            // Necessary workaround, see http://blogs.sourceallies.com/2010/01/hibernate-embeddable-objects/
            this.containerDates = new ContainerDates();
        }
        this.containerDates = containerDates;
    }

    /*
     * public BigDecimal getNumberAtDepot(CostedOrder costedOrder){ for (ContainerUsage containerUsage : containerUsages) {
     * if(containerUsage.getOrder().match(costedOrder)){ return containerUsage.getNumberAtClearingDepot(); } } return BigDecimal.ZERO; } public
     * BigDecimal getNumberAtPOD(CostedOrder costedOrder) { for (ContainerUsage containerUsage : containerUsages) { if
     * (containerUsage.getOrder().match(costedOrder)) { return containerUsage.getNumberAtPOD(); } } return BigDecimal.ZERO; }
     */

    public void copyFieldsFrom(Container container) {
        containerType = container.containerType;
        quantity = container.quantity;
        containerDates = container.containerDates;
    }

    @Override
    public int compareTo(Container other) {
        return containerType.getName().compareTo(other.getContainerType().getName());
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(containerType).append(quantity).toHashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (!(obj instanceof Container)) {
            return false;
        }
        Container other = (Container) obj;
        return new EqualsBuilder().append(containerType, other.containerType).append(quantity, other.quantity).isEquals();
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this).append(containerType).append(state).append(quantity).append(containerDates).toString();
    }

    public BigDecimal getVolumeM3() {
        return volumeM3;
    }

    public void setVolumeM3(BigDecimal volumeM3) {
        this.volumeM3 = volumeM3;
    }

    public BigDecimal getWeightKG() {
        return weightKG;
    }

    public void setWeightKG(BigDecimal weightKG) {
        this.weightKG = weightKG;
    }

    public BigDecimal getChargeableWeightKG() {
        return chargeableWeightKG;
    }

    public void setChargeableWeightKG(BigDecimal chargeableWeightKG) {
        this.chargeableWeightKG = chargeableWeightKG;
    }

    public BigDecimal getCartonsPerContainer() {
        if (cartonsPerContainer == null)
            cartonsPerContainer = BigDecimal.ZERO;
        return cartonsPerContainer;
    }

    public void setCartonsPerContainer(BigDecimal cartonsPerContainer) {
        this.cartonsPerContainer = cartonsPerContainer;
    }

    @Override
    public ContainerEvent getLastEvent() {
        return Event.getLastEvent(events);
    }

    @Override
    public List<AddedComment> getComments() {
        return comments;
    }

    @Override
    public void setComments(List<AddedComment> comments) {
        this.comments = comments;
    }

    @Override
    public CommentType getCommentType() {
        return CommentType.CONTAINER;
    }

    public boolean isShipmentContainer() {
        return false;
    }

    public Date getAtaFdLspNotifiedDate() {
        return ataFdLspNotifiedDate;
    }

    public void setAtaFdLspNotifiedDate(Date ataFdLspNotifiedDate) {
        this.ataFdLspNotifiedDate = ataFdLspNotifiedDate;
    }

    public ShippingType getShippingType() {
        return shippingType;
    }

    public void setShippingType(ShippingType shippingType) {
        this.shippingType = shippingType;
    }
}