/*
 * im.h - XMPP "IM" library API
 * Copyright (C) 2003  Justin Karneges
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#ifndef XMPP_IM_H
#define XMPP_IM_H

#include <tqdatetime.h>
#include <tqvaluelist.h>
#include "xmpp.h"

namespace XMPP
{
	class Url
	{
	public:
		Url(const TQString &url="", const TQString &desc="");
		Url(const Url &);
		Url & operator=(const Url &);
		~Url();

		TQString url() const;
		TQString desc() const;

		void setUrl(const TQString &);
		void setDesc(const TQString &);

	private:
		class Private;
		Private *d;
	};

	typedef TQValueList<Url> UrlList;
	typedef TQMap<TQString, TQString> StringMap;
	typedef enum { OfflineEvent, DeliveredEvent, DisplayedEvent,
			ComposingEvent, CancelEvent, InactiveEvent, GoneEvent } MsgEvent;
                                           
	class Message
	{
	public:
		Message(const Jid &to="");
		Message(const Message &from);
		Message & operator=(const Message &from);
		~Message();

		Jid to() const;
		Jid from() const;
		TQString id() const;
		TQString type() const;
		TQString lang() const;
		TQString subject(const TQString &lang="") const;
		TQString body(const TQString &lang="") const;
		TQString xHTMLBody(const TQString &lang="") const;
		TQString thread() const;
		Stanza::Error error() const;

		void setTo(const Jid &j);
		void setFrom(const Jid &j);
		void setId(const TQString &s);
		void setType(const TQString &s);
		void setLang(const TQString &s);
		void setSubject(const TQString &s, const TQString &lang="");
		void setBody(const TQString &s, const TQString &lang="");
		void setXHTMLBody(const TQString &s, const TQString &lang="", const TQString &attr = "");
		void setThread(const TQString &s);
		void setError(const Stanza::Error &err);

		// JEP-0091
		TQDateTime timeStamp() const;
		void setTimeStamp(const TQDateTime &ts);

		// JEP-0066
		UrlList urlList() const;
		void urlAdd(const Url &u);
		void urlsClear();
		void setUrlList(const UrlList &list);

		// JEP-0022
		TQString eventId() const;
		void setEventId(const TQString& id);
		bool containsEvents() const;
		bool containsEvent(MsgEvent e) const;
		void addEvent(MsgEvent e);
 
		// JEP-0027
		TQString xencrypted() const;
		void setXEncrypted(const TQString &s);

		// Obsolete invitation
		TQString invite() const;
		void setInvite(const TQString &s);

		// for compatibility.  delete me later
		bool spooled() const;
		void setSpooled(bool);
		bool wasEncrypted() const;
		void setWasEncrypted(bool);

		Stanza toStanza(Stream *stream) const;
		bool fromStanza(const Stanza &s, int tzoffset);

	private:
		class Private;
		Private *d;
	};

	class Subscription
	{
	public:
		enum SubType { None, To, From, Both, Remove };

		Subscription(SubType type=None);

		int type() const;

		TQString toString() const;
		bool fromString(const TQString &);

	private:
		SubType value;
	};

	class Status
	{
	public:
		Status(const TQString &show="", const TQString &status="", int priority=0, bool available=true);
		~Status();

		int priority() const;
		const TQString & show() const;
		const TQString & status() const;
		TQDateTime timeStamp() const;
		const TQString & keyID() const;
		bool isAvailable() const;
		bool isAway() const;
		bool isInvisible() const;
		bool hasError() const;
		int errorCode() const;
		const TQString & errorString() const;

		const TQString & xsigned() const;
		const TQString & songTitle() const;
		const TQString & capsNode() const;
		const TQString & capsVersion() const;
		const TQString & capsExt() const;

		void setPriority(int);
		void setShow(const TQString &);
		void setStatus(const TQString &);
		void setTimeStamp(const TQDateTime &);
		void setKeyID(const TQString &);
		void setIsAvailable(bool);
		void setIsInvisible(bool);
		void setError(int, const TQString &);
		void setCapsNode(const TQString&);
		void setCapsVersion(const TQString&);
		void setCapsExt(const TQString&);

		void setXSigned(const TQString &);
		void setSongTitle(const TQString &);

	private:
		int v_priority;
		TQString v_show, v_status, v_key;
		TQDateTime v_timeStamp;
		bool v_isAvailable;
		bool v_isInvisible;

		TQString v_xsigned;
		// gabber song extension
		TQString v_songTitle;
		TQString v_capsNode, v_capsVersion, v_capsExt;

		int ecode;
		TQString estr;

		class Private;
		Private *d;
	};

	class Resource
	{
	public:
		Resource(const TQString &name="", const Status &s=Status());
		~Resource();

		const TQString & name() const;
		int priority() const;
		const Status & status() const;

		void setName(const TQString &);
		void setStatus(const Status &);

	private:
		TQString v_name;
		Status v_status;

		class ResourcePrivate *d;
	};

	class ResourceList : public TQValueList<Resource>
	{
	public:
		ResourceList();
		~ResourceList();

		ResourceList::Iterator find(const TQString &);
		ResourceList::Iterator priority();

		ResourceList::ConstIterator find(const TQString &) const;
		ResourceList::ConstIterator priority() const;

	private:
		class ResourceListPrivate *d;
	};

	class RosterItem
	{
	public:
		RosterItem(const Jid &jid="");
		virtual ~RosterItem();

		const Jid & jid() const;
		const TQString & name() const;
		const TQStringList & groups() const;
		const Subscription & subscription() const;
		const TQString & ask() const;
		bool isPush() const;
		bool inGroup(const TQString &) const;

		virtual void setJid(const Jid &);
		void setName(const TQString &);
		void setGroups(const TQStringList &);
		void setSubscription(const Subscription &);
		void setAsk(const TQString &);
		void setIsPush(bool);
		bool addGroup(const TQString &);
		bool removeGroup(const TQString &);

		TQDomElement toXml(TQDomDocument *) const;
		bool fromXml(const TQDomElement &);

	private:
		Jid v_jid;
		TQString v_name;
		TQStringList v_groups;
		Subscription v_subscription;
		TQString v_ask;
		bool v_push;

		class RosterItemPrivate *d;
	};

	class Roster : public TQValueList<RosterItem>
	{
	public:
		Roster();
		~Roster();

		Roster::Iterator find(const Jid &);
		Roster::ConstIterator find(const Jid &) const;

	private:
		class RosterPrivate *d;
	};

        class Features
	{
	public:
		Features();
		Features(const TQStringList &);
		Features(const TQString &);
		~Features();

		TQStringList list() const; // actual featurelist
		void setList(const TQStringList &);

		// features
		bool canRegister() const;
		bool canSearch() const;
		bool canGroupchat() const;
		bool canVoice() const;
		bool canDisco() const;
		bool canXHTML() const;
		bool isGateway() const;
		bool haveVCard() const;

		enum FeatureID {
			FID_Invalid = -1,
			FID_None,
			FID_Register,
			FID_Search,
			FID_Groupchat,
			FID_Disco,
			FID_Gateway,
			FID_VCard,
			FID_Xhtml,

			// private Psi actions
			FID_Add
		};

		// useful functions
		bool test(const TQStringList &) const;

		TQString name() const;
		static TQString name(long id);
		static TQString name(const TQString &feature);

		long id() const;
		static long id(const TQString &feature);
		static TQString feature(long id);

		class FeatureName;
	private:
		TQStringList _list;
	};

	class AgentItem
	{
	public:
		AgentItem() { }

		const Jid & jid() const { return v_jid; }
		const TQString & name() const { return v_name; }
		const TQString & category() const { return v_category; }
		const TQString & type() const { return v_type; }
		const Features & features() const { return v_features; }

		void setJid(const Jid &j) { v_jid = j; }
		void setName(const TQString &n) { v_name = n; }
		void setCategory(const TQString &c) { v_category = c; }
		void setType(const TQString &t) { v_type = t; }
		void setFeatures(const Features &f) { v_features = f; }

	private:
		Jid v_jid;
		TQString v_name, v_category, v_type;
		Features v_features;
	};

	typedef TQValueList<AgentItem> AgentList;

	class DiscoItem
	{
	public:
		DiscoItem();
		~DiscoItem();

		const Jid &jid() const;
		const TQString &node() const;
		const TQString &name() const;

		void setJid(const Jid &);
		void setName(const TQString &);
		void setNode(const TQString &);

		enum Action {
			None = 0,
			Remove,
			Update
		};

		Action action() const;
		void setAction(Action);

		const Features &features() const;
		void setFeatures(const Features &);

		struct Identity
		{
			TQString category;
			TQString name;
			TQString type;
		};

		typedef TQValueList<Identity> Identities;

		const Identities &identities() const;
		void setIdentities(const Identities &);

		// some useful helper functions
		static Action string2action(TQString s);
		static TQString action2string(Action a);

		DiscoItem & operator= (const DiscoItem &);
		DiscoItem(const DiscoItem &);

		operator AgentItem() const { return toAgentItem(); }
		AgentItem toAgentItem() const;
		void fromAgentItem(const AgentItem &);

	private:
		class Private;
		Private *d;
	};

	typedef TQValueList<DiscoItem> DiscoList;

	class FormField
	{
	public:
		enum { username, nick, password, name, first, last, email, address, city, state, zip, phone, url, date, misc };
		FormField(const TQString &type="", const TQString &value="");
		~FormField();

		int type() const;
		TQString fieldName() const;
		TQString realName() const;
		bool isSecret() const;
		const TQString & value() const;
		void setType(int);
		bool setType(const TQString &);
		void setValue(const TQString &);

	private:
		int tagNameToType(const TQString &) const;
		TQString typeToTagName(int) const;

		int v_type;
		TQString v_value;

		class Private;
		Private *d;
	};

	class Form : public TQValueList<FormField>
	{
	public:
		Form(const Jid &j="");
		~Form();

		Jid jid() const;
		TQString instructions() const;
		TQString key() const;
		void setJid(const Jid &);
		void setInstructions(const TQString &);
		void setKey(const TQString &);

	private:
		Jid v_jid;
		TQString v_instructions, v_key;

		class Private;
		Private *d;
	};

	class SearchResult
	{
	public:
		SearchResult(const Jid &jid="");
		~SearchResult();

		const Jid & jid() const;
		const TQString & nick() const;
		const TQString & first() const;
		const TQString & last() const;
		const TQString & email() const;

		void setJid(const Jid &);
		void setNick(const TQString &);
		void setFirst(const TQString &);
		void setLast(const TQString &);
		void setEmail(const TQString &);

	private:
		Jid v_jid;
		TQString v_nick, v_first, v_last, v_email;
	};

	class Client;
	class LiveRosterItem;
	class LiveRoster;
	class S5BManager;
	class IBBManager;
	class JidLinkManager;
	class FileTransferManager;

	class Task : public TQObject
	{
		Q_OBJECT
  
	public:
		enum { ErrDisc };
		Task(Task *parent);
		Task(Client *, bool isRoot);
		virtual ~Task();

		Task *parent() const;
		Client *client() const;
		TQDomDocument *doc() const;
		TQString id() const;

		bool success() const;
		int statusCode() const;
		const TQString & statusString() const;

		void go(bool autoDelete=false);
		virtual bool take(const TQDomElement &);
		void safeDelete();

	signals:
		void finished();

	protected:
		virtual void onGo();
		virtual void onDisconnect();
		void send(const TQDomElement &);
		void setSuccess(int code=0, const TQString &str="");
		void setError(const TQDomElement &);
		void setError(int code=0, const TQString &str="");
		void debug(const char *, ...);
		void debug(const TQString &);
		bool iqVerify(const TQDomElement &x, const Jid &to, const TQString &id, const TQString &xmlns="");

	private slots:
		void clientDisconnected();
		void done();

	private:
		void init();

		class TaskPrivate;
		TaskPrivate *d;
	};

	class Client : public TQObject
	{
		Q_OBJECT
  

	public:
		Client(TQObject *parent=0);
		~Client();

		bool isActive() const;
		void connectToServer(ClientStream *s, const Jid &j, bool auth=true);
		void start(const TQString &host, const TQString &user, const TQString &pass, const TQString &resource);
		void close(bool fast=false);

		Stream & stream();
		const LiveRoster & roster() const;
		const ResourceList & resourceList() const;

		void send(const TQDomElement &);
		void send(const TQString &);

		TQString host() const;
		TQString user() const;
		TQString pass() const;
		TQString resource() const;
		Jid jid() const;

		void rosterRequest();
		void sendMessage(const Message &);
		void sendSubscription(const Jid &, const TQString &);
		void setPresence(const Status &);

		void debug(const TQString &);
		TQString genUniqueId();
		Task *rootTask();
		TQDomDocument *doc() const;

		TQString OSName() const;
		TQString timeZone() const;
		int timeZoneOffset() const;
		TQString clientName() const;
		TQString clientVersion() const;
		TQString capsNode() const;
		TQString capsVersion() const;
		TQString capsExt() const;

		void setOSName(const TQString &);
		void setTimeZone(const TQString &, int);
		void setClientName(const TQString &);
		void setClientVersion(const TQString &);
		void setCapsNode(const TQString &);
		void setCapsVersion(const TQString &);

		void setIdentity(DiscoItem::Identity);
		DiscoItem::Identity identity();

		void addExtension(const TQString& ext, const Features& f);
		void removeExtension(const TQString& ext);
		const Features& extension(const TQString& ext) const;
		TQStringList extensions() const;
		
		S5BManager *s5bManager() const;
		IBBManager *ibbManager() const;
		JidLinkManager *jidLinkManager() const;

		void setFileTransferEnabled(bool b);
		FileTransferManager *fileTransferManager() const;

		bool groupChatJoin(const TQString &host, const TQString &room, const TQString &nick);
		bool groupChatJoin(const TQString &host, const TQString &room, const TQString &nick, const TQString &password);
		void groupChatSetStatus(const TQString &host, const TQString &room, const Status &);
		void groupChatChangeNick(const TQString &host, const TQString &room, const TQString &nick, const Status &);
		void groupChatLeave(const TQString &host, const TQString &room);

	signals:
		void activated();
		void disconnected();
		//void authFinished(bool, int, const TQString &);
		void rosterRequestFinished(bool, int, const TQString &);
		void rosterItemAdded(const RosterItem &);
		void rosterItemUpdated(const RosterItem &);
		void rosterItemRemoved(const RosterItem &);
		void resourceAvailable(const Jid &, const Resource &);
		void resourceUnavailable(const Jid &, const Resource &);
		void presenceError(const Jid &, int, const TQString &);
		void subscription(const Jid &, const TQString &);
		void messageReceived(const Message &);
		void debugText(const TQString &);
		void xmlIncoming(const TQString &);
		void xmlOutgoing(const TQString &);
		void groupChatJoined(const Jid &);
		void groupChatLeft(const Jid &);
		void groupChatPresence(const Jid &, const Status &);
		void groupChatError(const Jid &, int, const TQString &);

		void incomingJidLink();

	private slots:
		//void streamConnected();
		//void streamHandshaken();
		//void streamError(const StreamError &);
		//void streamSSLCertificateReady(const TQSSLCert &);
		//void streamCloseFinished();
		void streamError(int);
		void streamReadyRead();
		void streamIncomingXml(const TQString &);
		void streamOutgoingXml(const TQString &);

		void slotRosterRequestFinished();

		// basic daemons
		void ppSubscription(const Jid &, const TQString &);
		void ppPresence(const Jid &, const Status &);
		void pmMessage(const Message &);
		void prRoster(const Roster &);

		void s5b_incomingReady();
		void ibb_incomingReady();

	public:
		class GroupChat;
	private:
		void cleanup();
		void distribute(const TQDomElement &);
		void importRoster(const Roster &);
		void importRosterItem(const RosterItem &);
		void updateSelfPresence(const Jid &, const Status &);
		void updatePresence(LiveRosterItem *, const Jid &, const Status &);

		class ClientPrivate;
		ClientPrivate *d;
	};

	class LiveRosterItem : public RosterItem
	{
	public:
		LiveRosterItem(const Jid &j="");
		LiveRosterItem(const RosterItem &);
		~LiveRosterItem();

		void setRosterItem(const RosterItem &);

		ResourceList & resourceList();
		ResourceList::Iterator priority();

		const ResourceList & resourceList() const;
		ResourceList::ConstIterator priority() const;

		bool isAvailable() const;
		const Status & lastUnavailableStatus() const;
		bool flagForDelete() const;

		void setLastUnavailableStatus(const Status &);
		void setFlagForDelete(bool);

	private:
		ResourceList v_resourceList;
		Status v_lastUnavailableStatus;
		bool v_flagForDelete;

		class LiveRosterItemPrivate;
		LiveRosterItemPrivate *d;
	};

	class LiveRoster : public TQValueList<LiveRosterItem>
	{
	public:
		LiveRoster();
		~LiveRoster();

		void flagAllForDelete();
		LiveRoster::Iterator find(const Jid &, bool compareRes=true);
		LiveRoster::ConstIterator find(const Jid &, bool compareRes=true) const;

	private:
		class LiveRosterPrivate;
		LiveRosterPrivate *d;
	};
}

#endif
