/***************************************************************************
                          msnsockethttp.h  -  description
                             -------------------
    begin                : Thu Apr 4 2008
    copyright            : (C) 2008 by Valerio Pilo
    email                : valerio@kmess.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 MSNSOCKETHTTP_H
#define MSNSOCKETHTTP_H

#include "msnsocketbase.h"

#include <QHash>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QStringList>
#include <QTime>
#include <QTimer>

// Forward declarations
class CurrentAccount;
class QNetworkReply;
class QSslError;



/**
 * @brief Basic I/O functionality for the MSN server protocol over a HTTP connection.
 *
 * This is a low-level class used used by MsnConnection.
 * The class provides the following facilities:
 * - HTTP-only connection to the MSN servers, with exclusive usage of ports 80 and 443.
 * - sending/receiving raw protocol data.
 *
 * With HTTP the server has no way of contacting the client by itself. Everytime we
 * send a request to the server (the "MSN HTTP Gateway"), it will send along with the answer
 * a full list of messages which we didn't receive yet. So if we've got nothing to send,
 * we're forced to periodically send 'poll' requests. These are bogus calls which exist only
 * to allow the gateway to send any new message back.
 *
 * In any given moment, there may only be one active message. This means that if we send two
 * subsequent requests, we will be disconnected immediately with a '400 Bad Request' response.
 * Therefore, this class implements a 1-item-wide sending window. It's not necessary to apply
 * it to receiving also, since the server just responds in order.
 *
 * Data from the server (the "HTTP Gateway") is handled by the slotDataReceived() slot.
 * This method receives responses to HTTP requests made by the class; they contain a list of
 * new undelivered messages. The slotDataReceived() method splits it up to individual commands
 * and forwards the received commands to MsnConnection individually.
 *
 * Simple scheme of requests/responses:
 *  - Got a request to send. Send it immediately.
 *  - Received a response with messages. Have queued requests?
 *    - Yes. Send the next now.
 *    - No. Send a polling request now.
 *  - Received an empty response (without messages). Have queued requests?
 *    - Yes. Send the next now.
 *    - No. What kind of message was last sent?
 *      - A command. Send a poll in 5 seconds.
 *      - A poll. Send another poll in 10 seconds.
 *
 * @author Valerio Pilo <valerio@kmess.org>
 * @ingroup NetworkCore
 */
class MsnSocketHttp : public MsnSocketBase
{
  Q_OBJECT


  public: // Public methods
    // The constructor
                         MsnSocketHttp( ServerType serverType );
    // The destructor
                        ~MsnSocketHttp();
    // Connect to the given server
    void                 connectToServer( const QString& server = QString(), const quint16 port = 0 );
    // Disconnect from the server
    void                 disconnectFromServer( bool isTransfer = false );
    // Return the local IP address
    QString              getLocalIp() const;
    // Set whether to send pings or not
    void                 setSendPings( bool sendPings );
    // Write data to the socket without conversions
    qint64               writeBinaryData( const QByteArray& data );
    // Write data to the socket
    qint64               writeData( const QString& data );


  private: // Private methods
    // Clean up the connection
    void                 cleanUp();
    // Dump the content of requests and replies
    void                 dump( void *obj, QByteArray data, bool isRequest );
    // Sends the next queued request
    void                 sendNextRequest();
    // Change the server connection gateway
    void                 setGateway( QString host );


  private slots: // Private slots
     // Send a polling message to the server, to retrieve pending commands
    void                 slotQueryServer();
    // Read received data and pass along the contained commands
    void                 slotReplyReceived( QNetworkReply *reply );


  private: // Private structures
    // Structure to hold all the useful data about an HTTP request
    struct RequestInfo
    {
      // Special request parameters to be sent along with the data
      QString            requestQueryString;
      // The actual contents of the request
      QByteArray         data;
    };


  private: // Private attributes
    // URL to specify in the queries
    QString                baseServerPath_;
    // State variable to detect whether it's possible or not to send another request
    bool                   canSendRequests_;
    // Time at which the last request has been sent
    QTime                  lastRequestTime_;
    // Saved gateway address
    QString                gatewayAddress_;
    // The HTTP interface
    QNetworkAccessManager *http_;
    // true if the last sent request was a polling message
    bool                   lastRequestWasPolling_;
    // true if the last received response didn't carry any new commands
    bool                   lastResponseWasEmpty_;
    // Time counter to regularly report pings to the application
    QDateTime              lastPing_;
    // Next request's ID
    QString                nextRequestId_;
    // Next request's parameters
    QString                nextRequestParameters_;
    // A timer to regularly query the server for new commands
    QTimer                 pollingTimer_;
    // List of requests waiting to be sent
    QList<RequestInfo>     queuedRequests_;
    // Container for never-changing request information
    QNetworkRequest        requestHeader_;
    // Are we sending pings?
    bool                   sendPings_;
    // Hashmap of non answered requests
    QList<QNetworkReply*>  unansweredRequests_;

};



#endif
