Source: src/js/models/connectors/Filters-Search.js

define([
  "backbone",
  "collections/Filters",
  "collections/SolrResults",
], function (Backbone, Filters, SearchResults) {
  "use strict";

  /**
   * @class FiltersSearchConnector
   * @name FiltersSearchConnector
   * @classdesc A model that creates listeners between a Filters collection and
   * a SearchResults. It does not assume anything about how the search results
   * or filters will be displayed in the UI or why those components need to be
   * connected. It simply sends a new search when the filters have been changed.
   * @name FiltersSearchConnector
   * @extends Backbone.Model
   * @constructor
   * @classcategory Models/Connectors
   */
  return Backbone.Model.extend(
    /** @lends FiltersSearchConnector.prototype */ {
      /**
       * The type of Backbone.Model this is.
       * @type {string}
       * @since 2.25.0
       * @default "FiltersSearchConnector
       */
      type: "FiltersSearchConnector",

      /**
       * @type {object}
       * @property {Filters} filters A Filters collection to use for this search
       * @property {SolrResults} searchResults The SolrResults collection that
       * the search results will be stored in
       * @property {boolean} isConnected Whether or not the model has listeners
       * set between the Filters and SearchResults. Set this with the
       * connect and disconnect methods.
       */
      defaults: function () {
        return {
          filters: new Filters([], { catalogSearch: true }),
          searchResults: new SearchResults(),
          isConnected: false,
        };
      },

      /**
       * Sets listeners on the Filters and SearchResults to trigger a search
       * when the search changes
       * @since 2.22.0
       */
      connect: function () {
        this.disconnect();
        const filters = this.get("filters");
        const search = this.get("searchResults");

        // Start results at first page and recreate query when the filters change
        this.listenTo(filters, "update change", () => this.triggerSearch());

        // "changing" event triggers when the query is about to change, but
        // before it has been sent. Useful for showing a loading indicator.
        this.listenTo(filters, "changing", function () {
          search.trigger("changing");
        });

        this.listenTo(search, "change:sort change:facet", () =>
          this.triggerSearch(),
        );

        // If the logged-in status changes, send a new search
        this.listenTo(MetacatUI.appUserModel, "change:loggedIn", () =>
          this.triggerSearch(),
        );

        this.set("isConnected", true);
      },

      /**
       * Stops listening to changes in the Filters and SearchResults
       * @since 2.25.0
       */
      disconnect: function () {
        const filters = this.get("filters");
        const searchResults = this.get("searchResults");
        this.stopListening(MetacatUI.appUserModel, "change:loggedIn");
        this.stopListening(filters, "update changing");
        this.stopListening(searchResults, "change:sort change:facet");
        this.set("isConnected", false);
      },

      /**
       * Get Results from the Solr index by combining the Filter query string
       * fragments in each Filter instance in the Search collection and querying
       * Solr.
       * @param {boolean} resetPage - Whether or not to reset the page number
       * to 0. Defaults to false.
       * @fires SolrResults#toPage
       * @since 2.22.0
       */
      triggerSearch: function (resetPage = false) {
        if (resetPage) MetacatUI.appModel.set("page", 0);

        const filters = this.get("filters");
        const searchResults = this.get("searchResults");

        // Get the Solr query string from the Search filter collection
        let query = filters.getQuery();

        // Set the query on the SolrResults collection
        searchResults.setQuery(query);

        // If the query hasn't changed since the last query that was sent, don't
        // do anything. This function may have been triggered by a change event
        // on a filter that doesn't affect the query at all
        if (!searchResults.hasChanged()) {
          // Trigger a reset event to indicate the search is complete (e.g. for
          // the UI)
          searchResults.trigger("reset");
          return;
        }

        // Get the page number
        let page = MetacatUI.appModel.get("page") || 0;
        searchResults.start = page * searchResults.rows;

        // Send the query to the server via the SolrResults collection
        searchResults.toPage(page);
      },
    },
  );
});