/***************************************************************************
                          application.h  -  description
                             -------------------
    begin                : Thu Mar 20 2003
    copyright            : (C) 2003 by Mike K. Bennett
    email                : mkb137b@hotmail.com
 ***************************************************************************/

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

#include "../chatmessage.h"

#include <QObject>


// Forward declarations
class Chat;
class MimeMessage;



/**
 * @brief Base class for all application invitations.
 * This class only provides the essentials like accept/cancel notifications.
 *
 * Application invitations can be used to start an out-of-band
 * session such as file transfers, voice and webcam conversations.
 * Other contacts are invited by creating an instance of an Application class,
 * and calling the start() method afterwards.
 * Responses from the other contact are passed to the <code>gotMessage()</code> method.
 * Both MimeApplication and P2PApplication implement their own version of this method.
 * The <code>gotMessage()</code> method also detects whether the contact sent the invitation.
 *
 * To implement your own application handler, create a new class which derives
 * from either MimeApplication or P2PApplication. The new application class should
 * implement the missing <code>contactStarted*</code> and <code>userStarted*</code> methods.
 * The <code>contactStarted*</code> methods are used for sessions started by the other contact (the chat buddy),
 * while the <code>userStarted*</code> methods are used for sessions started by the user itself (the KMess user).
 * Also note how each Application subclass implements a static <code>getAppId()</code>
 * method to return the Application GUID. This GUID is used to detect the invitation type.
 *
 * @author Mike K. Bennett, Diederik van der Boor (mime/p2p stuff)
 * @ingroup Applications
 */
class Application : public QObject
{
  Q_OBJECT

  public:

    enum ApplicationMode
    {
      APP_MODE_NORMAL,         ///< Normal mode (all messages should appear in the Chat Window)
      APP_MODE_ERROR_HANDLER,  ///< Application instance is started to handle an error.
      APP_MODE_DATACAST        ///< Application instance is started to emulate a datacast message (ink receiving, winks in msn6).
    };

    // The constructor
                           Application(const QString &contactHandle);
    // The destructor
    virtual               ~Application();
    // The contact cancelled the session
    virtual void           contactAborted(const QString &message = QString::null);
    // Return the chat the application was originally created for (may be null).
    Chat                  *getChat() const;
    // Return the handle of the other contact
    const QString&         getContactHandle() const;
    // Return the application's identifying cookie
    const QString&         getCookie() const;
    // A command for the application was received (i.e. "Accept" or "Reject")
    void                   gotCommand(QString command);
    // Read the current mode of the application
    int                    getMode() const;
    // Indicate whether the application is closing or not.
    bool                   isClosing() const;
    // Returns whether the application can operate in a multi-chat session, or requires a private chat.
    virtual bool           isPrivateChatRequired() const;
    // Set the chat the application was originally created for.
    void                   setChat( Chat *chat );
    // Set the current mode of the application
    void                   setMode(ApplicationMode mode);
    // Start the application
    void                   start();
    // The user cancelled the session
    virtual void           userAborted();


  protected: // Protected methods

    // Reasons why invitations get cancelled.
    enum ApplicationCancelReason
    {
      CANCEL_INVITATION,           ///< User cancelled the invitation (aka rejected)
      CANCEL_ABORT,                ///< User cancelled the session before it completed (real cancel)
      CANCEL_NOT_INSTALLED,        ///< Requested service is not installed
      CANCEL_TIMEOUT,              ///< Timeout waiting for contact to accept / send data
      CANCEL_FAILED,               ///< Failed to initialize the session / start the app

      CANCEL_INVALID_SLP_CONTENT_TYPE  ///< Got an invalid content-type, abort the session (P2P only)
    };

    // The contact rejected the invitation
    void                   contactRejected(const QString &message = QString::null);
    // Step one of a contact-started chat: the contact invites the user
    virtual void           contactStarted1_ContactInvitesUser(const MimeMessage& message);
    // Step two of a contact-started chat: the user accepts
    virtual void           contactStarted2_UserAccepts();
    // Step three of a contact-started chat: the contact confirms the accept
    virtual void           contactStarted3_ContactConfirmsAccept(const MimeMessage& message);
    // Close the appliation (asks switchboard to delete this object)
    void                   endApplication();
    // Request the application to not delete itself while doing external work, like displaying a dialog.
    void                   delayDeletion( bool doDelay );
    // Return an reject message to display.
    virtual QString        getContactAbortMessage() const;
    // Return a reject message to display.
    virtual QString        getContactRejectMessage() const;
    // Return an abort message to display
    virtual QString        getUserAbortMessage() const;
    // Return a reject message to display
    virtual QString        getUserRejectMessage() const;
    // Generate a random invitation or authorization cookie.
    QString                generateCookie() const;
    // Return the external IP address
    const QString&         getExternalIp() const;
    // Return the local IP address
    const QString&         getLocalIp() const;
    // Read the "user started this app" state.
    bool                   isUserStartedApp() const;
    // Return true if the user should press accept/cancel soon.
    bool                   isWaitingForUser() const;
    // Replace an application's accept/reject/cancel links with another text
    void                   modifyOfferMessage( const QString& newMessage = QString() );
    // Let the user accept or reject the application
    void                   offerAcceptOrReject(const QString& appHtml);
    // Let the user cancel the application
    void                   offerCancel(const QString& appHtml);
    /**
     * @brief Send a cancel message and terminate the application.
     *
     * This method needs to be implemented in the derived classes to send the correct cancel messages.
     * After sending a cancel message, the application should eventually be aborted
     * (either because of a timeout, or direct call to endApplication()).
     *
     * @param cancelReason  Reason for sending the cancel message.
     */
    virtual void           sendCancelMessage(const ApplicationCancelReason cancelReason) = 0;
    // Set the type of application we're starting
    void                   setApplicationType( ChatMessage::MessageType type );
    // Indicate the application is closing or not.
    void                   setClosing(bool closing);
    // Show a message to notify the user of a event (e.g. user invited, cancelled,connecting to host, the transfer is complete, etc..)
    virtual void           showEventMessage(const QString &message, const ChatMessage::ContentsClass contents, bool isIncoming = true );
    // Show a message to notify about a system error (e.g. invitation not supported)
    virtual void           showSystemMessage(const QString &message, const ChatMessage::ContentsClass contents, bool isIncoming = true );
    // Called when the transfer is complete.
    virtual void           showTransferComplete();
    // Show a message to inform about a transfer event (shown in the transfer dialog, e.g. connecting to host)
    virtual void           showTransferMessage(const QString &message);
    // Show the progress made during a transfer.
    virtual void           showTransferProgress( const ulong bytesTransferred );
    // Set the cookie from an INVITE command
    void                   startByInvite(const QString &invitationCookie);
    // The user rejected the invitation
    virtual void           userRejected();
    // Step one of a user-started chat: the user invites the contact
    virtual void           userStarted1_UserInvitesContact();
    // Step two of a user-started chat: the contact accepts
    virtual void           userStarted2_ContactAccepts(const MimeMessage& message);
    // Step three of a user-started chat: the user prepares for the session
    virtual void           userStarted3_UserPrepares();

  private: // Private attributes
    // The chat the application was originally initiatialized in.
    Chat                  *chat_;
    // The application is closing
    bool                   closing_;
    // The applications identifying cookie
    QString                cookie_;
    // Contact handle
    QString                contactHandle_;
    // The application is closing
    bool                   doDelayDeletion_;
    // The current mode
    ApplicationMode        mode_;
    // Current application type
    ChatMessage::MessageType type_;
    // Whether or not the user answered the invitation already
    bool                   userAnswered_;
    // Whether or not the user started the app
    bool                   userStartedApp_;
    // True if waiting for the user to accept
    bool                   waitingForUser_;

  signals: // Signals
    /**
     * Signal that this application likes to display a message
     * @param  message  The message to display.
     */
    void                   applicationMessage( const ChatMessage &message );
    /**
     * Signal that this application needs to update its accept/cancel links with another text
     * @param  messageId   The identifying cookie for the message
     * @param  newMessage  The new message to display.
     * @see Application::getCookie()
     */
    void                   updateApplicationMessage( const QString &messageId, const QString &newMessage );

    /**
     * Signal that this application's activity has ended and that it should be deleted.
     * @param  object  Reference to the this object.
     */
    void                   deleteMe(Application *object);
};

#endif
