package org.codiki.core.entities.persistence;

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.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.codiki.core.entities.dto.View;
import org.hibernate.annotations.Generated;
import org.hibernate.annotations.GenerationTime;

import com.fasterxml.jackson.annotation.JsonView;
import org.hibernate.annotations.Proxy;

@Entity
@Table(name="`user`")
@Proxy(lazy = false)
public class User implements Serializable {
	private static final long serialVersionUID = 1L;

	/* ******************* */
	/* Attributes */
	/* ******************* */
	@Id
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="user_id_seq")
	@SequenceGenerator(name="user_id_seq", sequenceName="user_id_seq", allocationSize=1)
	private Long id;

	@JsonView({View.UserDTO.class, View.PostDTO.class})
	// This annotation serves to fetch the attribute after an insert into db
	@Generated(GenerationTime.ALWAYS)
	private String key;

	@JsonView({View.UserDTO.class, View.PostDTO.class})
	private String name;

	@JsonView({View.UserDTO.class, View.PostDTO.class})
	private String email;

	private String password;

	@JsonView({View.UserDTO.class, View.PostDTO.class})
	private String image;

	@JsonView({View.UserDTO.class, View.PostDTO.class})
	@Column(name = "inscription_date")
	@Temporal(TemporalType.TIMESTAMP)
	private Date inscriptionDate;

	/* ******************* */
	/* Relations */
	/* ******************* */
	@JsonView({View.UserDTO.class})
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "role_id")
	private Role role;
	
	@OneToMany(mappedBy = "author")
	private List<Post> listPosts;
	
	@OneToMany(mappedBy = "author")
	private List<Comment> listComments;
	
	@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
	private List<Image> listImages;
	
	/* ******************* */
	/* Constructors */
	/* ******************* */
	public User() {
		super();
	}
	
	/* ******************* */
	/* Getters & Setters */
	/* ******************* */
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		if(this.id != null) {
			throw new IllegalAccessError("It's not allowed to rewrite the id entity.");
		}
		this.id = id;
	}

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

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

	public String getPassword() {
		return password;
	}

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

	public String getImage() {
		return image;
	}

	public void setImage(String image) {
		this.image = image;
	}

	public Date getInscriptionDate() {
		return inscriptionDate;
	}

	public void setInscriptionDate(Date inscriptionDate) {
		this.inscriptionDate = inscriptionDate;
	}

	public Role getRole() {
		return role;
	}

	public void setRole(Role role) {
		this.role = role;
	}

	public List<Post> getListPosts() {
		return listPosts;
	}

	public void setListPosts(List<Post> listPosts) {
		this.listPosts = listPosts;
	}

	public List<Comment> getListComments() {
		return listComments;
	}

	public void setListComments(List<Comment> listComments) {
		this.listComments = listComments;
	}

	public List<Image> getListImages() {
		return listImages;
	}

	public void addImage(final Image pImage) {
		if(listImages == null) {
			listImages = new ArrayList<>();
		}
		listImages.add(pImage);
		
		if(pImage.getUser() == null) {
			pImage.setUser(this);
		}
	}

	public void setListImages(List<Image> listImages) {
		this.listImages = listImages;
	}
}
