/*
Copyright (C) 2017 Belledonne Communications SARL

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef _LINPHONE_ACCOUNT_HH
#define _LINPHONE_ACCOUNT_HH

#include <string>
#include "enums.hh"
#include "object.hh"




struct _LinphoneAccount;


namespace linphone {

	class Address;
	class Core;
	class Account;
	class ErrorInfo;
	class AccountParams;
	class ProxyConfig;
	class AuthInfo;
	class AccountListener;

	/**
	 * @brief Object that represents a Linphone Account. 
	 *
	 * This object replaces the deprecated @ref ProxyConfig. Use a @ref AccountParams
	 * object to configure it. 
	 */
	class Account: public MultiListenableObject {
	
		public:

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

			LINPHONECXX_PUBLIC void addListener(const std::shared_ptr<AccountListener> &listener);
			LINPHONECXX_PUBLIC void removeListener(const std::shared_ptr<AccountListener> &listener);
	
		public:
			
		
			/**
			 * @brief Return the contact address of the account. 
			 *
			 * @return a @ref Address correspong to the contact address of the account.   
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<linphone::Address> getContactAddress();
			
			/**
			 * @brief Get the @ref Core object to which is associated the @ref Account. 
			 *
			 * @return The @ref Core object to which is associated the @ref Account.   
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<linphone::Core> getCore();
			
			/**
			 * @brief Get the dependency of a @ref Account. 
			 *
			 * @return The account this one is dependent upon, or nullptr if not marked
			 * dependent.   
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<linphone::Account> getDependency();
			
			/**
			 * @brief Mark this account as being dependent on the given one. 
			 *
			 * The dependency must refer to an account previously added to the core and which
			 * idkey property is defined.
			 * @see AccountParams::setIdkey()
			 * The account marked as dependent will wait for successful registration on its
			 * dependency before triggering its own.
			 * Once registered, both accounts will share the same contact address (the
			 * 'dependency' one).
			 * This mecanism must be enabled before the account is added to the core
			 * @param dependsOn The @ref Account this one shall be depending on.   
			 */
			LINPHONECXX_PUBLIC void setDependency(const std::shared_ptr<linphone::Account> & dependsOn);
			
			/**
			 * @brief Get the reason why registration failed when the account state is
			 * LinphoneRegistrationFailed. 
			 *
			 * @return The @ref Reason why registration failed for this account. 
			 */
			LINPHONECXX_PUBLIC linphone::Reason getError();
			
			/**
			 * @brief Get detailed information why registration failed when the account state
			 * is LinphoneRegistrationFailed. 
			 *
			 * @return The @ref ErrorInfo explaining why registration failed for this account.
			 *   
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<linphone::ErrorInfo> getErrorInfo();
			
			/**
			 * @brief Indicates whether AVPF/SAVPF is being used for calls using this account. 
			 *
			 * @return true if AVPF/SAVPF is enabled, false otherwise. 
			 */
			LINPHONECXX_PUBLIC bool isAvpfEnabled();
			
			/**
			 * @brief Get the @ref AccountParams as read-only object. 
			 *
			 * To make changes, clone the returned object using AccountParams::clone() method,
			 * make your changes on it and apply them using with setParams(). 
			 * @return The @ref AccountParams attached to this account.   
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<const linphone::AccountParams> getParams();
			
			/**
			 * @brief Set the @ref AccountParams used by this @ref Account. 
			 *
			 * @param params The @ref AccountParams object.   
			 */
			LINPHONECXX_PUBLIC int setParams(const std::shared_ptr<linphone::AccountParams> & params);
			
			/**
			 * @brief Get the registration state of the given account. 
			 *
			 * @return The @ref RegistrationState of the account. 
			 */
			LINPHONECXX_PUBLIC linphone::RegistrationState getState();
			
			/**
			 * @brief Get the transport from either service route, route or addr. 
			 *
			 * @return The transport as a string (I.E udp, tcp, tls, dtls). 
			 * @deprecated 01/03/2021 Use Linphone_account_params_get_transport() instead. 
			 */
			LINPHONECXX_PUBLIC LINPHONECXX_DEPRECATED linphone::TransportType getTransport();
			
			/**
			 * @brief Return the unread chat message count for a given account. 
			 *
			 * @return The unread chat message count. 
			 */
			LINPHONECXX_PUBLIC int getUnreadChatMessageCount();
			
			/**
			 * @brief Instantiate a new account with values from source. 
			 *
			 * @return The newly created @ref Account object.   
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<linphone::Account> clone() const;
			
			/**
			 * @brief Find authentication info matching account, if any, similarly to
			 * linphone_core_find_auth_info. 
			 *
			 * @return a @ref AuthInfo matching account criteria if possible, nullptr if
			 * nothing can be found.   
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<const linphone::AuthInfo> findAuthInfo();
			
			/**
			 * @brief Obtain the value of a header sent by the server in last answer to
			 * REGISTER. 
			 *
			 * @param headerName The header name for which to fetch corresponding value.   
			 * @return The value of the queried header.   
			 */
			LINPHONECXX_PUBLIC std::string getCustomHeader(const std::string & headerName);
			
			/**
			 * @brief Detect if the given input is a phone number or not. 
			 *
			 * @param username The string to parse.   
			 * @return true if input is a phone number, false otherwise. 
			 */
			LINPHONECXX_PUBLIC bool isPhoneNumber(const std::string & username);
			
			/**
			 * @brief Normalize a human readable phone number into a basic string. 
			 *
			 * 888-444-222 becomes 888444222 or +33888444222 depending on the @ref Account
			 * object. This function will always generate a normalized username if input is a
			 * phone number. 
			 * @param username The string to parse.   
			 * @return nullptr if input is an invalid phone number, normalized phone number
			 * from username input otherwise.   
			 */
			LINPHONECXX_PUBLIC std::string normalizePhoneNumber(const std::string & username);
			
			/**
			 * @brief Normalize a human readable sip uri into a fully qualified
			 * LinphoneAddress. 
			 *
			 * A sip address should look like DisplayName <sip:username@domain:port> .
			 * Basically this function performs the following tasks
			 * The result is a syntactically correct SIP address. 
			 * @param username The string to parse.   
			 * @return nullptr if invalid input, normalized sip address otherwise.   
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<linphone::Address> normalizeSipUri(const std::string & username);
			
			/**
			 * @brief Prevent an account from refreshing its registration. 
			 *
			 * This is useful to let registrations to expire naturally (or) when the
			 * application wants to keep control on when refreshes are sent. However,
			 * linphone_core_set_network_reachable(lc,true) will always request the accounts
			 * to refresh their registrations. The refreshing operations can be resumed with
			 * refreshRegister(). 
			 */
			LINPHONECXX_PUBLIC void pauseRegister();
			
			/**
			 * @brief Refresh a proxy registration. 
			 *
			 * This is useful if for example you resuming from suspend, thus IP address may
			 * have changed. 
			 */
			LINPHONECXX_PUBLIC void refreshRegister();
			
			/**
			 * @brief Set the value of a custom header sent to the server in REGISTERs
			 * request. 
			 *
			 * @param headerValue The header value.   
			 */
			LINPHONECXX_PUBLIC void setCustomHeader(const std::string & headerName, const std::string & headerValue);
			
			;
			/**
			 * @brief Create a new @ref Account with a Proxy config backpointer. 
			 *
			 * This is only intended to be used while keeping a backward compatibility with
			 * proxy config. 
			 * @param config The @ref ProxyConfig object.   
			 * @return The newly created @ref Account object.   
			 */
			LINPHONECXX_PUBLIC static std::shared_ptr<linphone::Account> newWithConfig(const std::shared_ptr<linphone::Core> & lc, const std::shared_ptr<linphone::AccountParams> & params, const std::shared_ptr<linphone::ProxyConfig> & config);
			

		private:
			void *createCallbacks() override;
	};

};

#endif // _LINPHONE_ACCOUNT_HH
