/*
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_CONFERENCE_HH
#define _LINPHONE_CONFERENCE_HH

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




struct _LinphoneConference;


namespace linphone {

	class Address;
	class Core;
	class ConferenceParams;
	class AudioDevice;
	class Participant;
	class Call;
	class CallParams;
	class ConferenceListener;

	/**
	 * @brief A conference is the object that allow to make calls when there are 2 or
	 * more participants. 
	 *
	 * To create (or find) a @ref Conference, you first need a @ref ConferenceParams
	 * object. Core::createConferenceWithParams() allows you to create a conference. A
	 * conference is uniquely identified by a conference address, meaning you can have
	 * more than one conference between two accounts. As of now, each @ref Core can
	 * host only 1 conference but it can be part of many conferences as a remote
	 * participant. To find a conference among those a core is part of, you can call
	 * Core::searchConference(). 
	 */
	class Conference: public MultiListenableObject {
	
		public:
			/**
			* @ref State is used to indicate the current state of a conference. 
			*
			*/
			enum class State {
				/**
				* Initial state. 
				*/
				None = 0,
				/**
				* Conference is now instantiated on local. 
				*/
				Instantiated = 1,
				/**
				* One creation request was sent to the server. 
				*/
				CreationPending = 2,
				/**
				* Conference was created on the server. 
				*/
				Created = 3,
				/**
				* Conference creation failed. 
				*/
				CreationFailed = 4,
				/**
				* Wait for conference termination. 
				*/
				TerminationPending = 5,
				/**
				* Conference exists on server but not in local. 
				*/
				Terminated = 6,
				/**
				* Conference termination failed. 
				*/
				TerminationFailed = 7,
				/**
				* Conference was deleted on the server. 
				*/
				Deleted = 8
			};


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

			LINPHONECXX_PUBLIC void addListener(const std::shared_ptr<ConferenceListener> &listener);
			LINPHONECXX_PUBLIC void removeListener(const std::shared_ptr<ConferenceListener> &listener);
	
		public:
			
		
			/**
			 * @brief Get the conference address of the conference. 
			 *
			 * @return The conference address of the conference.   
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<const linphone::Address> getConferenceAddress() const;
			
			/**
			 * @brief Set the conference address. 
			 *
			 * @param address the conference address to set.   
			 * @warning This is only allowed for a remote conference if it is in state
			 * CreationPending or Instantiated 
			 */
			LINPHONECXX_PUBLIC void setConferenceAddress(const std::shared_ptr<linphone::Address> & address);
			
			/**
			 * @brief Returns core for a @ref Conference. 
			 *
			 * @return back pointer to @ref Core object.   Returns back pointer to @ref Core
			 * object. 
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<linphone::Core> getCore() const;
			
			/**
			 * @brief Get current parameters of the conference. 
			 *
			 * @return a @ref ConferenceParams .   
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<const linphone::ConferenceParams> getCurrentParams() const;
			
			/**
			 * @brief Get the conference id as string. 
			 *
			 * @return the conference id   
			 * @deprecated 10/07/2020 Use getConferenceAddress() instead. 
			 */
			LINPHONECXX_PUBLIC LINPHONECXX_DEPRECATED std::string getId() const;
			
			/**
			 * @brief Set the conference id as string. 
			 *
			 * @param conferenceId the conference id to set.   
			 * @deprecated 10/07/2020 Use setConferenceAddress() instead. 
			 */
			LINPHONECXX_PUBLIC LINPHONECXX_DEPRECATED void setId(const std::string & conferenceId);
			
			/**
			 * @brief Gets the current input device for this conference. 
			 *
			 * @return the @ref AudioDevice used by this conference as input or nullptr if
			 * there is currently no soundcard configured (depending on the state of the
			 * conference)   
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<const linphone::AudioDevice> getInputAudioDevice() const;
			
			/**
			 * @brief Sets the given @ref AudioDevice as input for this conference only. 
			 *
			 * @param audioDevice The @ref AudioDevice. nullptr does nothing.   
			 */
			LINPHONECXX_PUBLIC void setInputAudioDevice(const std::shared_ptr<linphone::AudioDevice> & audioDevice);
			
			/**
			 * @brief For a local conference, it returns whether the local participant is
			 * enabled For a remote conference, it return whether the remote participant has
			 * left the conference without bein removed from it. 
			 *
			 * @return true if the local participant is in a conference, false otherwise. 
			 */
			LINPHONECXX_PUBLIC bool isIn() const;
			
			/**
			 * @brief For a local audio video conference, this function returns the
			 * participant hosting the conference For a remote audio video conference, this
			 * function returns the focus of the conference. 
			 *
			 * @return a @ref Participant .   
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<linphone::Participant> getMe() const;
			
			/**
			 * @brief Gets the current output device for this conference. 
			 *
			 * @return the @ref AudioDevice used by this conference as output or nullptr if
			 * there is currently no soundcard configured (depending on the state of the
			 * conference)   
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<const linphone::AudioDevice> getOutputAudioDevice() const;
			
			/**
			 * @brief Sets the given @ref AudioDevice as output for this conference only. 
			 *
			 * @param audioDevice The @ref AudioDevice. nullptr does nothing.   
			 */
			LINPHONECXX_PUBLIC void setOutputAudioDevice(const std::shared_ptr<linphone::AudioDevice> & audioDevice);
			
			/**
			 * @brief Get number of participants without me. 
			 *
			 * @return the number of participants excluding me in a @ref Conference 
			 */
			LINPHONECXX_PUBLIC int getParticipantCount() const;
			
			/**
			 * @brief Get list of all participants of one conference. 
			 *
			 * @return The list of participants of the conference.      
			 */
			LINPHONECXX_PUBLIC std::list<std::shared_ptr<linphone::Participant>> getParticipantList() const;
			
			/**
			 * @brief Get URIs of all participants of one conference The returned bctbx_list_t
			 * contains URIs of all participant. 
			 *
			 * That list must be freed after use and each URI must be unref with
			 * linphone_address_unref 
			 * @return The list of the participants' address active in the conference.      
			 * @deprecated 10/07/2020 Use getParticipantList() instead. 
			 */
			LINPHONECXX_PUBLIC LINPHONECXX_DEPRECATED std::list<std::shared_ptr<linphone::Address>> getParticipants() const;
			
			/**
			 * @brief Get the conference subject. 
			 *
			 * @return conference subject.   
			 */
			LINPHONECXX_PUBLIC std::string getSubject() const;
			
			/**
			 * @brief Set the conference subject. 
			 *
			 * @param subject conference subject   
			 */
			LINPHONECXX_PUBLIC void setSubject(const std::string & subject);
			
			/**
			 * @brief Join an existing call to the conference. 
			 *
			 * If the conference is in the state LinphoneConferenceStateCreationPending, then
			 * the conference will start on the input and output audio devices used for the
			 * currently active call, if any 
			 * @param call a @ref Call that has to be added to the conference.   
			 */
			LINPHONECXX_PUBLIC linphone::Status addParticipant(const std::shared_ptr<linphone::Call> & call);
			
			/**
			 * @brief Join a participant to the conference. 
			 *
			 * @param uri a @ref Address that has to be added to the conference.   
			 */
			LINPHONECXX_PUBLIC linphone::Status addParticipant(const std::shared_ptr<const linphone::Address> & uri);
			
			/**
			 * @brief Add participants to the conference, by supplying a list of @ref Call. 
			 *
			 * If the conference is in the state LinphoneConferenceStateCreationPending, then
			 * the conference will start on the input and output audio devices used for the
			 * currently active call, if any 
			 * @param calls A list of calls to add to the conference.    
			 */
			LINPHONECXX_PUBLIC linphone::Status addParticipants(const std::list<std::shared_ptr<linphone::Call>> & calls);
			
			/**
			 * @brief For a local conference, the local participant joins the conference For a
			 * remote conference, the participant rejoins the conference after leaving it
			 * earlier on. 
			 *
			 * @return 0 if succeeded. Negative number if failed 
			 */
			LINPHONECXX_PUBLIC int enter();
			
			/**
			 * @brief Find a participant from a conference. 
			 *
			 * @param uri SIP URI of the participant to search.   
			 * @return a pointer to the participant found or nullptr.   
			 */
			LINPHONECXX_PUBLIC std::shared_ptr<linphone::Participant> findParticipant(const std::shared_ptr<const linphone::Address> & uri);
			
			/**
			 * @brief Invite participants to the conference, by supplying a list of @ref
			 * Address If the conference is in the state
			 * LinphoneConferenceStateCreationPending, then the conference will start on the
			 * input and output audio devices used for the currently active call, if any. 
			 *
			 * @param params @ref CallParams to use for inviting the participants.   
			 */
			LINPHONECXX_PUBLIC linphone::Status inviteParticipants(const std::list<std::shared_ptr<linphone::Address>> & addresses, const std::shared_ptr<const linphone::CallParams> & params);
			
			/**
			 * @brief For a local audio video conference, this function compares the address
			 * provided as argument with that of participant hosting the conference For a
			 * remote audio video conference, this function compares the address provided as
			 * argument with that of the focus of the conference. 
			 *
			 * @param uri A @ref Address object   
			 * @return true if the participant is me, false otherwise. 
			 */
			LINPHONECXX_PUBLIC bool isMe(const std::shared_ptr<const linphone::Address> & uri) const;
			
			/**
			 * @brief For a local conference, the local participant leaves the conference For
			 * a remote conference, the participant leaves the conference after joining it
			 * earlier on. 
			 *
			 * @return 0 if succeeded. Negative number if failed 
			 */
			LINPHONECXX_PUBLIC int leave();
			
			/**
			 * @brief Call generic OpenGL render for a given conference. 
			 *
			 */
			LINPHONECXX_PUBLIC void oglRender();
			
			/**
			 * @brief Call generic OpenGL render preview for a given conference. 
			 *
			 */
			LINPHONECXX_PUBLIC void previewOglRender();
			
			/**
			 *
			 * @param uri URI of the participant to remove   
			 * @warning The passed participant uri must be one of those returned by
			 * getParticipants() 
			 * @return 0 if succeeded, -1 if failed 
			 * @deprecated 10/07/2020 Use removeParticipant() instead. 
			 */
			LINPHONECXX_PUBLIC LINPHONECXX_DEPRECATED linphone::Status removeParticipant(const std::shared_ptr<const linphone::Address> & uri);
			
			/**
			 *
			 * @param participant participant to remove   
			 * @warning The passed participant must be one of those returned by
			 * getParticipantList() 
			 * @warning This method may destroy the conference if the only remaining
			 * participant had an existing call to the local participant before the conference
			 * was created 
			 * @return 0 if succeeded, -1 if failed 
			 */
			LINPHONECXX_PUBLIC linphone::Status removeParticipant(const std::shared_ptr<linphone::Participant> & participant);
			
			/**
			 *
			 * @param call call to remove   
			 * @return 0 if succeeded, -1 if failed 
			 * @deprecated 10/07/2020 Use removeParticipant() instead. 
			 */
			LINPHONECXX_PUBLIC LINPHONECXX_DEPRECATED linphone::Status removeParticipant(const std::shared_ptr<linphone::Call> & call);
			
			/**
			 * @brief Change the admin status of a participant of a conference (you need to be
			 * an admin yourself to do this). 
			 *
			 * @param isAdmin A boolean value telling whether the participant should now be an
			 * admin or not 
			 */
			LINPHONECXX_PUBLIC void setParticipantAdminStatus(const std::shared_ptr<linphone::Participant> & participant, bool isAdmin);
			
			/**
			 * @brief Terminates conference. 
			 *
			 * @return 0 if the termination is successful, -1 otherwise. 
			 */
			LINPHONECXX_PUBLIC int terminate();
			
			/**
			 * @brief Update parameters of the conference. 
			 *
			 * This is typically used enable or disable the video stream in the conference. 
			 * @param params the new parameters to apply.   
			 */
			LINPHONECXX_PUBLIC int updateParams(const std::shared_ptr<const linphone::ConferenceParams> & params);
			
			
		private:
			void *createCallbacks() override;
	};

};

#endif // _LINPHONE_CONFERENCE_HH
