package de.vorb.platon.model;


import de.vorb.platon.web.rest.json.ByteArraySerializer;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Arrays;
import java.util.Objects;


@Entity
@Table(name = "COMMENTS")
public class Comment {

    private static final Logger logger = LoggerFactory.getLogger(Comment.class);

    private static final int LIMIT_AUTHOR = 128;
    private static final int LIMIT_URL = 256;

    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "comments_seq")
    @SequenceGenerator(name = "comments_seq", sequenceName = "SEQ_COMMENTS", allocationSize = 0)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "THREAD_ID", nullable = false)
    @JsonIgnore
    private CommentThread thread;

    @OneToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "PARENT_ID", nullable = true)
    @JsonIgnore
    private Comment parent;

    @Column(name = "CREATION_DATE", nullable = false)
    private Instant creationDate;

    @Column(name = "MODIFICATION_DATE", nullable = false)
    private Instant modificationDate;

    @Column(name = "TEXT", nullable = false)
    @Lob
    private String text;

    @Column(name = "AUTHOR", length = LIMIT_AUTHOR, nullable = true)
    private String author;

    @Column(name = "EMAIL_HASH", columnDefinition = "BINARY(16) NULL")
    @JsonSerialize(using = ByteArraySerializer.class)
    private byte[] emailHash;

    @Column(name = "URL", length = LIMIT_URL, nullable = true)
    private String url;


    protected Comment() {}

    public Comment(CommentThread thread, Comment parent, String text, String author, String email, String url) {
        setThread(thread);
        setParent(parent);
        setText(text);
        setAuthor(author);
        setEmail(email);
        setUrl(url);
    }


    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public CommentThread getThread() {
        return thread;
    }

    public void setThread(CommentThread thread) {
        this.thread = thread;
    }

    public Comment getParent() {
        return parent;
    }

    public void setParent(Comment parent) {
        this.parent = parent;
    }

    public Long getParentId() {
        return parent != null ? parent.getId() : null;
    }

    public void setParentId(Long parentId) {
        if (parentId != null) {
            parent = new Comment();
            parent.setId(parentId);
        } else if (parent != null) {
            parent = null;
        }
    }

    public Instant getCreationDate() {
        return creationDate;
    }

    public void setCreationDate(Instant creationDate) {
        this.creationDate = creationDate;
    }

    public Instant getModificationDate() {
        return modificationDate;
    }

    public void setModificationDate(Instant modificationDate) {
        this.modificationDate = modificationDate;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        Preconditions.checkNotNull(text);
        this.text = text;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = StringUtils.left(author, LIMIT_AUTHOR);
    }

    public byte[] getEmailHash() {
        return emailHash;
    }

    public void setEmailHash(byte[] emailHash) {
        Preconditions.checkArgument(emailHash.length == 16, "emailHash has invalid length");
        this.emailHash = emailHash;
    }

    public void setEmail(String email) {
        if (email == null) {
            this.emailHash = null;
            return;
        }

        final byte[] stringBytes = email.getBytes(StandardCharsets.UTF_8);
        try {
            emailHash = MessageDigest.getInstance("MD5").digest(stringBytes);
        } catch (NoSuchAlgorithmException e) {
            logger.error("No implementation of MessageDigest algorithm MD5 available on this platform");
        }
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = StringUtils.left(url, LIMIT_URL);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Comment comment = (Comment) o;
        return Objects.equals(id, comment.id) &&
                Objects.equals(thread, comment.thread) &&
                Objects.equals(text, comment.text) &&
                Objects.equals(author, comment.author) &&
                Arrays.equals(emailHash, comment.emailHash) &&
                Objects.equals(url, comment.url);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, thread, text, author, emailHash, url);
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .omitNullValues()
                .add("id", id)
                .add("text", text)
                .add("author", author)
                .add("emailHash", emailHash)
                .add("url", url)
                .toString();
    }

}

@@ -287,16 +287,80 @@
 itions;%0A
+import org.apache.commons.codec.digest.MessageDigestAlgorithms;%0A
 import o
@@ -4745,13 +4745,35 @@
 nce(
-%22
+MessageDigestAlgorithms.
 MD5
-%22
 ).di
@@ -5410,24 +5410,82 @@
 .thread) &&%0A
+                Objects.equals(parent, comment.parent) &&%0A
             
@@ -5785,16 +5785,24 @@
  thread,
+ parent,
  text, a
@@ -5808,16 +5808,44 @@
 author, 
+url) * 31 + Arrays.hashCode(
 emailHas
@@ -5845,21 +5845,16 @@
 mailHash
-, url
 );%0A    %7D

Fix hashCode of comment model