package com.jakubu9333.grammarManager.model;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonView;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.PostUpdate;
import javax.persistence.SequenceGenerator;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * @author Jakub Uhlarik
 */
@Entity
@Getter
@Setter
public class Grammar {

    @Id
    @JsonView(View.All.class)
    @SequenceGenerator(name = "grammar_sequence", allocationSize = 1, sequenceName = "grammar_sequence")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "grammar_sequence")
    private Long id;

    @JsonView(View.All.class)
    @Column(columnDefinition = "text")
    private String uri;

    // @JsonView(View.All.class)
    private LocalDateTime updateTime;


    @OneToMany
    @JsonView(View.All.class)
    private Set<FileMetadata> files;


    @OneToMany
    @JsonView(View.RuleWithoutGrammar.class)
    private Set<RuleModel> rules;

    @OneToOne
    @JsonView(View.RuleWithoutGrammar.class)
    private RuleModel rootRule;


    public Grammar() {
        this(null, null, null);
    }

    public Grammar(String uri, Set<RuleModel> rules, RuleModel rootRule) {
        this(null, uri, rules, rootRule);
    }
    public Grammar(String uri ){
        this(null, uri, null, null);
    }


    @JsonCreator
    public Grammar(@JsonProperty("id") Long id, @JsonProperty("uri") String uri, @JsonProperty("rules") Set<RuleModel> rules, @JsonProperty("rootRule") RuleModel rootRule) {
        this.rootRule = rootRule;
        this.uri = uri;
        this.files = new HashSet<>();
        if (rules == null) {
            this.rules = new HashSet<>();
            return;
        }
        this.rules = rules;

    }

    @PostUpdate
    public void preUpdate() {
        this.updateTime = LocalDateTime.now();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Grammar grammar = (Grammar) o;
        return Objects.equals(uri, grammar.uri) && Objects.equals(rules, grammar.rules) && Objects.equals(rootRule, grammar.rootRule);
    }

    @Override
    public int hashCode() {
        return Objects.hash(uri, rules, rootRule);
    }
}
