/*
 * Project home: https://github.com/jaxio/celerio-angular-quickstart
 * 
 * Source code generated by Celerio, an Open Source code generator by Jaxio.
 * Documentation: http://www.jaxio.com/documentation/celerio/
 * Source code: https://github.com/jaxio/celerio/
 * Follow us on twitter: @jaxiosoft
 * This header can be customized in Celerio conf...
 * Template pack-angular:src/main/java/domain/Entity.java.e.vm
 */
package com.mycompany.myapp.domain;

import static javax.persistence.EnumType.STRING;
import static javax.persistence.GenerationType.IDENTITY;

import java.io.Serializable;
import java.time.Instant;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;

import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;

/**
 * Author has various dates for demo
 */
@Entity
@Table(name = "AUTHOR")
public class Author implements Identifiable<Integer>, Serializable {
    private static final long serialVersionUID = 1L;
    private static final Logger log = Logger.getLogger(Author.class.getName());

    // Raw attributes
    private Integer id;
    private Civility civility;
    private String lastName;
    private String firstName;
    private String email;
    private LocalDate birthDate;
    private Instant birthDateTime;

    // Many to one
    private Author favoriteAuthor;

    // One to many
    private List<Book> books = new ArrayList<Book>();
    private List<Project> projects = new ArrayList<Project>();

    @Override
    public String entityClassName() {
        return Author.class.getSimpleName();
    }

    // -- [id] ------------------------

    @Override
    @Column(name = "ID", precision = 10)
    @GeneratedValue(strategy = IDENTITY)
    @Id
    public Integer getId() {
        return id;
    }

    @Override
    public void setId(Integer id) {
        this.id = id;
    }

    public Author id(Integer id) {
        setId(id);
        return this;
    }

    @Override
    @Transient
    public boolean isIdSet() {
        return id != null;
    }
    // -- [civility] ------------------------

    @Column(name = "CIVILITY", length = 2)
    @Enumerated(STRING)
    public Civility getCivility() {
        return civility;
    }

    public void setCivility(Civility civility) {
        this.civility = civility;
    }

    public Author civility(Civility civility) {
        setCivility(civility);
        return this;
    }
    // -- [lastName] ------------------------

    @Size(min = 2, max = 100)
    @Column(name = "LAST_NAME", length = 100)
    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Author lastName(String lastName) {
        setLastName(lastName);
        return this;
    }
    // -- [firstName] ------------------------

    @NotEmpty
    @Size(min = 2, max = 100)
    @Column(name = "FIRST_NAME", nullable = false, length = 100)
    public String getFirstName() {
        return firstName;
    }

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

    public Author firstName(String firstName) {
        setFirstName(firstName);
        return this;
    }
    // -- [email] ------------------------

    @Email
    @Size(max = 100)
    @Column(name = "EMAIL", length = 100)
    public String getEmail() {
        return email;
    }

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

    public Author email(String email) {
        setEmail(email);
        return this;
    }
    // -- [birthDate] ------------------------

    @Column(name = "BIRTH_DATE", length = 8)
    public LocalDate getBirthDate() {
        return birthDate;
    }

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

    public Author birthDate(LocalDate birthDate) {
        setBirthDate(birthDate);
        return this;
    }
    // -- [birthDateTime] ------------------------

    @Column(name = "BIRTH_DATE_TIME", length = 23)
    public Instant getBirthDateTime() {
        return birthDateTime;
    }

    public void setBirthDateTime(Instant birthDateTime) {
        this.birthDateTime = birthDateTime;
    }

    public Author birthDateTime(Instant birthDateTime) {
        setBirthDateTime(birthDateTime);
        return this;
    }

    // -----------------------------------------------------------------
    // Many to One support
    // -----------------------------------------------------------------

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // many-to-one: Author.favoriteAuthor ==> Author.id
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    @JoinColumn(name = "FAVORITE_AUTHOR_ID")
    @ManyToOne
    public Author getFavoriteAuthor() {
        return favoriteAuthor;
    }

    /**
     * Set the {@link #favoriteAuthor} without adding this Author instance on the passed {@link #favoriteAuthor}
     */
    public void setFavoriteAuthor(Author favoriteAuthor) {
        this.favoriteAuthor = favoriteAuthor;
    }

    public Author favoriteAuthor(Author favoriteAuthor) {
        setFavoriteAuthor(favoriteAuthor);
        return this;
    }

    // -----------------------------------------------------------------
    // One to Many support
    // -----------------------------------------------------------------

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // one to many: author ==> books
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    @OneToMany(mappedBy = "author", orphanRemoval = true)
    public List<Book> getBooks() {
        return books;
    }

    /**
     * Set the {@link Book} list.
     * It is recommended to use the helper method {@link #addBook(Book)} / {@link #removeBook(Book)}
     * if you want to preserve referential integrity at the object level.
     *
     * @param books the list to set
     */
    public void setBooks(List<Book> books) {
        this.books = books;
    }

    /**
     * Helper method to add the passed {@link Book} to the {@link #books} list
     * and set this author on the passed book to preserve referential
     * integrity at the object level.
     *
     * @param book the to add
     * @return true if the book could be added to the books list, false otherwise
     */
    public boolean addBook(Book book) {
        if (getBooks().add(book)) {
            book.setAuthor(this);
            return true;
        }
        return false;
    }

    /**
     * Helper method to remove the passed {@link Book} from the {@link #books} list and unset
     * this author from the passed book to preserve referential integrity at the object level.
     *
     * @param book the instance to remove
     * @return true if the book could be removed from the books list, false otherwise
     */
    public boolean removeBook(Book book) {
        if (getBooks().remove(book)) {
            book.setAuthor(null);
            return true;
        }
        return false;
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // one to many: author ==> projects
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    @OneToMany(mappedBy = "author", orphanRemoval = true)
    public List<Project> getProjects() {
        return projects;
    }

    /**
     * Set the {@link Project} list.
     * It is recommended to use the helper method {@link #addProject(Project)} / {@link #removeProject(Project)}
     * if you want to preserve referential integrity at the object level.
     *
     * @param projects the list to set
     */
    public void setProjects(List<Project> projects) {
        this.projects = projects;
    }

    /**
     * Helper method to add the passed {@link Project} to the {@link #projects} list
     * and set this author on the passed project to preserve referential
     * integrity at the object level.
     *
     * @param project the to add
     * @return true if the project could be added to the projects list, false otherwise
     */
    public boolean addProject(Project project) {
        if (getProjects().add(project)) {
            project.setAuthor(this);
            return true;
        }
        return false;
    }

    /**
     * Helper method to remove the passed {@link Project} from the {@link #projects} list and unset
     * this author from the passed project to preserve referential integrity at the object level.
     *
     * @param project the instance to remove
     * @return true if the project could be removed from the projects list, false otherwise
     */
    public boolean removeProject(Project project) {
        if (getProjects().remove(project)) {
            project.setAuthor(null);
            return true;
        }
        return false;
    }

    /**
     * Apply the default values.
     */
    public Author withDefaults() {
        setCivility(Civility.MR);
        return this;
    }

    /**
     * Equals implementation using a business key.
     */
    @Override
    public boolean equals(Object other) {
        return this == other || (other instanceof Author && hashCode() == other.hashCode());
    }

    private IdentifiableHashBuilder identifiableHashBuilder = new IdentifiableHashBuilder();

    @Override
    public int hashCode() {
        return identifiableHashBuilder.hash(log, this);
    }

    /**
     * Construct a readable string representation for this Author instance.
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this) //
                .add("id", getId()) //
                .add("civility", getCivility()) //
                .add("lastName", getLastName()) //
                .add("firstName", getFirstName()) //
                .add("email", getEmail()) //
                .add("birthDate", getBirthDate()) //
                .add("birthDateTime", getBirthDateTime()) //
                .toString();
    }
}