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.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

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

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

    @ManyToOne
    @JsonView(View.GrammarWithoutRules.class)
    private Grammar grammar;

    @JsonView(View.All.class)
    @Column(columnDefinition = "text")
    private String leftSymbol;
    @JsonView(View.All.class)
    @OneToMany
    private Set<RightSidePart> rightSide;


    @JsonView(View.All.class)
    private Boolean root;

    @JsonCreator
    public RuleModel(@JsonProperty("id") Long id, @JsonProperty("grammar") Grammar grammar, @JsonProperty("leftSymbol") String leftSymbol, @JsonProperty("rightSide") Set<RightSidePart> rightSide, @JsonProperty("isRoot") Boolean isRoot) {
        this.root = isRoot;
        this.grammar = grammar;
        this.leftSymbol = leftSymbol;
        if (rightSide == null) {
            this.rightSide = new HashSet<>();
            return;
        }
        this.rightSide = rightSide;
    }

    public RuleModel() {
        this(null, null, new HashSet<>(), null);
    }

    public RuleModel(String leftSymbol, Set<RightSidePart> rightSide, Boolean isRoot) {
        this(null, null, leftSymbol, rightSide, isRoot);
    }

    public RuleModel(String leftSymbol, Set<RightSidePart> rightSide) {
        this(null, null, leftSymbol, rightSide, false);
    }

    public RuleModel(Grammar grammar, String leftSymbol, Set<RightSidePart> rightSide, Boolean isRoot) {
        this(null, grammar, leftSymbol, rightSide, isRoot);
    }


    public RuleModel(RuleModel rule) {
        this.root = rule.getRoot();
        this.id = null;
        this.grammar = rule.getGrammar();
        this.leftSymbol = rule.getLeftSymbol();
        this.rightSide = rule.getRightSide().stream().map(RightSidePart::new).collect(Collectors.toSet());
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RuleModel rule = (RuleModel) o;
        return Objects.equals(leftSymbol, rule.leftSymbol) && Objects.equals(rightSide, rule.rightSide) && Objects.equals(root, rule.root);
    }

    @Override
    public int hashCode() {
        return Objects.hash(leftSymbol, rightSide, root);
    }
}
