/*
 * WengoPhone, a voice over Internet phone
 * Copyright (C) 2004-2007  Wengo
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef OWPHAPIWRAPPER_H
#define OWPHAPIWRAPPER_H

#include "PhApiCallbacks.h"

#include "PhApiIMChat.h"

#include <sipwrapper/SipWrapper.h>

#include <imwrapper/EnumPresenceState.h>
#include <imwrapper/IMChat.h>
#include <imwrapper/IMPresence.h>
#include <imwrapper/IMChatSession.h>

#include <sound/AudioDevice.h>
#include <thread/Mutex.h>
#include <thread/Timer.h>
#include <util/Event.h>

#include <phapi.h>

#include <string>

class PhApiSFPWrapper;

/**
 * SIP wrapper for PhApi.
 *
 * PhApi is a SIP implementation developed in C.
 * PhApi is based on eXosip, oSIP and oRTP.
 *
 * @ingroup model
 * @author Tanguy Krotoff
 * @author Mathieu Stute
 * @author Julien Bossart
 */
class PhApiWrapper : public SipWrapper {
public:

	Event<void (PhApiWrapper & sender, IMChatSession & imChatSession)> newIMChatSessionCreatedEvent;

	Event<void (PhApiWrapper & sender, IMChatSession & imChatSession, const std::string & contactId)> contactAddedEvent;

	Event<void (PhApiWrapper & sender, IMChatSession & imChatSession, const std::string & contactId)> contactRemovedEvent;

	Event<void (PhApiWrapper & sender, IMChatSession & chatSession, const std::string & from, const std::string & message)> messageReceivedEvent;

	Event<void (PhApiWrapper & sender, IMChatSession & chatSession, PhApiIMChat::StatusMessage status, const std::string & message)> statusMessageReceivedEvent;

	Event<void (PhApiWrapper & sender, IMChatSession & chatSession, const std::string & contactId, IMChat::TypingState state)> typingStateChangedEvent;

	Event<void (PhApiWrapper & sender)> connectedEvent;

	Event<void (PhApiWrapper & sender, bool connectionError, const std::string & reason)> disconnectedEvent;

	Event<void (PhApiWrapper & sender, int currentStep, int totalSteps, const std::string & infoMessage)> connectionProgressEvent;

	Event<void (PhApiWrapper & sender, EnumPresenceState::PresenceState state, const std::string & note, const std::string & from)> presenceStateChangedEvent;

	Event<void (PhApiWrapper & sender, EnumPresenceState::MyPresenceStatus status, const std::string & note)> myPresenceStatusEvent;

	Event<void (PhApiWrapper & sender, const std::string & contactId, IMPresence::SubscribeStatus status)> subscribeStatusEvent;

	Event<void (PhApiWrapper & sender, const std::string & contactId, const std::string filename)> contactIconChangedEvent;


	/** Value when phApi returns an error message. */
	static const int PhApiResultNoError = 0;

	static PhApiWrapper * getInstance() {
		static PhApiWrapper instance(PhApiCallbacks::getInstance());
		return &instance;
	}

	~PhApiWrapper();

	void terminate();

	int addVirtualLine(const std::string & displayName,
		const std::string & username, const std::string & identity,
		const std::string & password, const std::string & realm,
		const std::string & proxyServer, const std::string & registerServer);

	int registerVirtualLine(int lineId);

	void removeVirtualLine(int lineId);

	int makeCall(int lineId, const std::string & sipAddress, bool enableVideo);

	void sendRingingNotification(int callId, bool enableVideo);

	void acceptCall(int callId, bool enableVideo);

	void rejectCall(int callId);

	void closeCall(int callId);

	void holdCall(int callId);

	void resumeCall(int callId);

	void blindTransfer(int callId, const std::string & sipAddress);

	void playDtmf(int callId, char dtmf);

	void playSoundFile(int callId, const std::string & soundFile);

	void setAudioCodecList(const StringList & audioCodecList);

	CodecList::AudioCodec getAudioCodecUsed(int callId);

	CodecList::VideoCodec getVideoCodecUsed(int callId);

	void setVideoDevice(const std::string & deviceName);

	bool setCallInputAudioDevice(const AudioDevice & device);

	bool setRingerOutputAudioDevice(const AudioDevice & device);

	bool setCallOutputAudioDevice(const AudioDevice & device);

	void enableAEC(bool enable);

	void enableHalfDuplex(bool enable);

	void enablePIM(bool enable);

	void setPluginPath(const std::string & path);

	void setProxy(const std::string & address, unsigned port,
		const std::string & login, const std::string & password);

	void setTunnel(const std::string & address, unsigned port, bool ssl);

	void setNatType(EnumNatType::NatType natType);

	void setVideoQuality(EnumVideoQuality::VideoQuality videoQuality);

	void setSIP(const std::string & server, unsigned serverPort, unsigned localPort);

	/**
	 * @see SipWrapper::setCallsEncryption
	 */
	virtual void setCallsEncryption(bool enable);

	/**
	 * @see SipWrapper::areCallsEncrypted
	 */
	virtual bool isCallEncrypted(int callId);

	/**
	 * @name Conference
	 * @{
	 */

	int createConference();

	void joinConference(int confId, int callId);

	void splitConference(int confId, int callId);

	/** @} */

	/**
	 * @name PhApi callbacks
	 * @{
	 */

	void init();

	/** @} */

	/**
	 * @name IMConnect Implementation
	 * @{
	 */

	void connect();

	void disconnect();

	/** @} */

	/**
	 * @name IMChat Implementation
	 * @{
	 */

	void sendMessage(IMChatSession & chatSession, const std::string & message);
	void changeTypingState(IMChatSession & chatSession, IMChat::TypingState state);
	void createSession(IMChat & imChat, const IMContactSet & imContactSet);
	void closeSession(IMChatSession & chatSession);
	void addContact(IMChatSession & chatSession, const std::string & contactId);
	void removeContact(IMChatSession & chatSession, const std::string & contactId);

	/** @} */

	/**
	 * @name IMPresence Implementation
	 * @{
	 */

	void changeMyPresence(EnumPresenceState::PresenceState state, const std::string & note);

	//Look at changeMyIcon in IMPresence
	void sendMyIcon(const std::string & contactId, const std::string & iconFilename);

	void subscribeToPresenceOf(const std::string & contactId);

	void unsubscribeToPresenceOf(const std::string & contactId);

	void blockContact(const std::string & contactId);

	void unblockContact(const std::string & contactId);

	std::map<int, IMChatSession *> & getMessageIdChatSessionMap() {
		return _messageIdChatSessionMap;
	}

	std::map<const std::string, IMChatSession *> & getContactChatMap() {
		return _contactChatMap;
	}

	void allowWatcher(const std::string & watcher);

	void forbidWatcher(const std::string & watcher);

	/** @} */

	/**
	 * Helper function for the enum phCallStateEvent.
	 *
	 * @param event a phCallStateEvent to "convert" into a string
	 * @return a string representing the enum
	 */
	static std::string phapiCallStateToString(enum phCallStateEvent event);

	static const std::string PresenceStateOnline;
	static const std::string PresenceStateAway;
	static const std::string PresenceStateDoNotDisturb;

	static PhApiWrapper * PhApiWrapperHack;

	// Fixme: temporary hack
	std::string _iconFilename;

	bool isRegistered() const { return _registered; };
	void setRegistered(bool registered) { _registered = registered; };

	int getActiveVline() const { return _wengoVline; };

	void flipVideoImage(bool flip);

	std::string getWengoRealm() {
		return _wengoRealm;
	};

	/**
	 * Parse the From field from a SIP header.
	 * @param from the From from the SIP header.
	 * @return user@realm or just user if the realm is the same as the connection
	 */
	static std::string parseFromHeader(const std::string & from);

	/**
 	 * Looks for an IMChatSession associated with given contact.
	 *
	 * @return found IMChatSession, NULL otherwise
	 */
	IMChatSession *getIMChatSession(const std::string & from) const;


	//=================P2PP begins==============
	/**	
	* Get UDP socket
	*/
	void getUDPSock(int *sock);

	/**
	* Initialize NAT 
	*/
	void initNAT(const char *nat_type, const char *nat_router_addr, const int nat_router_port);

    /**
	* set SDP Audio Relay 
	*/
	void setSDPAudioRelay(const char *relay_addr, const int relay_port);

    /**
	* set SDP Audio Srflex 
	*/
	void setSDPAudioSrflex(const char *audio_srflex_addr, const int audio_srflex_port);

    /**
	* set SDP Audio Host
	*/
	void setSDPAudioHost(const char *audio_host_addr, const int audio_host_port);

	/**
	* Register functions to be used for parsing STUN packets (P2PP)
	*/
	void registerStunCallbacks(void *cb_sti_create_send_indication, void *cb_sti_read_data_from_ind);

	/**
	* Register functions to be used for parsing STUN packets (P2PP)
	*/
	void registerAudioStunCallbacks(void *cb_sti_create_send_indication, void *cb_sti_read_data_from_ind);

	/**
	* Register functions to be used for parsing ICE remote sdp informer
	*/
  void registerICECallbacks(void *cb_sti_audio_set_remote_sdp_candidates, 
                            void* cb_sti_audio_set_remote_sdp_candidates_callee,
                            void* cb_sti_start_ice_check_callee);

	/**
	* Set contact url
	*/
	void setContactURL(const std::string contacturl);


	/**
	* get audio port
	*/
	void getAudioPort(char* buf);


	/**
	* get video port
	*/
	void getVideoPort(char* buf);


	/**
	* set audio socket
	*/
	void setAudioSock(const int* sock);

	/**
	* set video socket
	*/
	void setVideoSock(const int* sock);

	//=================P2PP ends==============

private:

	/**
	 * Set phApi with parameters previously set with setProxy, etc. methods.
	 */
	void setNetworkParameter();

	PhApiWrapper(PhApiCallbacks & callbacks);

	/**
	 * Factorizes code.
	 *
	 * @see publishOnline()
	 * @see publishOffline()
	 */
	//void publishPresence(const std::string & pidf, const std::string & note);
	void publishPresence(bool online, const std::string & note);

	/** @see changeMyPresence() */
	void publishOnline(const std::string & note);

	/** @see changeMyPresence() */
	void publishOffline(const std::string & note);

	/** Changes audio devices inside PhApi. */
	bool setAudioDevices();

	/** Makes a SIP uri from a contact id. */
	/* (checks if a domain is set, otherwise adds the default one) */
	std::string makeSipAddress(const std::string & contactId);

	//FIXME ugly for call conference
	void phoneCallStateChangedEventHandler(SipWrapper & sender, int callId,
		EnumPhoneCallState::PhoneCallState state, const std::string & from);

	PhApiCallbacks * _callbacks;

	/** Checks if phApi has been initialized: if phInit() has been called. */
	bool _isInitialized;

	/** Virtual line for the Wengo SIP service. */
	int _wengoVline;

	/** SIP address for the Wengo SIP service. */
	std::string _wengoSipAddress;

	/** Realm for the Wengo SIP service. */
	std::string _wengoRealm;

	/** Playback audio device. */
	AudioDevice _outputAudioDevice;

	/** Record audio device. */
	AudioDevice _inputAudioDevice;

	std::map<int, IMChatSession *> _messageIdChatSessionMap;

	std::map<const std::string, IMChatSession *> _contactChatMap;

	std::string _proxyServer;

	unsigned _proxyPort;

	std::string _proxyLogin;

	std::string _proxyPassword;

	bool _tunnelNeeded;

	std::string _tunnelServer;

	unsigned _tunnelPort;

	bool _tunnelSSL;

	EnumNatType::NatType _natType;

	std::string _sipServer;

	unsigned _sipServerPort;

	unsigned _sipLocalPort;

	std::string _pluginPath;

	mutable Mutex _mutex;

	bool _registered;

	PhApiSFPWrapper & _phApiSFPWrapper;
};

#endif	//OWPHAPIWRAPPER_H
