Source: src/js/collections/queryFields/QueryFields.js

define([
  "jquery",
  "underscore",
  "backbone",
  "x2js",
  "models/queryFields/QueryField",
], function ($, _, Backbone, X2JS, QueryField) {
  "use strict";

  /**
   * @class QueryFields
   * @classdesc The collection of queryable fields supported by the the
   * DataONE Solr index, as provided by the DataONE API
   * CNRead.getQueryEngineDescription() function. For more information, see:
   * https://indexer-documentation.readthedocs.io/en/latest/generated/solr_schema.html
   * https://dataone-architecture-documentation.readthedocs.io/en/latest/design/SearchMetadata.html
   * @classcategory Collections/QueryFields
   * @name QueryFields
   * @extends Backbone.Collection
   * @since 2.14.0
   * @constructor
   */
  var QueryFields = Backbone.Collection.extend(
    /** @lends QueryFields.prototype */
    {
      /**
       * The type of Backbone model that this collection comprises
       */
      model: QueryField,

      /**
       * initialize - Creates a new QueryFields collection
       */
      initialize: function (models, options) {
        try {
          if (typeof options === "undefined") {
            var options = {};
          }
        } catch (e) {
          console.log(
            "Failed to initialize a Query Fields collection, error message: " +
              e,
          );
        }
      },

      /**
       * comparator - A sortBy function that returns the order of each Query
       * Filter model based on its position in the categoriesMap object.
       *
       * @param  {QueryFilter} model The individual Query Filter model
       * @return {number}      A numeric value by which the model should be ordered relative to others.
       */
      comparator: function (model) {
        try {
          var categoriesMap = model.categoriesMap();
          var order = _(categoriesMap)
            .chain()
            .pluck("queryFields")
            .flatten()
            .value();
          return order.indexOf(model.get("name"));
        } catch (e) {
          console.log(
            "Failed to sort the Query Fields Collection, error message: " + e,
          );
          return 0;
        }
      },

      /**
       * The constructed URL of the collection
       *
       * @returns {string} - The URL to use during fetch
       */
      url: function () {
        try {
          return MetacatUI.appModel.get("queryServiceUrl").replace(/\/\?$/, "");
        } catch (e) {
          return "https://cn.dataone.org/cn/v2/query/solr";
        }
      },

      /**
       * Retrieve the fields from the Coordinating Node
       * @extends Backbone.Collection#fetch
       */
      fetch: function (options) {
        try {
          var fetchOptions = _.extend({ dataType: "text" }, options);
          return Backbone.Model.prototype.fetch.call(this, fetchOptions);
        } catch (e) {
          console.log("Failed to fetch Query Fields, error message: " + e);
        }
      },

      /**
       * parse - Parse the XML response from the CN
       *
       * @param  {string} response The queryEngineDescription XML as a string
       * @return {Array}  the Array of Query Field attributes to be added to the collection.
       */
      parse: function (response) {
        try {
          // If the collection is already parsed, just return it
          if (typeof response === "object") {
            return response;
          }
          var x2js = new X2JS();
          var responseJSON = x2js.xml_str2json(response);
          if (responseJSON && responseJSON.queryEngineDescription) {
            return responseJSON.queryEngineDescription.queryField;
          }
        } catch (e) {
          console.log(
            "Failed to parse Query Fields response, error message: " + e,
          );
        }
      },

      /**
       * getRequiredFilterType - Based on an array of query (Solr) field names, get the
       * type of filter model to use with these fields. For example, if the fields are
       * type text, use a regular filter model. If the fields are tdate, use a
       * dateFilter. If the field types are mixed, then returns the filterType default
       * value in QueryField models.
       *
       * @param  {string[]} fields The list of Query Field names
       * @return {string} The nodeName of the filter model to use (one of the four types
       * of fields that are set in {@link QueryField#filterTypesMap})
       */
      getRequiredFilterType: function (fields) {
        try {
          var types = [],
            // When fields is empty or are different types
            defaultFilterType =
              MetacatUI.queryFields.models[0].defaults().filterType;

          if (!fields || fields.length === 0 || fields[0] === "") {
            return defaultFilterType;
          }

          fields.forEach((newField, i) => {
            var fieldModel = MetacatUI.queryFields.findWhere({
              name: newField,
            });
            types.push(fieldModel.get("filterType"));
          });

          // Test of all the fields are of the same type
          var allEqual = types.every((val, i, arr) => val === arr[0]);

          if (allEqual) {
            return types[0];
          } else {
            return defaultFilterType;
          }
        } catch (e) {
          console.log(
            "Failed to detect the required filter type in a Query Fields" +
              " Collection, error message: " +
              e,
          );
        }
      },
    },
  );
  return QueryFields;
});