/*
 * Copyright (c) 2010-2022 Belledonne Communications SARL.
 *
 * This file is part of Liblinphone 
 * (see https://gitlab.linphone.org/BC/public/liblinphone).
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _MSC_VER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif // _MSC_VER

#ifndef _MAGIC_SEARCH_HH
#define _MAGIC_SEARCH_HH

#include <string>
#include <list>
#include "magic_search.hh"
#include "object.hh"




struct _LinphoneMagicSearch;


namespace linphone {

	class SearchResult;
	class MagicSearchListener;

	/**
	 * @brief A @ref MagicSearch is used to search for contacts from various sources: 
	 *
	 */
	class MagicSearch: public MultiListenableObject {
	
		public:
			/**
			* Enum describing how to merge @ref SearchResult from @ref MagicSearch. 
			*
			*/
			enum class Aggregation {
				/**
				* No aggregation is done, you can have multiple SearchResult with the same
				* Friend. 
				*/
				None = 0,
				/**
				* Aggregation is done by friend, you will have at most a SearchResult per Friend. 
				*/
				Friend = 1
			};

			/**
			* Enum describing the search categories for Magic Search. 
			*
			*/
			enum class Source {
				/**
				* no Source specified. 
				*/
				None = 0,
				/**
				* Search in friends only. 
				*/
				Friends = 1<<0,
				/**
				* Search in Call Logs. 
				*/
				CallLogs = 1<<1,
				/**
				* Search in LDAP servers. 
				*/
				LdapServers = 1<<2,
				/**
				* Search in Chat rooms participants. 
				*/
				ChatRooms = 1<<3,
				/**
				* Search from request : it is usually an address built from the request. 
				*/
				Request = 1<<4,
				/**
				* Search in "starred" friends only. 
				*/
				FavoriteFriends = 1<<5,
				/**
				* Search in conferences info (organizer and participants). 
				*/
				ConferencesInfo = 1<<6,
				/**
				* Search in remote CardDAV servers (not locally synched ones) if any. 
				*/
				RemoteCardDAV = 1<<7,
				/**
				* Search in all sources. 
				*/
				All = -1
			};


			LINPHONECXX_PUBLIC MagicSearch(void *ptr, bool takeRef=true);
			LINPHONECXX_PUBLIC _LinphoneMagicSearch *cPtr() {return (_LinphoneMagicSearch *)mPrivPtr;}

			/**
			 * @brief Add an application listener to the MagicSearch instance.
			 *
			 * @param listener the application listener
			 */
			LINPHONECXX_PUBLIC void addListener(const std::shared_ptr<MagicSearchListener> &listener);
			/**
			 * @brief Remove a previously added listener from the MagicSearch instance.
			 *
			 * @param listener the application listener
			 */
			LINPHONECXX_PUBLIC void removeListener(const std::shared_ptr<MagicSearchListener> &listener);
	
		public:
			
		
			/**
			 * @brief Get the delimiter used for the search. 
			 *
			 * @return the delimiter used to find matched filter word    
			 */
			LINPHONECXX_PUBLIC std::string getDelimiter() const;
			
			/**
			 * @brief Set the delimiter used to find matched filter word. 
			 *
			 * @param delimiter delimiter (example "-_.,")    
			 */
			LINPHONECXX_PUBLIC void setDelimiter(const std::string & delimiter);
			
			/**
			 *
			 * @return sorted list of         
			 */
			LINPHONECXX_PUBLIC std::list<std::shared_ptr<linphone::SearchResult>> getLastSearch() const;
			
			/**
			 * @brief Returns whether or not the search is limited or not. 
			 *
			 * If not limited, the getSearchLimit() won't be applied. 
			 * @return true if the search is limited, false otherwise 
			 */
			LINPHONECXX_PUBLIC bool getLimitedSearch() const;
			
			/**
			 * @brief Enables or disables the limited search. 
			 *
			 * Even if configured as unlimited, the LDAP maxResults configuration parameter
			 * still applies. 
			 * @param limited true to limit the search, false otherwise 
			 */
			LINPHONECXX_PUBLIC void setLimitedSearch(bool limited);
			
			/**
			 * @brief Get the maximum value used to calculate the weight in search. 
			 *
			 * @return the maximum value used to calculate the weight in search 
			 */
			LINPHONECXX_PUBLIC unsigned int getMaxWeight() const;
			
			/**
			 * @brief Set the maximum value used to calculate the weight in search. 
			 *
			 * @param weight maximum weight 
			 */
			LINPHONECXX_PUBLIC void setMaxWeight(unsigned int weight);
			
			/**
			 * @brief Get the minimum value used to calculate the weight in search. 
			 *
			 * @return the minimum value used to calculate the weight in search 
			 */
			LINPHONECXX_PUBLIC unsigned int getMinWeight() const;
			
			/**
			 * @brief Set the minimum value used to calculate the weight in search. 
			 *
			 * @param weight minimum weight 
			 */
			LINPHONECXX_PUBLIC void setMinWeight(unsigned int weight);
			
			/**
			 * @brief Gets the number of maximum search result the search will return. 
			 *
			 * The returned value doesn't take into account the "limited search" mode, so make
			 * sure to check getLimitedSearch() result as well. 
			 * @return the number of the maximum @ref SearchResult which will be returned if
			 * magic search is in limited mode. 
			 */
			LINPHONECXX_PUBLIC unsigned int getSearchLimit() const;
			
			/**
			 * @brief Sets the number of the maximum SearchResult which will be returned, if
			 * the magic search isn't configured as unlimited with setLimitedSearch(). 
			 *
			 * @param limit the maximum number of @ref SearchResult the search will return if
			 * magic search is in limited mode. 
			 */
			LINPHONECXX_PUBLIC void setSearchLimit(unsigned int limit);
			
			/**
			 * @brief Returns whether the delimiter is being used for the search. 
			 *
			 * @return if the delimiter search is used 
			 */
			LINPHONECXX_PUBLIC bool getUseDelimiter();
			
			/**
			 * @brief Enable or disable the delimiter in search. 
			 *
			 * @param enable true to use the delimiter, false otherwise 
			 */
			LINPHONECXX_PUBLIC void setUseDelimiter(bool enable);
			
			/**
			 * @brief Create a sorted list of SearchResult which match with a filter word,
			 * from SipUri in this order : Contact's display name, address username, address
			 * domain and phone number. 
			 *
			 * The last item list will be an address formed with "filter" if a proxy config
			 * exist and requested in sourceFlags During the first search, a cache is created
			 * and used for the next search Use resetSearchCache() to begin a new search 
			 * @param filter word we search    
			 * @param domain domain which we want to search only   
			 * @param sourceFlags Flags that specify where to search : @ref Source 
			 * @param aggregation a @ref Aggregation mode to indicate how to merge results 
			 * @return sorted list of         
			 */
			LINPHONECXX_PUBLIC std::list<std::shared_ptr<linphone::SearchResult>> getContactsList(const std::string & filter, const std::string & domain, int sourceFlags, Aggregation aggregation);
			
			/**
			 * @brief This is the asynchronous version of
			 * linphone_magic_search_get_contacts(). 
			 *
			 * Create a sorted list of SearchResult which match with a filter word, from
			 * SipUri in this order : Contact's display name, address username, address domain
			 * and phone number. The last item list will be an address formed with "filter" if
			 * a proxy config exist and requested in sourceFlags During the first search, a
			 * cache is created and used for the next search Use resetSearchCache() to begin a
			 * new search 
			 * @param filter word we search    
			 * @param domain domain which we want to search only   
			 * @param sourceFlags Flags that specify where to search : @ref Source 
			 * @param aggregation a @ref Aggregation mode to indicate how to merge results 
			 */
			LINPHONECXX_PUBLIC void getContactsListAsync(const std::string & filter, const std::string & domain, int sourceFlags, Aggregation aggregation);
			
			/**
			 * @brief Reset the cache to begin a new search. 
			 *
			 */
			LINPHONECXX_PUBLIC void resetSearchCache();
			
			
		private:
			void *createCallbacks() override;
	};

};

#endif // _MAGIC_SEARCH_HH

#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif // _MSC_VER
