text: // Copyright 2013 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef UI_APP_LIST_SEARCH_MIXER_H_
  #define UI_APP_LIST_SEARCH_MIXER_H_
  
  #include <stddef.h>
  
  #include <vector>
  
  #include "base/gtest_prod_util.h"
  #include "base/macros.h"
  #include "base/memory/scoped_vector.h"
  #include "ui/app_list/app_list_export.h"
  #include "ui/app_list/app_list_model.h"
  #include "ui/app_list/search/history_types.h"
  
  namespace app_list {
  
  namespace test {
  FORWARD_DECLARE_TEST(MixerTest, Publish);
  }
  
  class SearchProvider;
  class SearchResult;
  
  // Mixer collects results from providers, sorts them and publishes them to the
  // SearchResults UI model. The targeted results have 6 slots to hold the
  // result. The search controller can specify any number of groups, each with a
  // different number of results and priority boost. The "omnibox" group is
  // expected to contain omnibox results, and will be treated specially.
  class APP_LIST_EXPORT Mixer {
   public:
    explicit Mixer(AppListModel::SearchResults* ui_results);
    ~Mixer();
  
    // Adds a new mixer group. A maximum of |max_results| results will be
    // displayed from this group (if 0, will allow unlimited results from this
    // group). Behaviour depends on the AppListMixer field trial:
    // - If default: Each result in the group will have its score boosted by
    //   |boost|. |multiplier| is ignored.
    // - If "Blended": |max_results| is a "soft" maximum; if there aren't enough
    //   results from all groups, more than |max_results| may be chosen from this
    //   group. Each result in the group will have its score multiplied by
    //   |multiplier|. |boost| is ignored.
    // Returns the group's group_id.
    size_t AddGroup(size_t max_results, double boost, double multiplier);
  
    // Adds a new mixer group for the special "omnibox" group. This group will be
    // treated specially by the Mixer (it will be truncated such that it fills the
    // remaining slots without overflowing, but with at least one result). A
    // maximum of one group should be added using this method.
    size_t AddOmniboxGroup(size_t max_results, double boost, double multiplier);
  
    // Associates a provider with a mixer group.
    void AddProviderToGroup(size_t group_id, SearchProvider* provider);
  
    // Collects the results, sorts and publishes them.
    void MixAndPublish(bool is_voice_query, const KnownResults& known_results);
  
   private:
    FRIEND_TEST_ALL_PREFIXES(test::MixerTest, Publish);
  
    // Used for sorting and mixing results.
    struct APP_LIST_EXPORT SortData {
      SortData();
      SortData(SearchResult* result, double score);
  
      bool operator<(const SortData& other) const;
  
      SearchResult* result;  // Not owned.
      double score;
    };
    typedef std::vector<Mixer::SortData> SortedResults;
  
    class Group;
    typedef ScopedVector<Group> Groups;
  
    // Publishes the given |new_results| to |ui_results|, deleting any existing
    // results that are not in |new_results|. Results that already exist in
    // |ui_results| are reused to avoid flickering caused by icon reload.
    static void Publish(const SortedResults& results,
                        AppListModel::SearchResults* ui_results);
  
    // Removes entries from |results| with duplicate IDs. When two or more results
    // have the same ID, the earliest one in the |results| list is kept.
    // NOTE: This is not necessarily the one with the highest *score*, as
    // |results| may not have been sorted yet.
    static void RemoveDuplicates(SortedResults* results);
  
    void FetchResults(bool is_voice_query, const KnownResults& known_results);
  
    AppListModel::SearchResults* ui_results_;  // Not owned.
    Groups groups_;
  
    // The ID of the omnibox group. The group with this ID will be treated
    // specially by the Mixer. Ignored if the AppListMixer field trial is
    // "Blended".
    // TODO(mgiuca): Remove this after the field trial is complete.
    size_t omnibox_group_ = 0;
    // Whether |omnibox_group_| has been set.
    bool has_omnibox_group_ = false;
  
    DISALLOW_COPY_AND_ASSIGN(Mixer);
  };
  
  }  // namespace app_list
  
  #endif  // UI_APP_LIST_SEARCH_MIXER_H_
  