/**
 * License Agreement.
 *
 *  JBoss RichFaces - Ajax4jsf Component Library
 *
 * Copyright (C) 2007  Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */
package org.richfaces.realworld.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import org.hibernate.validator.Length;
import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.NotNull;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Role;

/**
 * Class for representing Album Entity EJB3 Entity Bean
 *
 * @author Andrey Markhel
 */
@Entity
@Name("album")
@Table(name = "albums")
@Role(name = "selectedAlbum", scope = ScopeType.CONVERSATION)
public class Album implements Serializable {

    private static final long serialVersionUID = -7042878411608396483L;

    @Id
    @GeneratedValue
    @Column(name = "ALBUM_ID")
    private Long id = null;

    @Column(length = 255, nullable = false)
    @NotNull
    @NotEmpty
    @Length(min = 3, max = 50)
	//TODO nick - add maxLength validation here and everywhere?
    private String name;

    @Column(length = 1024)
    private String description;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "album")
    @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)
    private List<Image> images = new ArrayList<Image>();

    @NotNull
    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "PARENT_SHELF_ID", nullable = false)
    @org.hibernate.annotations.ForeignKey(name = "FK_SHELF_PARENT_ID")
    private Shelf shelf;

    @Temporal(TemporalType.TIMESTAMP)
    private Date created;

    @Transient
    private List<Image> unvisitedImages = new ArrayList<Image>();

    @OneToOne(cascade = CascadeType.ALL, optional = true)
    private Image coveringImage;

    // ********************** Accessor Methods ********************** //


    public Shelf getShelf() {
        return shelf;
    }

    public void setShelf(Shelf parent) {
        this.shelf = parent;
    }

    /**
     * Getter for property id
     *
     * @return id of album
     */
    public Long getId() {
        return id;
    }

    /**
     * Getter for property name
     *
     * @return name of album
     */
    public String getName() {
        return name;
    }

    /**
     * Setter for property name
     *
     * @param name -
     *             name of album
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Getter for property description
     *
     * @return description of album
     */
    public String getDescription() {
        return description;
    }

    /**
     * Setter for property description
     *
     * @param description -
     *                    description of album
     */
    public void setDescription(String description) {
        this.description = description;
    }

    // ********************** Business Methods ********************** //

    /**
     * This method add image to collection of images of current album
     *
     * @param image -
     *              image to add
     */
    public void addImage(Image image) {
        if (image == null) {
            throw new IllegalArgumentException("Null image!");
        }
        if (image.getAlbum() != null && !this.equals(image.getAlbum())) {
			//TODO nick - use removeImage()
        	image.getAlbum().removeImage(image);
        }
        image.setAlbum(this);
        images.add(image);
    }

    /**
     * This method remove image from collection of images of album
     *
     * @param image -
     *              image to remove
     */
    public void removeImage(Image image) {
        if (image == null) {
            throw new IllegalArgumentException("Null image");
        }
		//TODO nick - check if image is in the current album
        if(image.getAlbum().equals(this)){
        	image.setAlbum(null);
            images.remove(image);
        }else{
        	throw new IllegalArgumentException("This album not contain this image!");
        }
    }

    /**
     * This method return count of images of current album
     *
     * @return count of images of this album
     */
    public int getCountImages() {
        return this.getImages() != null ? this.getImages().size() : 0;
    }

    public User getOwner() {
        return getShelf().getOwner();
    }

    public List<Image> getImages() {
        return images;
    }

    public int getIndex(Image image) {
		//TODO nick - use indexOf
		//TODO nick - check images == null?
        return this.images.indexOf(image);
    }

    public Image getCoveringImage() {
        if (coveringImage != null) {
            return coveringImage;
        }
        if (images != null && images.size() > 0) {
			//TODO nick - i suggest we use random images
            coveringImage = images.get(0);
            return images.get(0);
        } else {
            return null;
        }
    }

    public boolean isEmpty() {
        return images == null || images.size() == 0;
    }

    /**
     * @return the created
     */
    public Date getCreated() {
        return created;
    }

    /**
     * @param created the created to set
     */
    public void setCreated(Date created) {
        this.created = created;
    }

    public Long getCountUnvisitedImages() {
        return new Long(unvisitedImages.size());
    }


    public List<Image> getUnvisitedImages() {
        return unvisitedImages;
    }

    public void setUnvisitedImages(List<Image> unvisitedImages) {
        this.unvisitedImages = unvisitedImages;
    }

    public void visitImage(Image image) {
        if (unvisitedImages.contains(image)) {
            unvisitedImages.remove(image);
        }
    }

    public void setCoveringImage(Image coveringImage) {
        this.coveringImage = coveringImage;
    }

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Album album = (Album) o;

        if (id != null ? !id.equals(album.id) : album.id != null) return false;
        if (!shelf.equals(album.shelf)) return false;
        if (!name.equals(album.name)) return false;

        return true;
    }

    public int hashCode() {
        int result;
        result = (id != null ? id.hashCode() : 0);
        result = 31 * result + name.hashCode();
        result = 31 * result + shelf.hashCode();
        return result;
    }
}
