 /*
    jabbercapabilitiesmanager.h - Manage entity capabilities(JEP-0115) pool.

    Copyright (c) 2006      by Michaël Larouche     <michael.larouche@kdemail.net>

    Kopete    (c) 2001-2006 by the Kopete developers <kopete-devel@kde.org>

    Imported from caps.cpp from Psi:
    Copyright (C) 2005  Remko Troncon

    *************************************************************************
    *                                                                       *
    * 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.                                   *
    *                                                                       *
    *************************************************************************
*/
#ifndef JABBERCAPABILITIESMANAGER_H
#define JABBERCAPABILITIESMANAGER_H

#include <tqobject.h>
#include <im.h>
#include <xmpp.h>

using namespace XMPP;

class JabberAccount;

/**
 * @brief Manage Jabber entity capabilities (JEP-0115)
 * @author Michaël Larouche <michael.larouche@kdemail.net>
 * @author Remko Troncon
 */
class JabberCapabilitiesManager : public TQObject
{
	Q_OBJECT
  
public:
	/**
	 * Construct
	 */
	JabberCapabilitiesManager();
	~JabberCapabilitiesManager();

	/**
	 * Load cached information from local file.
	 */
	void loadCachedInformation();

	/**
	 * Check if the jid support Entity capabitilies.
	 * @param jid JID to check.
	 * @return true if the jid support entity capabitilies.
	 */
	bool capabilitiesEnabled(const Jid& jid) const;

	/**
	 * Remove account from manager.
	 */
	void removeAccount(JabberAccount *account);

	/**
	 * Return the features supported for the JID.
	 */
	XMPP::Features features(const Jid& jid) const;
	/**
	 * Return the client name for the current JID.
	 */
	TQString clientName(const Jid& jid) const;
	/**
	 * Return the client version for the current JID.
	 */
	TQString clientVersion(const Jid& jid) const;

signals:
	void capabilitiesChanged(const XMPP::Jid &jid);

public slots:
	/**
	 * Update if necessary the capabities for the JID passed in args.
	 * Caps are received in Presence messages so that's why we are
	 * passing a XMPP::Status object.
	 *
	 * @param jid JID that capabilities was updated.
	 * @param status The XMPP::Status that contain the caps.
	 */
	void updateCapabilities(JabberAccount *account, const XMPP::Jid &jid, const XMPP::Status &status);

private slots:
	/**
	 * @brief Called when a reply to disco#info request was received.
	 * If the result was succesful, the resulting features are recorded in the
	 * features database for the requested node, and all the affected jids are
	 * put in the queue for update notification.
	 * If the result was unsuccesful, another jid with the same capabilities is
	 * selected and sent a disco#info query.
	 */
	void discoRequestFinished();

private:
	/**
	 * @brief Sends a disco#info request to a given node of a jid through an account.
	 * When the request is finished, the discoRequestFinished() slot is called.
	 *
	 * @param account The account through which to send the disco request.
	 * @param jid The target entity's JID 
	 * @param node The target disco#info node
	 */
	void requestDiscoInfo(JabberAccount *account, const Jid& jid, const TQString& node);

	/**
	 * Save capabilities information to disk.
	 */
	void saveInformation();

	class Capabilities;
	typedef TQValueList<Capabilities> CapabilitiesList;
	/**
	 * @brief A class representing an entity capability specification.
	 * An entity capability is a combination of a node, a version, and a set of
	 * extensions.
	 */
	class Capabilities
	{
		public:
			/**
			 * Default constructor.
			 */
			Capabilities();
			/**
			 * Define capabilities.
			 * @param node the node
			 * @param version the version
			 * @param extensions the list of extensions (separated by spaces)
			 */
			Capabilities(const TQString &node, const TQString &version, const TQString &extensions);
			/**
			 * Returns the node of the capabilities specification.
			 */
			const TQString& node() const;
			/**
			 * @brief Returns the version of the capabilities specification.
			 */
			const TQString& version() const;
			/**
			 * @brief Returns the extensions of the capabilities specification.
			 */
			const TQString& extensions() const; 
			/**
			 * \brief Flattens the caps specification into the set of 'simple' specifications.
			 * A 'simple' specification is a specification with exactly one extension,
			 * or with the version number as the extension.
			 *
			 * Example: A caps specification with node=http://psi-im.org, version=0.10,
			 * and ext='achat vchat' would be expanded into the following list of specs:
			 *	node=http://psi-im.org, ver=0.10, ext=0.10
			 *	node=http://psi-im.org, ver=0.10, ext=achat
			 *	node=http://psi-im.org, ver=0.10, ext=vchat
			 */
			CapabilitiesList flatten() const;
	
			bool operator==(const Capabilities&) const;
			bool operator!=(const Capabilities&) const;
			bool operator<(const Capabilities&) const;
				
		private:
			TQString m_node, m_version, m_extensions;
	};

	class CapabilitiesInformation
	{
		public:
			CapabilitiesInformation();
			const TQStringList& features() const;
			const DiscoItem::Identities& identities() const;
			TQStringList jids() const;
			bool discovered() const;
			int pendingRequests() const;

			void reset();
			void removeAccount(JabberAccount* acc);
			void removeJid(const Jid&);
			void addJid(const Jid&, JabberAccount*);
			TQPair<Jid,JabberAccount*> nextJid(const Jid&, const Task*);
			
			void setDiscovered(bool);
			void setPendingRequests(int);
			void setIdentities(const DiscoItem::Identities&);
			void setFeatures(const TQStringList&);
			
			TQDomElement toXml(TQDomDocument *) const;
			void fromXml(const TQDomElement&);

		protected:
			void updateLastSeen();
			
		private:
			bool m_discovered;
			int m_pendingRequests;
			TQStringList m_features;
			DiscoItem::Identities m_identities;
			TQValueList<TQPair<TQString,JabberAccount*> > m_jids;
			TQDate m_lastSeen;
	};

	class Private;
	Private *d;
};

#endif
