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

#include <QString>



/**
 * A message using MSN P2P protocol.
 *
 * @author Michael Jarrett (JudgeBeavis@hotmail.com), Diederik van der Boor (vdboor --at-- codingdomain.com)
 * @ingroup NetworkCore
 */
class P2PMessage
{
  public:  // Enums

  enum MsnP2PFlags
  {
    MSN_FLAG_NEGATIVE_ACK      = 0x01,       /// NAK. P2P Message size and offset fields are invalid or out of order.
    MSN_FLAG_ACK               = 0x02,       /// ACK. P2P Message is an ACK
    MSN_FLAG_WAITING           = 0x04,       // Other client is waiting for a reply
    MSN_FLAG_WAITING_FOR_ACK   = 0x06,       // Other client is waiting for an ack reply / requesting ack response (we guess)
    MSN_FLAG_ERROR             = 0x08,       /// RST. Error (possibly at binary level)
    MSN_FLAG_OBJECT_DATA       = 0x20,       /// MsnObject data (picture data, etc..)
    MSN_FLAG_ABORTED_SENDING   = 0x40,       /// Sender prematurely data transfer initiated by itself. Also received when sender aborts in response to a 0x08 or BYE at unexpected moment.
    MSN_FLAG_ABORTED_RECEIVING = 0x80,       /// TLP_ERR. Receiver premature aborted the data trasnfer. Also received when the receiver doesn't receive any data from the sender's "transport layer proxy??".
    MSN_FLAG_DC_HANDSHAKE      = 0x100,      // Direct connection handshake
    MSN_FLAG_DATA_2009         = 0x1000000,  // Used instead of 0x00 in WLM 2009
    MSN_FLAG_FILE_DATA         = 0x1000030   // File transfer (is: 0x10 | 0x20 | 0x1000000)
  };

public:  // Constructors
//  /**
//   * Build an (empty) P2P message.
//   */
//  P2PMessage();

  // Build a P2P message based on the received binary data.
                       P2PMessage(const char *data, uint size);

  // Build a P2P message based on the received binary data.
                       P2PMessage(const QByteArray &message);


public:    // Accessors
  // Retreives the current session ID.
  quint32              getSessionID() const;
  // Retreives the current message ID.
  quint32              getMessageID() const;
  // Retreives the current data message offset.
  quint32              getDataOffset() const;
  // Retreives the current data message size.
  quint32              getDataSize() const;
  // Retreives the message flags. */
  quint32              getFlags() const;
  // Retreives the total message size.
  quint32              getTotalSize() const;
  // Retrieves the ack message ID field.
  quint32              getAckSessionID() const;
  // Retreives the ack unique ID field.
  quint32              getAckUniqueID() const;
  // Retreives the ack data size field.
  quint32              getAckDataSize() const;
  // Retreives the nonce field (for direct connection handshake.
  QString              getNonce() const;

  // Retreives the actual data.
  const char          *getData() const;

  // Returns true if the contact aborted the data transfer by the other client.
  bool                 isAbortedReceivingAck() const;
  // Returns true if the contact aborted it's own data transfer.
  bool                 isAbortedSendingAck() const;
  // Returns true if the ACK flag is set
  bool                 isAck() const;
  // Returns true if the message is a direct-connection handshake message.
  bool                 isConnectionHandshake() const;
  // Returns true if the binary-error flag is set.
  bool                 isError() const;
  // Return true if the file-data flag is set.
  bool                 isData() const;
  // Return true if the message is the data preparation message.
  bool                 isDataPreparation() const;
  // Return true if this is an fragment (splitted message packet).
  bool                 isFragment() const;
  // Return true if this is the last part of a message.
  bool                 isLastFragment() const;
  // Returns true of the nak flag is set
  bool                 isNegativeAck() const;
  // Return true if this is part of an SLP message.
  bool                 isSlpData() const;
  // Returns true of the waiting-for-ack flag is set
  bool                 isWaitingForAck() const;
  // Returns true of the waiting-for-reply flag is set
  bool                 isWaitingForReply() const;


  // Copy integers into the binary header.
  static void          insertBytes(QByteArray& buffer, const unsigned int value, const int offset);
  // Copy short integers into the binary header.
  static void          insertShortBytes(QByteArray &buffer, const unsigned short value, const int offset);
  // Copy a nonce string into the binary header.
  static void          insertNonce(QByteArray& buffer, const QString &nonce, const int offset = 32);
  // Copy short integers into the binary header.
  static void          insertUtf16String(QByteArray &buffer, const QString &value, int offset);
  // Extracts the bytes from the data block.
  static unsigned int  extractBytes(const char *data, const int offset);
  // Extracts the bytes from the data block.
  static quint32       extractLongBytes(const char *data, const int offset);
  // Extracts the nonce string from the data header.
  static QString       extractNonce(const char *data, const int offset = 32);
  // Extracts an utf16 string from the data header.
  static QString       extractUtf16String(const char *data, const int offset, int size);


private:    // Helper functions
  // Extract the fields from the P2P binary header.
  void                 parseP2PHeader();


private:    // Data
  QByteArray           message_;

  // Session ID identifying which (MSN-)SLP we're dealing with.
  quint32              sessionID_;
  // Message ID identifying which message packet we're dealing with.
  quint32              messageID_;
  // Message offset.. (message packets can be split)
  quint32              dataOffset_;
  // Message size..
  quint32              dataSize_;
  // Message flags.
  quint32              flags_;
  // Total message size
  quint32              totalSize_;
  // Ack session id.
  quint32              ackSessionID_;
  // Ack Unique id.
  quint32              ackUniqueID_;
  // Ack data size.
  quint32              ackDataSize_;
};


#endif
