Package com.psddev.cms.tool.page

Source Code of com.psddev.cms.tool.page.SearchAdvancedPredicate

package com.psddev.cms.tool.page;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;

import com.psddev.cms.db.Taxon;
import com.psddev.cms.db.ToolUi;
import com.psddev.cms.tool.Search;
import com.psddev.cms.tool.ToolPageContext;
import com.psddev.dari.db.ComparisonPredicate;
import com.psddev.dari.db.CompoundPredicate;
import com.psddev.dari.db.Database;
import com.psddev.dari.db.DatabaseEnvironment;
import com.psddev.dari.db.ObjectField;
import com.psddev.dari.db.ObjectFieldComparator;
import com.psddev.dari.db.ObjectIndex;
import com.psddev.dari.db.ObjectStruct;
import com.psddev.dari.db.ObjectType;
import com.psddev.dari.db.Predicate;
import com.psddev.dari.db.Query;
import com.psddev.dari.db.Record;
import com.psddev.dari.db.Singleton;
import com.psddev.dari.db.State;
import com.psddev.dari.util.ObjectUtils;

@ToolUi.Hidden
public abstract class SearchAdvancedPredicate extends Record implements Singleton {

    @Indexed(unique = true)
    @Required
    protected String parameterValue;

    public String getParameterValue() {
        return parameterValue;
    }

    public abstract String getLabel();

    public abstract Predicate writeInputs(
            SearchAdvancedQuery servlet,
            ToolPageContext page,
            List<String> paramNames,
            String predicateParam,
            String paramPrefix)
            throws IOException;

    public abstract static class Compound extends SearchAdvancedPredicate {

        public abstract String getOperator();

        @Override
        public Predicate writeInputs(
                SearchAdvancedQuery servlet,
                ToolPageContext page,
                List<String> paramNames,
                String predicateParam,
                String paramPrefix)
                throws IOException {

            Predicate predicate = null;
            String subPredicateIndexParam = paramPrefix + ".p";
            int lastSubPredicateIndex = -1;

            page.writeStart("ul");
                for (String paramName : paramNames) {
                    if (paramName.startsWith(subPredicateIndexParam)) {
                        Integer subPredicateIndex = ObjectUtils.to(Integer.class, paramName.substring(subPredicateIndexParam.length()));

                        if (subPredicateIndex != null) {
                            if (lastSubPredicateIndex < subPredicateIndex) {
                                lastSubPredicateIndex = subPredicateIndex;
                            }

                            page.writeStart("li");
                                predicate = CompoundPredicate.combine(
                                        getOperator(),
                                        predicate,
                                        servlet.writeSearchAdvancedPredicate(page, paramNames, paramName, paramPrefix + "." + subPredicateIndex));
                            page.writeEnd();
                        }
                    }
                }
            page.writeEnd();

            page.writeStart("button",
                    "class", "icon icon-action-add link",
                    "name", paramPrefix + ".p" + (lastSubPredicateIndex + 1),
                    "value", 1);
                page.writeHtml("Add Another ");
                page.writeHtml(getLabel());
            page.writeEnd();

            return predicate;
        }
    }

    public static class And extends Compound {

        public And() {
            this.parameterValue = "A";
        }

        @Override
        public String getLabel() {
            return "Match All (AND)";
        }

        @Override
        public String getOperator() {
            return "AND";
        }
    }

    public static class Or extends Compound {

        public Or() {
            this.parameterValue = "O";
        }

        @Override
        public String getLabel() {
            return "Match Any (OR)";
        }

        @Override
        public String getOperator() {
            return "OR";
        }
    }

    public static class Not extends Compound {

        public Not() {
            this.parameterValue = "N";
        }

        @Override
        public String getLabel() {
            return "Match None (NOT)";
        }

        @Override
        public String getOperator() {
            return "NOT";
        }
    }

    public static class Comparison extends SearchAdvancedPredicate {

        public Comparison() {
            this.parameterValue = "C";
        }

        @Override
        public String getLabel() {
            return "Comparison";
        }

        @Override
        public Predicate writeInputs(
                SearchAdvancedQuery servlet,
                ToolPageContext page,
                List<String> paramNames,
                String predicateParam,
                String paramPrefix)
                throws IOException {

            String comparisonTypeParam = paramPrefix + ".ct";
            String comparisonPathParam = paramPrefix + ".cp";
            String comparisonOperatorParam = paramPrefix + ".co";
            String comparisonValueParam = paramPrefix + ".cv";
            DatabaseEnvironment environment = Database.Static.getDefault().getEnvironment();
            Set<UUID> comparisonTypeIds = new HashSet<UUID>();
            Set<ObjectType> comparisonTypes = new HashSet<ObjectType>();

            for (UUID id : page.params(UUID.class, comparisonTypeParam)) {
                comparisonTypeIds.add(id);
                comparisonTypes.add(ObjectType.getInstance(id));
            }

            String comparisonPath = page.param(String.class, comparisonPathParam);
            ComparisonOperator comparisonOperator = page.param(ComparisonOperator.class, comparisonOperatorParam);
            PathedField comparisonPathedField = null;
            ObjectField comparisonField = null;

            page.writeHtml(" ");
            page.writeMultipleTypeSelect(
                    null,
                    comparisonTypes,
                    "name", comparisonTypeParam,
                    "placeholder", "Any Types",
                    "data-bsp-autosubmit", "",
                    "data-searchable", true);

            page.writeHtml(" ");
            page.writeStart("select",
                    "name", comparisonPathParam,
                    "data-bsp-autosubmit", "",
                    "data-searchable", true);
                page.writeStart("option", "value", "");
                    page.writeHtml("Any Fields");
                page.writeEnd();

                if (!comparisonTypes.isEmpty()) {
                    Set<PathedField> pathedFields = null;

                    for (ObjectType t : comparisonTypes) {
                        Set<PathedField> pf = getPathedFields(t);

                        if (pathedFields == null) {
                            pathedFields = pf;

                        } else {
                            pathedFields.retainAll(pf);
                        }
                    }

                    if (!pathedFields.isEmpty()) {
                        page.writeStart("optgroup", "label", "Type-Specific Fields");
                            for (PathedField pf : pathedFields) {
                                String path = pf.getPath();

                                if (comparisonField == null &&
                                        path.equals(comparisonPath)) {
                                    List<ObjectField> pfs = pf.getFields();

                                    if (!pfs.isEmpty()) {
                                        comparisonPathedField = pf;
                                        comparisonField = pfs.get(pfs.size() - 1);
                                    }
                                }

                                page.writeStart("option",
                                        "selected", path.equals(comparisonPath) ? "selected" : null,
                                        "value", path);
                                    page.writeHtml(pf.getDisplayName());
                                page.writeEnd();
                            }
                        page.writeEnd();
                    }
                }

                page.writeStart("optgroup", "label", "Global Fields");
                    for (PathedField pf : getPathedFields(environment)) {
                        String path = pf.getPath();

                        if (comparisonField == null &&
                                path.equals(comparisonPath)) {
                            List<ObjectField> pfs = pf.getFields();

                            if (!pfs.isEmpty()) {
                                comparisonPathedField = pf;
                                comparisonField = pfs.get(pfs.size() - 1);
                            }
                        }

                        page.writeStart("option",
                                "selected", path.equals(comparisonPath) ? "selected" : null,
                                "value", path);
                            page.writeHtml(pf.getDisplayName());
                        page.writeEnd();
                    }
                page.writeEnd();
            page.writeEnd();

            page.writeHtml(" ");
            page.writeStart("select",
                    "data-bsp-autosubmit", "",
                    "name", comparisonOperatorParam);
                for (ComparisonOperator op : ComparisonOperator.values()) {
                    if ((ObjectUtils.isBlank(comparisonPath) &&
                            !op.equals(ComparisonOperator.M)) ||
                            (!ObjectUtils.isBlank(comparisonPath) &&
                            !op.isDisplayedFor(comparisonField))) {
                        if (op.equals(comparisonOperator)) {
                            comparisonOperator = null;
                        }

                        continue;
                    }

                    if (comparisonOperator == null) {
                        comparisonOperator = op;
                    }

                    page.writeStart("option",
                            "selected", op.equals(comparisonOperator) ? "selected" : null,
                            "value", op.name());
                        page.writeHtml(op.getLabel());
                        page.writeHtml(":");
                    page.writeEnd();
                }
            page.writeEnd();

            page.writeHtml(" ");
            comparisonOperator.writeValueInputs(page, comparisonValueParam, comparisonField);

            return CompoundPredicate.combine(
                    "AND",
                    comparisonTypeIds.isEmpty() ? null : new ComparisonPredicate("=", false, "_type", comparisonTypeIds),
                    comparisonOperator.createPredicate(page, comparisonValueParam, comparisonPathedField));
        }

        private Set<PathedField> getPathedFields(ObjectStruct struct) {
            Set<PathedField> pathedFields = new TreeSet<PathedField>();

            addPathedFields(pathedFields, null, struct);
            return pathedFields;
        }

        private void addPathedFields(Set<PathedField> pathedFields, List<ObjectField> prefix, ObjectStruct struct) {
            List<ObjectField> fields = struct.getFields();
            Set<String> indexedFields = new HashSet<String>();

            for (ObjectIndex index : struct.getIndexes()) {
                indexedFields.addAll(index.getFields());
            }

            for (Iterator<ObjectField> i = fields.iterator(); i.hasNext();) {
                ObjectField field = i.next();
                String declaring = field.getJavaDeclaringClassName();

                if (declaring != null &&
                        declaring.startsWith("com.psddev.dari.db.")) {
                    continue;
                }

                String fieldName = field.getInternalName();
                boolean embedded = field.isEmbedded();

                if (!embedded &&
                        ObjectField.RECORD_TYPE.equals(field.getInternalItemType())) {
                    embedded = true;

                    for (ObjectType t : field.getTypes()) {
                        if (!t.isEmbedded()) {
                            embedded = false;
                            break;
                        }
                    }
                }

                if (embedded) {
                    for (ObjectType t : field.getTypes()) {
                        addPathedFields(pathedFields, copyConcatenate(prefix, field), t);
                    }

                } else if (indexedFields.contains(fieldName) &&
                        !field.isDeprecated() &&
                        !field.as(ToolUi.class).isHidden()) {
                    pathedFields.add(new PathedField(copyConcatenate(prefix, field)));
                }
            }
        }

        private static <T> List<T> copyConcatenate(List<T> list, T item) {
            list = list != null ? new ArrayList<T>(list) : new ArrayList<T>();

            list.add(item);
            return list;
        }

        private static class PathedField implements Comparable<PathedField> {

            private final List<ObjectField> fields;
            private final String path;
            private final String displayName;

            public PathedField(List<ObjectField> fields) {
                this.fields = Collections.unmodifiableList(fields);

                StringBuilder path = new StringBuilder();

                for (ObjectField f : getFields()) {
                    path.append(f.getInternalName());
                    path.append('/');
                }

                path.setLength(path.length() - 1);

                this.path = path.toString();

                StringBuilder displayName = new StringBuilder();

                for (ObjectField f : getFields()) {
                    displayName.append(f.getDisplayName());
                    displayName.append(" \u2192 ");
                }

                displayName.setLength(displayName.length() - 3);

                this.displayName = displayName.toString();
            }

            public List<ObjectField> getFields() {
                return fields;
            }

            public String getPath() {
                return path;
            }

            public String getDisplayName() {
                return displayName;
            }

            @Override
            public int compareTo(PathedField other) {
                return getDisplayName().compareTo(other.getDisplayName());
            }

            @Override
            public int hashCode() {
                return getPath().hashCode();
            }

            @Override
            public boolean equals(Object other) {
                if (this == other) {
                    return true;

                } else if (other instanceof PathedField) {
                    return getPath().equals(((PathedField) other).getPath());

                } else {
                    return false;
                }
            }
        }

        private enum TaxonOption {
            C("Or Its Children"),
            D("Or Its Descendants");

            private final String label;

            private TaxonOption(String label) {
                this.label = label;
            }

            public String getLabel() {
                return label;
            }
        }

        private enum ComparisonOperator {

            M("Contains Text") {

                @Override
                public boolean isDisplayedFor(ObjectField field) {
                    String t = field.getInternalItemType();

                    return ObjectField.REFERENTIAL_TEXT_TYPE.equals(t) ||
                            ObjectField.TEXT_TYPE.equals(t);
                }

                @Override
                public void writeValueInputs(
                        ToolPageContext page,
                        String valueParam,
                        ObjectField field)
                        throws IOException {

                    page.writeElement("input",
                            "type", "text",
                            "name", valueParam,
                            "value", page.param(String.class, valueParam));
                }

                @Override
                public Predicate createPredicate(
                        ToolPageContext page,
                        String valueParam,
                        PathedField pathedField) {

                    return createPredicateWithOperatorAndValue(
                            pathedField,
                            "matches",
                            page.param(String.class, valueParam));
                }
            },

            I("Is") {

                @Override
                public boolean isDisplayedFor(ObjectField field) {
                    String t = field.getInternalItemType();

                    return ObjectField.NUMBER_TYPE.equals(t) ||
                            ObjectField.RECORD_TYPE.equals(t) ||
                            ObjectField.TEXT_TYPE.equals(t);
                }

                @Override
                public void writeValueInputs(
                        ToolPageContext page,
                        String valueParam,
                        ObjectField field)
                        throws IOException {

                    if (ObjectField.RECORD_TYPE.equals(field.getInternalItemType())) {
                        List<Object> selected = Query.
                                fromAll().
                                where("_id = ?", page.params(UUID.class, valueParam)).
                                selectAll();

                        if (page.isObjectSelectDropDown(field)) {
                            List<?> items = new Search(field).toQuery(page.getSite()).selectAll();

                            Collections.sort(items, new ObjectFieldComparator("_label", false));

                            page.writeStart("select",
                                    "name", valueParam,
                                    "multiple", "multiple",
                                    "data-searchable", "true");

                                for (Object item : items) {
                                    State itemState = State.getInstance(item);

                                    page.writeStart("option",
                                            "selected", selected.contains(item) ? "selected" : null,
                                            "value", itemState.getId());
                                        page.writeObjectLabel(item);
                                    page.writeEnd();
                                }
                            page.writeEnd();

                        } else {
                            if (selected.isEmpty()) {
                                selected.add(null);
                            }

                            String taxonParam = valueParam + "x";
                            List<TaxonOption> taxonOptions = page.params(TaxonOption.class, taxonParam);
                            boolean taxon = false;

                            for (ObjectType t : field.getTypes()) {
                                if (t.getGroups().contains(Taxon.class.getName())) {
                                    taxon = true;
                                    break;
                                }
                            }

                            page.writeStart("div",
                                    "class", "repeatableObjectId",
                                    "style", "overflow:hidden;");

                                page.writeStart("ul");
                                    for (int i = 0, size = selected.size(); i < size; ++ i) {
                                        Object item = selected.get(i);

                                        page.writeStart("li");
                                            page.writeObjectSelect(
                                                    field,
                                                    item,
                                                    "name", valueParam);

                                            if (taxon) {
                                                TaxonOption taxonOption = i < taxonOptions.size() ? taxonOptions.get(i) : null;

                                                page.writeHtml(" ");
                                                page.writeStart("select",
                                                        "name", taxonParam);
                                                    page.writeStart("option");
                                                        page.writeHtml("Only");
                                                    page.writeEnd();

                                                    for (TaxonOption o : TaxonOption.values()) {
                                                        page.writeStart("option",
                                                                "selected", o.equals(taxonOption) ? "selected" : null,
                                                                "value", o.name());
                                                            page.writeHtml(o.getLabel());
                                                        page.writeEnd();
                                                    }
                                                page.writeEnd();
                                            }
                                        page.writeEnd();
                                    }

                                    page.writeStart("script", "type", "text/template");
                                        page.writeStart("li");
                                            page.writeObjectSelect(
                                                    field,
                                                    null,
                                                    "name", valueParam);

                                            if (taxon) {
                                                page.writeHtml(" ");
                                                page.writeStart("select",
                                                        "name", taxonParam);
                                                    page.writeStart("option");
                                                        page.writeHtml("Only");
                                                    page.writeEnd();

                                                    for (TaxonOption o : TaxonOption.values()) {
                                                        page.writeStart("option", "value", o.name());
                                                            page.writeHtml(o.getLabel());
                                                        page.writeEnd();
                                                    }
                                                page.writeEnd();
                                            }
                                        page.writeEnd();
                                    page.writeEnd();
                                page.writeEnd();
                            page.writeEnd();
                        }

                    } else {
                        page.writeElement("input",
                                "type", "text",
                                "name", valueParam,
                                "value", page.param(String.class, valueParam));
                    }
                }

                @Override
                public Predicate createPredicate(
                        ToolPageContext page,
                        String valueParam,
                        PathedField pathedField) {

                    TaxonOption taxonOption = page.param(TaxonOption.class, valueParam + "x");

                    if (taxonOption != null) {
                        Taxon top = Query.from(Taxon.class).where("_id = ?", page.param(UUID.class, valueParam)).first();
                        Set<UUID> values = new HashSet<UUID>();

                        if (top != null) {
                            values.add(top.getState().getId());

                            if (taxonOption.equals(TaxonOption.D)) {
                                addChildren(values, top);

                            } else {
                                for (Taxon c : top.getChildren()) {
                                    values.add(c.getState().getId());
                                }
                            }
                        }

                        return createPredicateWithOperatorAndValue(
                                pathedField,
                                "=",
                                values);

                    } else {
                        return createPredicateWithOperatorAndValue(
                                pathedField,
                                "=",
                                page.params(String.class, valueParam));
                    }
                }

                private void addChildren(Set<UUID> values, Taxon parent) {
                    for (Taxon c : parent.getChildren()) {
                        values.add(c.getState().getId());
                        addChildren(values, c);
                    }
                }
            },

            N("Is Not") {

                @Override
                public boolean isDisplayedFor(ObjectField field) {
                    return I.isDisplayedFor(field);
                }

                @Override
                public void writeValueInputs(
                        ToolPageContext page,
                        String valueParam,
                        ObjectField field)
                        throws IOException {
                    I.writeValueInputs(page, valueParam, field);
                }

                @Override
                public Predicate createPredicate(
                        ToolPageContext page,
                        String valueParam,
                        PathedField pathedField) {

                    return createPredicateWithOperatorAndValue(
                            pathedField,
                            "!=",
                            page.param(String.class, valueParam));
                }
            },

            T("Is Set") {

                @Override
                public boolean isDisplayedFor(ObjectField field) {
                    return ObjectField.BOOLEAN_TYPE.equals(field.getInternalType());
                }

                @Override
                public void writeValueInputs(
                        ToolPageContext page,
                        String valueParam,
                        ObjectField field)
                        throws IOException {
                }

                @Override
                public Predicate createPredicate(
                        ToolPageContext page,
                        String valueParam,
                        PathedField pathedField) {

                    return createPredicateWithOperatorAndValue(
                            pathedField,
                            "=",
                            Boolean.TRUE);
                }
            },

            F("Is Not Set") {

                @Override
                public boolean isDisplayedFor(ObjectField field) {
                    return T.isDisplayedFor(field);
                }

                @Override
                public void writeValueInputs(
                        ToolPageContext page,
                        String valueParam,
                        ObjectField field)
                        throws IOException {
                }

                @Override
                public Predicate createPredicate(
                        ToolPageContext page,
                        String valueParam,
                        PathedField pathedField) {

                    return createPredicateWithOperatorAndValue(
                            pathedField,
                            "!=",
                            Boolean.TRUE);
                }
            },

            S("Is Missing") {

                @Override
                public boolean isDisplayedFor(ObjectField field) {
                    return !ObjectField.BOOLEAN_TYPE.equals(field.getInternalType());
                }

                @Override
                public void writeValueInputs(
                        ToolPageContext page,
                        String valueParam,
                        ObjectField field)
                        throws IOException {
                }

                @Override
                public Predicate createPredicate(
                        ToolPageContext page,
                        String valueParam,
                        PathedField pathedField) {

                    return createPredicateWithOperatorAndValue(
                            pathedField,
                            "=",
                            Query.MISSING_VALUE);
                }
            },

            G("Is Not Missing") {

                @Override
                public boolean isDisplayedFor(ObjectField field) {
                    return S.isDisplayedFor(field);
                }

                @Override
                public void writeValueInputs(
                        ToolPageContext page,
                        String valueParam,
                        ObjectField field)
                        throws IOException {
                }

                @Override
                public Predicate createPredicate(
                        ToolPageContext page,
                        String valueParam,
                        PathedField pathedField) {

                    return createPredicateWithOperatorAndValue(
                            pathedField,
                            "!=",
                            Query.MISSING_VALUE);
                }
            },

            B("Between") {

                @Override
                public boolean isDisplayedFor(ObjectField field) {
                    String t = field.getInternalItemType();

                    return ObjectField.DATE_TYPE.equals(t) ||
                            ObjectField.NUMBER_TYPE.equals(t);
                }

                @Override
                public void writeValueInputs(
                        ToolPageContext page,
                        String valueParam,
                        ObjectField field)
                        throws IOException {

                    boolean date = ObjectField.DATE_TYPE.equals(field.getInternalItemType());
                    String valueToParam = valueParam + "t";

                    page.writeElement("input",
                            "type", "text",
                            "class", date ? "date" : null,
                            "name", valueParam,
                            "value", page.param(String.class, valueParam));

                    page.writeHtml(" ");
                    page.writeElement("input",
                            "type", "text",
                            "class", date ? "date" : null,
                            "name", valueToParam,
                            "value", page.param(String.class, valueToParam));
                }

                @Override
                public Predicate createPredicate(
                        ToolPageContext page,
                        String valueParam,
                        PathedField pathedField) {

                    List<ObjectField> fields = pathedField.getFields();
                    boolean date = ObjectField.DATE_TYPE.equals(fields.get(fields.size() - 1).getInternalItemType());
                    Object from = page.param(date ? Date.class : Double.class, valueParam);
                    Object to = page.param(date ? Date.class : Double.class, valueParam + "t");

                    return CompoundPredicate.combine(
                            "AND",
                            from == null ? null : createPredicateWithOperatorAndValue(pathedField, ">=", from),
                            to == null ? null : createPredicateWithOperatorAndValue(pathedField, "<=", to));
                }
            };

            private final String label;

            private ComparisonOperator(String label) {
                this.label = label;
            }

            public abstract boolean isDisplayedFor(ObjectField field);

            public abstract void writeValueInputs(
                    ToolPageContext page,
                    String valueParam,
                    ObjectField field)
                    throws IOException;

            public abstract Predicate createPredicate(
                    ToolPageContext page,
                    String valueParam,
                    PathedField pathedField);

            public String getLabel() {
                return label;
            }

            public Predicate createPredicateWithOperatorAndValue(
                    PathedField pathedField,
                    String operator,
                    Object value) {

                if (value == null) {
                    return null;

                } else {
                    StringBuilder key = new StringBuilder();

                    if (pathedField == null) {
                        key.append("_any");

                    } else {
                        for (ObjectField f : pathedField.getFields()) {
                            if (key.length() == 0) {
                                key.append(f.getUniqueName());

                            } else {
                                key.append('/');
                                key.append(f.getInternalName());
                            }
                        }
                    }

                    return new ComparisonPredicate(
                            operator,
                            false,
                            key.toString(),
                            value instanceof Iterable ? (Iterable<?>) value : Arrays.asList(value));
                }
            }
        }
    }
}
TOP

Related Classes of com.psddev.cms.tool.page.SearchAdvancedPredicate

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.