package org.richfaces.realworld.domain;

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

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.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.persistence.Version;
import org.hibernate.validator.Length;
import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.NotNull;
import org.hibernate.validator.Pattern;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Role;
import org.jboss.seam.annotations.Scope;

/*@NamedQueries({
    @NamedQuery(
        name = "User-rootAlbums",
        query = "select a from Album a where a.parent is null and a.owner=:owner"
   )
})*/

@Entity
@Scope(ScopeType.CONVERSATION)
@Name("user")
@Role(name="selectedUser", scope = ScopeType.CONVERSATION)
@Table(name = "Users")
public class User implements Serializable {
	
	
	private static final long serialVersionUID = 1L;
	
	@Id
	@GeneratedValue
	@Column(name = "USER_ID")
	private Long id = null;
	
	@Version
	@Column(name = "OBJ_VERSION")
	private int version = 0;
	 
	@Column(length = 255, nullable = false)
    @NotNull
	@NotEmpty
    @Length(min=3)
	private String firstName;
	
	@Column(length = 255, nullable = false)
    @NotNull
    @NotEmpty
    @Length(min=3)
	private String secondName;
	
	@Column(length = 255, nullable = false)
    @NotNull
    @NotEmpty
    @Pattern(regex=".+@.+\\.[a-z]+", message="Not valid e-mail")
	private String email;
	
	@Column(length = 255)
	private String avatarPath;
	
	@Column(length = 255, nullable = false)
    @NotNull
    @NotEmpty
    @Length(min=3)
	private String login;
	
	@Column(length = 255, nullable = false)
    @NotNull
    @NotEmpty
    @Length(min=3)
	private String password;
	
	@Transient
	private String confirmPassword;
	
	@ManyToMany(mappedBy = "sharedOwners")
    private List<Album> sharedAlbums = new ArrayList<Album>();
	
	@ManyToMany
    @JoinTable(
        name = "USER_FRIENDS",
        joinColumns =        @JoinColumn(name = "USER1_ID"),
        inverseJoinColumns = @JoinColumn(name = "USER2_ID")
    )
	private List<User> friends;
	
	@Temporal(TemporalType.TIMESTAMP)
	private Date birthDate;
	
	@OneToMany(mappedBy = "owner", cascade = { CascadeType.ALL}, fetch = FetchType.LAZY)
	    @org.hibernate.annotations.LazyCollection(org.hibernate.annotations.LazyCollectionOption.EXTRA)
	    @org.hibernate.annotations.OrderBy(clause = "NAME asc")
	    private List<Album> childAlbums = new ArrayList<Album>();
	
	@OneToMany(mappedBy = "owner", cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
    @org.hibernate.annotations.LazyCollection(org.hibernate.annotations.LazyCollectionOption.EXTRA)
    @org.hibernate.annotations.OrderBy(clause = "Date desc")
    private List<Message> messages = new ArrayList<Message>();
	
	@OneToMany(mappedBy = "user", cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
    private List<FriendshipRequest> friendshipRequests = new ArrayList<FriendshipRequest>();

	/**
	 * No-arg constructor for JavaBean tools
	 */
    public User() {
    }

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getSecondName() {
		return secondName;
	}

	public void setSecondName(String secondName) {
		this.secondName = secondName;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getAvatarPath() {
		return avatarPath;
	}

	public void setAvatarPath(String avatarPath) {
		this.avatarPath = avatarPath;
	}

	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public Date getBirthDate() {
		return birthDate;
	}

	public void setBirthDate(Date birthDate) {
		this.birthDate = birthDate;
	}

	public Long getId() {
		return id;
	}

	public List<Album> getChildAlbums() {
		return childAlbums;
	}

	public void setChildAlbums(List<Album> childAlbums) {
		this.childAlbums = childAlbums;
	}
	
	//---------------------------Business methods
	
	/**
	 * This method add image to collection of images of current album
	 * 
	 * @param image - image to add
	 */
    public void addAlbum(Album album) {
        if (album == null) {
            throw new IllegalArgumentException("Null album!");
        } 
        if (album.getOwner() != null && !this.equals(album.getOwner())) {
        	album.getOwner().getChildAlbums().remove(album);
        }   
        album.setOwner(this);
        childAlbums.add(album);
    }

	/**
	 * This method remove image from collection of images of album
	 * 
	 * @param image - image to remove
	 */
    public void removeAlbum(Album album) {
        if (album == null) {
            throw new IllegalArgumentException("Null album");
        }  
        album.setOwner(null);
        childAlbums.remove(album);
    }
    
    public void removeFriend(User friend) {
        if (friend == null) {
            throw new IllegalArgumentException("Null friend");
        }  
        friends.remove(friend);
    }
    
    public void addMessage(Message message) {
        if (message == null) {
            throw new IllegalArgumentException("Null Message!");
        } 
        if (message.getOwner() != null && !this.equals(message.getOwner())) {
        	message.getOwner().getMessages().remove(message);
        }   
        message.setOwner(this);
        messages.add(message);
    }

    public void removeMessage(Message message) {
        if (message == null) {
            throw new IllegalArgumentException("Null message");
        }  
        message.setOwner(null);
        messages.remove(message);
    }

	public String getConfirmPassword() {
		return confirmPassword;
	}

	public void setConfirmPassword(String confirmPassword) {
		this.confirmPassword = confirmPassword;
	}

	public List<User> getFriends() {
		return friends;
	}

	public void setFriends(List<User> friends) {
		this.friends = friends;
	}

	public List<Album> getSharedAlbums() {
		return sharedAlbums;
	}

	public void setSharedAlbums(List<Album> sharedAlbums) {
		this.sharedAlbums = sharedAlbums;
	}

	public List<Message> getMessages() {
		return messages;
	}

	public void setMessages(List<Message> messages) {
		this.messages = messages;
	}

	public List<FriendshipRequest> getFriendshipRequests() {
		return friendshipRequests;
	}

	public void setFriendshipRequests(List<FriendshipRequest> friendshipRequests) {
		this.friendshipRequests = friendshipRequests;
	}

	public void addFriendshipRequest(User owner) {
		FriendshipRequest request = new FriendshipRequest();
		request.setUser(this);
		request.setFriend(owner);
		this.friendshipRequests.add(request);
	}

	public void removeFriendshipRequest(FriendshipRequest request) {
		this.friendshipRequests.remove(request);	
	}

	public void addFriend(User friend) {
		this.friends.add(friend);
	}

	public FriendshipRequest getFriendshipRequest(User friend, User user) {
		for(FriendshipRequest req: this.friendshipRequests){
			if(req.getUser().getLogin().equals(user.getLogin()) && req.getFriend().getLogin().equals(friend.getLogin())){
				return req;
			}
		}
		return null;
	}

	public Album getAlbumByName(String albumName){
		for(Album a : this.getChildAlbums()){
			if(a.getName().equals(albumName)){
				return a;
			}
		}
		return null;
	}

	public void removeFromSharedAlbums(Album album) {
		sharedAlbums.remove(album);
	}

	public void addSharedAlbum(Album album) {
		if (album == null) {
            throw new IllegalArgumentException("Null album!");
        } 
		if(sharedAlbums.contains(album)){
			return;
		}
		sharedAlbums.add(album);
	}
}