/*
 * psiaccount.h - handles a Psi account
 * Copyright (C) 2001-2005  Justin Karneges
 *
 * 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.
 *
 * You can also redistribute and/or modify this program under the
 * terms of the Psi License, specified in the accompanied COPYING
 * file, as published by the Psi Project; either dated January 1st,
 * 2005, 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#ifndef PSIACCOUNT_H
#define PSIACCOUNT_H

#include<qlabel.h>
#include<qptrlist.h>
#include<qdom.h>
#include"xmpp.h"
#include"openpgp.h"
#include"ui_pgpkey.h"
#include"common.h"


namespace XMPP
{
	class Status;
	class RosterItem;
	class Client;
	//class StreamError;
	class Resource;
	class Message;
};

using namespace XMPP;

class PsiCon;
class PsiAccount;
class PsiEvent;
class UserAccount;
class ContactProfile;
class QWidget;
class EventQueue;
class UserResource;
class UserListItem;
class UserList;
class EventDlg;
class ChatDlg;
class EDB;
class QSSLCert;
class QHostAddress;
class AvatarFactory;

class PGPKeyDlg : public PGPKeyUI
{
	Q_OBJECT
public:
	PGPKeyDlg(const OpenPGP::KeyList &, const QString &choose, QWidget *parent=0, const char *name=0);
	~PGPKeyDlg();

	QString keyID() const;
	QString userID() const;

private slots:
	void qlv_doubleClicked(QListViewItem *);
	void do_accept();

private:
	class Private;
	Private *d;
};

class AccountLabel : public QLabel
{
	Q_OBJECT
public:
	AccountLabel(PsiAccount *, QWidget *parent=0, bool simpleMode=false);
	~AccountLabel();

private slots:
	void updateName();
	void deleteMe();

private:
	PsiAccount *pa;
	bool simpleMode;
};

class PGPTransaction : public OpenPGP::Request
{
	Q_OBJECT
public:
	PGPTransaction(OpenPGP::Engine *);
	~PGPTransaction();

	int id() const;
	const Message & message() const;
	void setMessage(const Message &);
	const QDomElement & xml() const;
	void setXml(const QDomElement &);

	Jid jid() const;
	void setJid(const Jid &);

private:
	class Private;
	Private *d;
};

// sick sick remove this someday please!
#include"im.h"
struct GCContact
{
	Jid jid;
	Status status;
};

class PsiAccount : public QObject
{
	Q_OBJECT
public:
	PsiAccount(const UserAccount &acc, PsiCon *parent);
	~PsiAccount();

	bool enabled() const;
	void setEnabled(bool e = TRUE);

	bool isActive() const;
	bool isConnected() const;
	const QString &name() const;

	const UserAccount & userAccount() const;
	void setUserAccount(const UserAccount &);
	const Jid & jid() const;
	QString nameWithJid() const;

	XMPP::Client *client() const;
	ContactProfile *contactProfile() const;
	EventQueue *eventQueue() const;
	EDB *edb() const;
	PsiCon *psi() const;
	AvatarFactory *avatarFactory() const;
	Status status() const;
	void setStatusDirect(const Status &);
	void setStatusActual(const Status &);
	void login();
	void logout(bool fast=false, const Status &s = Status("", "Logged out", 0, false));
	bool loggedIn() const;
	void setNick(const QString &);
	QString nick() const;
	QString pgpKey() const;
	QHostAddress *localAddress() const;

	QWidget *dialogFind(const char *className, const Jid &jid="");
	void dialogRegister(QWidget *w, const Jid &jid="");
	void dialogUnregister(QWidget *w);

	void modify();
	void changeVCard();
	void changePW();
	void changeStatus(int);
	void doDisco();

	void showXmlConsole();
	void openAddUserDlg();
	void openGroupChat(const Jid &);
	bool groupChatJoin(const QString &host, const QString &room, const QString &nick);
	void groupChatSetStatus(const QString &host, const QString &room, const Status &);
	void groupChatChangeNick(const QString &host, const QString &room, const QString& nick, const Status &);
	void groupChatLeave(const QString &host, const QString &room);

	UserListItem *find(const Jid &) const;
	QPtrList<UserListItem> findRelavent(const Jid &) const;
	UserListItem *findFirstRelavent(const Jid &) const;
	UserList *userList() const;

	bool checkConnected(QWidget *parent=0);
	void playSound(const QString &);

	QLabel *accountLabel(QWidget *parent=0, bool simpleMode=false);
	QStringList hiddenChats(const Jid &) const;

	int sendMessageEncrypted(const Message &);

	// sucks sucks sucks sucks sucks sucks sucks
	GCContact *findGCContact(const Jid &j);
	QStringList groupchats() const;

	void toggleSecurity(const Jid &, bool);
	bool ensureKey(const Jid &);
	void tryVerify(UserListItem *, UserResource *);

	static QString resultToString(int result);
	static void getErrorInfo(int err, AdvancedConnector *conn, Stream *stream, QCATLSHandler *tlsHandler, QString *_str, bool *_reconn);

	void deleteQueueFile();

signals:
	void disconnected();
	void updatedActivity();
	void updatedAccount();
	void queueChanged();
	void updateContact(const UserListItem &);
	void updateContact(const Jid &);
	void updateContact(const Jid &, bool);
	void nickChanged();
	void pgpKeyChanged();
	void encryptedMessageSent(int, bool);
	void enabledChanged();

public slots:
	void setStatus(const Status &);

	void secondsIdle(int);
	void openNextEvent();

	void dj_sendMessage(const Message &, bool log=true);
	void dj_composeMessage(const Jid &jid, const QString &body);
	void dj_composeMessage(const Jid &jid, const QString &body, const QString &subject, const QString &thread);
	void dj_addAuth(const Jid &);
	void dj_add(const Jid &, const QString &, const QStringList &, bool authReq);
	void dj_authReq(const Jid &);
	void dj_auth(const Jid &);
	void dj_deny(const Jid &);
	void dj_rename(const Jid &, const QString &);
	void dj_remove(const Jid &);

	void actionDefault(const Jid &);
	void actionRecvEvent(const Jid &);
	void actionSendMessage(const Jid &);
	void actionSendMessage(const JidList &);
	void actionSendUrl(const Jid &);
	void actionRemove(const Jid &);
	void actionRename(const Jid &, const QString &);
	void actionGroupRename(const QString &, const QString &);
	void actionHistory(const Jid &);
	void actionOpenChat(const Jid &);
	void actionOpenChatSpecific(const Jid &);
	void actionAgentSetStatus(const Jid &, Status &s);
	void actionInfo(const Jid &);
	void actionAuth(const Jid &);
	void actionAuthRequest(const Jid &);
	void actionAuthRemove(const Jid &);
	void actionAdd(const Jid &);
	void actionGroupAdd(const Jid &, const QString &);
	void actionGroupRemove(const Jid &, const QString &);
	void actionHistoryBox(PsiEvent *);
	void actionTest(const Jid &);
	void actionRegister(const Jid &);
	void actionSearch(const Jid &);
	void actionJoin(const Jid &);
	void actionDisco(const Jid &, const QString &);
	void actionInvite(const Jid &, const QString &);
	void actionSendFile(const Jid &);
	void actionSendFiles(const Jid &, const QStringList&);
	void featureActivated(QString feature, Jid jid, QString node);

	void actionAssignKey(const Jid &);
	void actionUnassignKey(const Jid &);

	void invokeGCMessage(const Jid &);
	void invokeGCChat(const Jid &);
	void invokeGCInfo(const Jid &);
	void invokeGCFile(const Jid &);

private slots:
	void tls_handshaken();
	void cs_connected();
	void cs_securityLayerActivated();
	void cs_needAuthParams(bool, bool, bool);
	void cs_authenticated();
	void cs_connectionClosed();
	void cs_delayedCloseFinished();
	void cs_warning(int);
	void cs_error(int);
	void client_rosterRequestFinished(bool, int, const QString &);
	void resolveContactName();
	void client_rosterItemAdded(const RosterItem &);
	void client_rosterItemUpdated(const RosterItem &);
	void client_rosterItemRemoved(const RosterItem &);
	void client_resourceAvailable(const Jid &, const Resource &);
	void client_resourceUnavailable(const Jid &, const Resource &);
	void client_presenceError(const Jid &, int, const QString &);
	void client_messageReceived(const Message &);
	void client_subscription(const Jid &, const QString &);
	void client_debugText(const QString &);
	void client_groupChatJoined(const Jid &);
	void client_groupChatLeft(const Jid &);
	void client_groupChatPresence(const Jid &, const Status &);
	void client_groupChatError(const Jid &, int, const QString &);
	void client_incomingJidLink();
	void client_incomingFileTransfer();

	void reconnect();
	void disconnect();
	void enableNotifyOnline();

	void slotClientVersionFinished();

	void chatMessagesRead(const Jid &);

	void slotCheckVCard();
	void edb_finished();
	void pgpToggled(bool);
	void pgpKeysUpdated();

	void trySignPresence();
	void pgp_needPassphrase();
	void pgp_signFinished(bool);
	void pgp_verifyFinished(bool);
	void pgp_finished(bool);
	void pgp_decryptFinished(bool);

	void submitPassphrase(const QString &);
	void rejectPassphrase();

	void optionsUpdate();

	void processReadNext(const UserListItem &);
	void processReadNext(const Jid &);

private slots:
	void handleEvent(PsiEvent *);

public:
	class Private;
private:
	Private *d;

	void deleteAllDialogs();
	void stateChanged();
	void simulateContactOffline(UserListItem *);
	void simulateRosterOffline();
	void cpUpdate(const UserListItem &, const QString &rname="", bool fromPresence=false);
	void logEvent(const Jid &, PsiEvent *);
	void queueEvent(PsiEvent *);
	void openNextEvent(const UserListItem &);
	void updateReadNext(const Jid &);
	ChatDlg *ensureChatDlg(const Jid &);
	void lastStepLogin();
	void processIncomingMessage(const Message &);
	void processEncryptedMessage(const Message &);
	void processMessageQueue();
	void processEncryptedMessageNext();
	void processEncryptedMessageDone();
	void verifyStatus(const Jid &j, const Status &s);

	void promptPassphrase();
	void processChats(const Jid &);
	void openChat(const Jid &);
	EventDlg *ensureEventDlg(const Jid &);
	friend class PsiCon;

	bool isDisconnecting, notifyOnlineOk, doReconnect, usingAutoStatus, rosterDone, presenceSent, v_isActive;
	void cleanupStream();

	friend class Private;
};

#endif
