//! The crate aims to provide an easy to use wrapper around the GNOME Shell Search Provider DBus interface.
//!
//! - [Writing a Search Provider tutorial](https://developer.gnome.org/documentation/tutorials/search-provider.html)
//!
//!
//! # How to use
//!
//! - [Register a new search provider](https://developer.gnome.org/documentation/tutorials/search-provider.html#registering-a-new-search-provider)
//! - Implement the [`SearchProviderImpl`] trait for the struct that holds your Application.
//! - Once the application is installed, enable it in GNOME Settings -> Search.
//!
//! ```
//! use search_provider::{ResultID, ResultMeta, SearchProviderImpl};
//! use std::collections::HashMap;
//!
//! #[derive(Debug)]
//! struct Application {
//!     results: HashMap<String, String>,
//! }
//! impl SearchProviderImpl for Application {
//!     fn activate_result(&self, identifier: ResultID, terms: &[String], timestamp: u32) {
//!         let result = self.results.get(&identifier);
//!         println!(
//!             "activating result {:#?} identified by {}",
//!             result, identifier
//!         );
//!     }
//!
//!     fn initial_result_set(&self, terms: &[String]) -> Vec<ResultID> {
//!         // Here do your search logic
//!         if terms.contains(&"some_value".to_owned()) {
//!             vec!["some_key".to_owned()]
//!         } else {
//!             vec![]
//!         }
//!     }
//!
//!     fn result_metas(&self, identifiers: &[ResultID]) -> Vec<ResultMeta> {
//!         self.results
//!             .iter()
//!             .map(|(identifier, value)| {
//!                 ResultMeta::builder(identifier.to_owned(), "Some name")
//!                     .description("Some description of the current identifier")
//!                     .build()
//!             })
//!             .collect::<Vec<_>>()
//!     }
//! }
//! ```
//!
//! - Create an instance of [`SearchProvider`]
//!
//! ```ignore
//! use search_provider::SearchProvider;
//! use std::collections::HashMap;
//!
//! async fn main_entry() -> zbus::Result<()> {
//!     let mut results = HashMap::new();
//!     results.insert("some_key".to_string(), "some_value".to_string());
//!     let app = Application { results };
//!     let provider = SearchProvider::new(
//!         app,
//!         "org.gnome.design.IconLibrary.SearchProvider",
//!         "/org/gnome/design/IconLibrary/SearchProvider",
//!     )
//!     .await?;
//!     Ok(())
//! }
//! ```

mod search_provider;
pub use crate::search_provider::SearchProvider;

mod result_metadata;
pub use crate::result_metadata::{IconData, ResultMeta, ResultMetaBuilder};

/// A result identifier.
pub type ResultID = String;

/// A trait to implement to communicate with the search provider
/// interface.
pub trait SearchProviderImpl {
    /// The method is called when a user clicks on an individual search result
    /// to open it in the application.
    ///
    /// # Arguments
    ///
    /// * `identifier` - the result ID.
    /// * `terms` - current search terms.
    /// * `timestamp` - current timestamp.
    fn activate_result(&self, identifier: ResultID, terms: &[String], timestamp: u32);

    /// The method is called when a new search is started.
    ///
    /// # Arguments
    ///
    /// * `terms` - current search terms.
    /// * `timestamp` - current timestamp.
    ///
    /// # Returns
    ///
    /// A list of search results IDs. GNOME Shell, will call [`result_metas()`](SearchProviderImpl::result_metas`)
    /// on some of those IDs to retrieve the corresponding [`ResultMeta`].
    #[doc(alias = "get_initial_result_set")]
    fn initial_result_set(&self, terms: &[String]) -> Vec<ResultID>;

    /// The method is called to refine the initial search results when more characters were typed
    /// in the search entry.
    ///
    /// # Arguments
    ///
    /// * `previous_results` - list of results ID returned by a previous call to [`initial_result_set()`](SearchProviderImpl::initial_result_set`).
    /// * `terms` - current search terms.
    ///
    /// # Returns
    ///
    /// A list of search results IDs. GNOME Shell, will call [`result_metas()`](SearchProviderImpl::result_metas`)
    /// on some of those IDs to retrieve the corresponding [`ResultMeta`].
    ///
    /// By default the method calls [`initial_result_set()`](SearchProviderImpl::initial_result_set`).
    #[doc(alias = "get_subsearch_result_set")]
    fn subsearch_result_set(
        &self,
        _previous_results: &[ResultID],
        terms: &[String],
    ) -> Vec<ResultID> {
        self.initial_result_set(terms)
    }

    /// The method is called to obtain detailed information of the results.
    ///
    /// # Arguments
    ///
    /// * `identifiers` - search result IDs.
    ///
    /// # Returns
    ///
    /// A list of their corresponding [`ResultMeta`], see [`ResultMeta::builder`] on how to construct one.
    #[doc(alias = "get_result_metas")]
    fn result_metas(&self, identifiers: &[ResultID]) -> Vec<ResultMeta>;

    /// The method is called when a user clicks on the provider icon to
    /// display more search results in the application.
    ///
    /// # Arguments
    ///
    /// * `terms` - current search terms.
    /// * `timestamp` - current timestamp.
    ///
    /// By default the method does nothing.
    fn launch_search(&self, _terms: &[String], _timestamp: u32) {}
}
