package <%- entityAbsolutePackage %>.<%_ if(jpaMetamodelFiltering && reactive) { _%>domain<%_ } else { _%>service<%_ } _%>.criteria;

import java.io.Serializable;
import java.util.Optional;
import java.util.Objects;
import java.util.function.BiFunction;

import org.springdoc.core.annotations.ParameterObject;
import tech.jhipster.service.Criteria;
<%_ for (const field of fields) { _%>
  <%_ if (field.fieldIsEnum === true) { _%>
import <%- packageName %>.domain.enumeration.<%- field.fieldType %>;
  <%_ } _%>
<%_ } _%>
<%_ if (anyFieldIsLocalTime) { _%>
import java.time.LocalTime;
<%_ } _%>
import tech.jhipster.service.filter.*;
<%_ if (ormTool === 'mybatis') { _%>
import com.diboot.core.binding.query.BindQuery;
  <% for (relationship of relationships) { _%>
import <%= relationship.otherEntity.entityAbsolutePackage%>.domain.<%= relationship.otherEntity.entityClass %>;
  <%_ } _%>
<%_ } _%>

/**
 * Criteria class for the {@link <%- entityAbsoluteClass %>} entity. This class is used
 * in {@link <%- entityAbsolutePackage %>.web.rest.<%- entityClass %>Resource} to receive all the possible filtering options from
 * the Http GET request parameters.
 * For example the following could be a valid request:
 * {@code /<%- entityApiUrl %>?id.greaterThan=5&attr1.contains=something&attr2.specified=false}
 * As Spring is unable to properly convert the types, unless specific {@link Filter} class are used, we need to use
 * fix type specific filters.
 */
@ParameterObject
@SuppressWarnings("common-java:DuplicatedBlocks")
public class <%- entityClass %>Criteria implements Serializable, Criteria {
<%_ for (const { type, superType, fieldType } of entityJavaCustomFilters) { _%>

    /**
     * Class for filtering <%- fieldType %>
     */
    public static class <%- type %> extends <%- superType %> {

        public <%- type %>() {}

        public <%- type %>(<%- type %> filter) {
            super(filter);
        }

        @Override
        public <%- type %> copy() {
            return new <%- type %>(this);
        }

    }
<%_ } _%>

    private static final long serialVersionUID = 1L;
<%_ for (const filterableProperty of entityJavaFilterableProperties) { _%>

    <%_ if (ormTool === 'mybatis' && filterableProperty.bindQuery) { _%>
    <%- filterableProperty.bindQuery %>
    <%_ } _%>
    private <%- filterableProperty.propertyJavaFilterType %> <%- filterableProperty.propertyJavaFilterName %>;
    <%_
        const bcAddFilterFields = filterableProperty.bcAddFilterFields || [];
        bcAddFilterFields.forEach(addFilterField => { _%>

        <%_ if (ormTool === 'mybatis' && addFilterField.bindQuery) { _%>
    <%- addFilterField.bindQuery %>
        <%_ } _%>
    private <%- addFilterField.propertyJavaFilterType %> <%- addFilterField.propertyJavaFilterName %>;

    <%_ }); _%>
<%_ } _%>

    <%_ if (ormTool === 'mybatis') { _%>
    @BindQuery(ignore = true)
    <%_ } _%>
    private String jhiCommonSearchKeywords;

    <%_ if (ormTool === 'mybatis') { _%>
    @BindQuery(ignore = true)
    <%_ } _%>
    private Boolean useOr = false;

    <%_ if (ormTool === 'mybatis') { _%>
    @BindQuery(ignore = true)
    <%_ } _%>
    private <%= entityClass %>Criteria and;

    <%_ if (ormTool === 'mybatis') { _%>
    @BindQuery(ignore = true)
    <%_ } _%>
    private <%= entityClass %>Criteria or;

    private Boolean distinct;

    public <%- entityClass %>Criteria() {
    }

    public <%- entityClass %>Criteria(<%- entityClass %>Criteria other) {
<%_ for (const { propertyJavaFilterName, propertyJavaFilterJavaBeanName, propertyJavaFilterType, bcAddFilterFields = [] } of entityJavaFilterableProperties) { _%>
        this.<%- propertyJavaFilterName %> = other.optional<%- propertyJavaFilterJavaBeanName %>().map(<%- propertyJavaFilterType %>::copy).orElse(null);
    <%_
        bcAddFilterFields.forEach(addFilterField => { _%>
        this.<%- addFilterField.propertyJavaFilterName %> = other.optional<%- addFilterField.propertyJavaFilterJavaBeanName %>().map(<%- addFilterField.propertyJavaFilterType %>::copy).orElse(null);
    <%_ }); _%>
<%_ } _%>
        this.distinct = other.distinct;
    }

    @Override
    public <%- entityClass %>Criteria copy() {
        return new <%- entityClass %>Criteria(this);
    }
<%_ for (const { propertyJavaFilterName, propertyJavaFilterType, propertyJavaFilterJavaBeanName, bcAddFilterFields = [] } of entityJavaFilterableProperties) { _%>

    public <%- propertyJavaFilterType %> get<%- propertyJavaFilterJavaBeanName %>() {
        return <%- propertyJavaFilterName %>;
    }

    public Optional<<%- propertyJavaFilterType %>> optional<%- propertyJavaFilterJavaBeanName %>() {
        return Optional.ofNullable(<%- propertyJavaFilterName %>);
    }

    public <%- propertyJavaFilterType %> <%- propertyJavaFilterName %>() {
        if (<%- propertyJavaFilterName %> == null) {
            set<%- propertyJavaFilterJavaBeanName %>(new <%- propertyJavaFilterType %>());
        }
        return <%- propertyJavaFilterName %>;
    }

    public void set<%- propertyJavaFilterJavaBeanName %>(<%- propertyJavaFilterType %> <%- propertyJavaFilterName %>) {
        this.<%- propertyJavaFilterName %> = <%- propertyJavaFilterName %>;
    }
    <%_ bcAddFilterFields.forEach(addFilterField => { _%>

    public <%- addFilterField.propertyJavaFilterType %> get<%- addFilterField.propertyJavaFilterJavaBeanName %>() {
        return <%- addFilterField.propertyJavaFilterName %>;
    }

    public Optional<<%- addFilterField.propertyJavaFilterType %>> optional<%- addFilterField.propertyJavaFilterJavaBeanName %>() {
        return Optional.ofNullable(<%- addFilterField.propertyJavaFilterName %>);
    }

    public <%- addFilterField.propertyJavaFilterType %> <%- addFilterField.propertyJavaFilterName %>() {
        if (<%- addFilterField.propertyJavaFilterName %> == null) {
            set<%- addFilterField.propertyJavaFilterJavaBeanName %>(new <%- addFilterField.propertyJavaFilterType %>());
        }
        return <%- addFilterField.propertyJavaFilterName %>;
    }

    public void set<%- addFilterField.propertyJavaFilterJavaBeanName %>(<%- addFilterField.propertyJavaFilterType %> <%- addFilterField.propertyJavaFilterName %>) {
        this.<%- addFilterField.propertyJavaFilterName %> = <%- addFilterField.propertyJavaFilterName %>;
    }
    <%_ });_%>
<%_ } _%>

    public void setAnd(<%= entityClass %>Criteria and) {
        this.and = and;
    }

    public <%= entityClass %>Criteria getAnd() {
        return and;
    }

    public <%= entityClass %>Criteria and() {
        if (and == null) {
            and = new <%= entityClass %>Criteria();
        }
        return and;
    }

    public void setOr(<%= entityClass %>Criteria or) {
        this.or = or;
    }

    public <%= entityClass %>Criteria getOr() {
        return or;
    }

    public <%= entityClass %>Criteria or() {
        if (or == null) {
            or = new <%= entityClass %>Criteria();
        }
        return or;
    }

     public String getJhiCommonSearchKeywords() {
        return jhiCommonSearchKeywords;
    }

    public void setJhiCommonSearchKeywords(String jhiCommonSearchKeywords) {
        this.jhiCommonSearchKeywords = jhiCommonSearchKeywords;
    }

    public Boolean getUseOr() {
        return useOr;
    }

    public void setUseOr(Boolean useOr) {
        this.useOr = useOr;
    }

    public Boolean getDistinct() {
        return distinct;
    }

    public Optional<Boolean> optionalDistinct() {
        return Optional.ofNullable(distinct);
    }

    public Boolean distinct() {
        if (distinct == null) {
            setDistinct(true);
        }
        return distinct;
    }

    public void setDistinct(Boolean distinct) {
        this.distinct = distinct;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        final <%- entityClass %>Criteria that = (<%- entityClass %>Criteria) o;
        return
<%_ for (const { propertyJavaFilterName } of entityJavaFilterableProperties) { _%>
            Objects.equals(<%- propertyJavaFilterName %>, that.<%- propertyJavaFilterName %>) &&
<%_ } _%>
            Objects.equals(distinct, that.distinct);
    }

    @Override
    public int hashCode() {
        return Objects.hash(
<%_ for (const { propertyJavaFilterName } of entityJavaFilterableProperties) { _%>
          <%- propertyJavaFilterName %>,
<%_ } _%>
          distinct
        );
    }

    // prettier-ignore
    @Override
    public String toString() {
        return "<%- entityClass %>Criteria{" +
<%_ for (const { propertyJavaFilterName, propertyJavaFilterJavaBeanName, bcAddFilterFields = [] } of entityJavaFilterableProperties) { _%>
            optional<%- propertyJavaFilterJavaBeanName %>().map(f -> "<%- propertyJavaFilterName %>=" + f + ", ").orElse("") +
    <%_ bcAddFilterFields.forEach(addFilterField => { _%>
            optional<%- addFilterField.propertyJavaFilterJavaBeanName %>().map(f -> "<%- addFilterField.propertyJavaFilterName %>=" + f + ", ").orElse("") +
    <%_ }); _%>
<%_ } _%>
            (jhiCommonSearchKeywords != null ? "jhiCommonSearchKeywords=" + jhiCommonSearchKeywords + ", " : "") +
            "useOr=" + useOr +
            (and != null ? "and=" + and + ", " : "") +
            (or != null ? "or=" + or + ", " : "") +
            optionalDistinct().map(f -> "distinct=" + f + ", ").orElse("") +
        "}";
    }

}
