/***************************************************************************
 *   Copyright (C) 2004 - 2005 by Raphael Langerhorst                      *
 *   raphael-langerhorst@gmx.at                                            *
 *                                                                         *
 *   Permission is hereby granted, free of charge, to any person obtaining *
 *   a copy of this software and associated documentation files (the       *
 *   "Software"), to deal in the Software without restriction, including   *
 *   without limitation the rights to use, copy, modify, merge, publish,   *
 *   distribute, sublicense, and/or sell copies of the Software, and to    *
 *   permit persons to whom the Software is furnished to do so, subject to *
 *   the following conditions:                                             *
 *                                                                         *
 *   The above copyright notice and this permission notice shall be        *
 *   included in all copies or substantial portions of the Software.       *
 *                                                                         *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
 *   OTHER DEALINGS IN THE SOFTWARE.                                       *
 ***************************************************************************/

#ifndef GXMPPNETWORK_H
#define GXMPPNETWORK_H

#include "GXmlNetwork.h"

#include <xmpp.h>
#include <qca.h>
#include <qmutex.h>

class QCustomEvent;

namespace GWE
{

class GXmppMessageQueue;

/**
 * \Class GXmppNetwork GXmppNetwork.h
 * \brief Implements XML based networking using the XMPP-Core protocol.
 * @author Raphael Langerhorst
 *
 * This XML network implementation represents the GWE Server as an XMPP client.
 *
 * This Network implementation uses the XMPP library Iris, by Justin Karneges.
 * 
 * Please note that the GXmppNetwork class just provides the protocol regarding
 * XMPP. The communication logic between GWE Servers is fully included in the
 * GXmlDataController which just uses this class for data transport.
 * The GXmppNetwork takes care of different stanza kinds. Tags in a message
 * stanza are handled as normal messages and handed to the data controller.
 * 
 * @see http://www.xmpp.org/
 * @see http://delta.affinix.com/iris/
 */
 
class GXmppNetwork : public GXmlNetwork, protected QMutex
{
  Q_OBJECT
  
  private:
  
  /**
   * The password used for authentication.
   */
  QString Password;
  
  protected:
  
  /**
   * Network connection active.
   */
  bool Active;
  
  /**
   * Connected to the XMPP network.
   */
  bool Connected;
  
  /**
   * Currently connecting?
   */
  bool Connecting;
  
  /**
   * XMPP related objects created.
   */
  bool XmppLayerCreated;
  
  /**
   * CMPP Connection to an XMPP Server.
   */
  XMPP::AdvancedConnector* XmppConnector;
  
  /**
   * TLS for security.
   */
  QCA::TLS* Tls;
  
  /**
   * TLS handler used by the connection.
   */
  XMPP::QCATLSHandler* TlsHandler;
  
  /**
   * The stream that is used to transport data.
   */
  XMPP::ClientStream* Stream;
  
  /**
   * The JID that identifies this GWE Server in an XMPP network.
   * @note A GWE Server instance is a client in the sense of an XMPP network!
   */
  XMPP::Jid NetworkId;
  
  /**
   * Stores the subscription state of known servers.
   * This XmppNetwork class always tries to achieve a subscription state
   * of "subscribed".
   * The map key's are the servers and the subscription states are the values.
   * See RFC 3921 for possible states.
   */
  QMap<QString,QString> SubscriptionStates;
  
  /**
   * As long as two communication partners are not subscribed to each
   * other information cannot be exchanged. If data is to be sent,
   * the first thing to do is to create a presence subscription. As
   * soon as a communication partner is subscribed, queued messages
   * that are stored in this message queue can be sent for the particular
   * peer.
   */
  GXmppMessageQueue* MessageQueue;
  
  /**
   * Set to true if the network should stay connected.
   * In this case reinitializing the network will be done
   * automatically if the network got disconnected.
   * closeNetwork() sets this to false before shutting down.
   */
  bool StayConnected;
  
  protected slots:
  
  /**
   * Creates all XMPP related member objects: XmppConnector, Tls, TlsHandler, Stream.
   */
  bool createXmppLayer();
  
  /**
   * Deletes all XMPP related member objects - be careful!! Shut down the network beforehand.
   * @param force if set to TRUE then all objects will be deleted no matter what the state varaibles are.
   * @see closeNetwork()
   * @note This gets automatically called when the object is deleted.
   */
  bool deleteXmppLayer(bool force);
  
  protected:
    
    /**
     * Processes queued data events - if pending data has to be sent.
     * The recognised event type is QCustomEvent with type 65001 and
     * data should be a (pointer to a) QString. These strings are
     * then sent out.
     * 
     * All event creation is done internally, in particular in the
     * send methods.
     */
    virtual void customEvent(QCustomEvent* event);
    
    /**
     * Checks if presence subscription is active for given destination.
     */
    bool isSubscribed(QString destination);
    
    /**
     * Checks if any messages are queued for given destination
     * and sends all queued messages.
     */
    void sendQueuedMessages(QString destination);

  protected slots:

    /**
     * Sends a <presence/> heartbeat.
     */
    void sendHeartbeat();
  
  public:
  
  /**
   * Constructors
   * @param full_jid a string representation of a full JID as defined by the XMPP protocol
   * @see setJid()
   */
  GXmppNetwork(QString full_jid = "", QObject *parent = 0, const char *name = 0);

  /**
   * Virtual Destructor.
   * All active network connections are closed.
   */
  virtual ~GXmppNetwork();
  
  // GXmlNetwork implementation BEGIN //

  virtual bool isConnected();

  /**
   * @returns the network ID of this GWE Server instance.
   *
   * @see NetworkId
   */
  virtual QString getNetworkId() const;
  
  public slots:
  
  /**
   * Initialization.
   */
  virtual bool initNetwork();
  
  /**
   * Issues a single shot timer to call initNetwork()
   * Useful when wanting to reconnect but being in the middle
   * of something (that is, in a slot)
   */
  virtual void reconnectNetwork();
   
  /**
   * Shuts down the network.
   * This should be called when the GWE Server is shutting down,
   * and AFTER all required tasks were performed to allow safe
   * shutdown (moving data to other server, etc.).
   */
  virtual bool closeNetwork();
  
  /**
   * Sets the password to be used, clear text at the moment!!
   */
  virtual void setPassword(const QString& password);
  
   
  // DATA TRANSPORTING
   
  /**
   * Add data for transportation.
   * 
   * This method constructs a message XML element with a to attribute set to
   * given destination. Inside this element the actual data is inserted.
   * 
   * @param data The data that will be sent to the given network destination.
   * @param destination The GWE Server to which the data should be sent to.
   *
   * @see flushOutput()
   */
  virtual bool send(QDomElement data, const QString& destination);

  /**
   * Given string is directly sent, it's the responsibility of the application
   * to make it XML compliant.
   * 
   * Do not forget that the above send member function creates a
   * message XML element in which the given data is inserted. Here,
   * such an element is not created, if it should be present, it has to
   * be included in the given data string.
   */
  virtual bool send(const QString& data);
  
  /**
   * Send all pending output data. This call blocks until all data was sent.
   */
  virtual bool flushOutput();
  
  /**
   * Subscribes presence with given destination.
   * This will either result in a destination not available if the
   * destination is offline or in a successfull presence subscription
   * in which case the destination is available.
   * 
   * Available status is communicated with the signal
   * presenceChanged(QString server, bool available)
   * 
   * @see GXmlNetwork::presenceChanged();
   */
  virtual void makeDestinationAvailable(const QString& destination);
  
  // GXmlNetwork implementation END //
  
  
  // XMPP slots and signals for network management BEGIN //
   
  protected slots:
  
  // CONNECTOR SLOTS //
  
  void connectorServerLookup(const QString& server);
  void connectorServerResult(bool success);
  void connectorHttpSyncStarted();
  void connectorHttpSyncFinished();
  
  // TLS SLOTS //
  
  void tlsHandshaken();
  
  // STREAM SLOTS //
  
  void clientStreamConnected();
  void clientStreamSecurityLayerActivated(int);
  void clientStreamNeedAuthenticationParameters(bool,bool,bool);
  void clientStreamAuthenticated();
  void clientStreamConnectionClosed();
  void clientStreamDelayedCloseFinished();
  void clientStreamReadyRead();
  void clientStreamStanzaWritten();
  
  void clientStreamWarning(int w);
  void clientStreamError(int e);
  
  // XMPP slots and signals for network management END //
  
};

}

#endif //GXMPPNETWORK_H

