/***************************************************************************
   Copyright 2006 David Nolden <david.nolden.kdevelop@art-master.de>
***************************************************************************/

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

#include "networkfwd.h"
#include "messageinterface.h"
#include "binder.h"
#include "networkexport.h"
///Since objects must have external linkage to be usable as template-arguments, these must be defined here.

namespace Teamwork {

typedef std::vector<char> DataVector;

/** Example for a custom Message:
class CustomMessage : public RawMessage {
  DECLARE_MESSAGE( CustomMessage, RawMessage, 83 );
  typedef vector<MyType> MyDataType;
  MyDataType myData;

  template<class Arch>
  void serial( Arch& arch ) {
    arch & myData;
}
  public:

  CustomMessage( const MessageConstructionInfo& info, MyDataType& data ) :  RawMessage( info(this) ), myData( data ) {
}

  CustomMessage( InArchive& arch, const MessageInfo& info ) : RawMessage( arch, info ) {
    serial( arch );
}

  virtual void serialize( OutArchive& arch ) {
    Precursor::serialize( arch );
    serial( arch );
}
};
 */

 class MessageConstructionInfo;
 /**MessageConstructionInfo is a class used while constructing messages, that makes sure that the name of the most derived message will be passed on to RawMessage.
  *Use it by simply passing the this-pointer of each constructed message while passing it to the parent-message. */

 class NETWORK_EXPORT MessageConstructionInfo {
 public:
   //This is the constructor you are supposed to use when creating a message(use the automatic conversion from MessageTypeSet&)
   MessageConstructionInfo( const MessageTypeSet& rhs );

   //Use this to pass MessageConstructionInfo up to the parent, giving "this" as argument.
    template<class Message>
    MessageConstructionInfo operator() (Message* ) const {
      return MessageConstructionInfo( name_.empty() ? Message::staticName() : name_, typeSet_ );
    }

    const MessageTypeSet& typeSet() const;

    const std::string name() const;

    MessageInfo messageInfo() const;

    //operator () must be used when passing the construction-info to the parent
    MessageConstructionInfo( const MessageConstructionInfo& rhs );

 private:
    MessageConstructionInfo( const std::string& name, const MessageTypeSet& typeSet_ );
    MessageConstructionInfo& operator=( const MessageConstructionInfo& );
    std::string name_;
    const MessageTypeSet& typeSet_;
 };

  class NETWORK_EXPORT RawMessage : public MessageInterface
  {
    DECLARE_MESSAGE( RawMessage, MessageInterface, 1 );

    MessageInfo info_;
    DataVector body_;

    public:

      RawMessage( const MessageConstructionInfo& messageTypes, const DataVector& data );

      ///This should be used to indicate that this message is a reply to the other message(replyTarget)
      void setReply( MessageInterface* replyTarget );

      RawMessage( InArchive& from, const MessageInfo& info );

      virtual void serialize( OutArchive& target );

      virtual const MessageInfo& info() const;

      virtual MessageInfo& info();

      /**This is called once a message has been tried to be sent, with the appropriate result, and can be used by the message to give some feedback to the sender. The Session used to send the message is still locked.
       */
      virtual void result( bool success );

      /**Returns a reference to the data-store of this raw message. It does not include data serialized to inherited messages. */
      DataVector& body();

      /**Returns a reference to the data-store of this raw message. It does not include data serialized to inherited messages. */
      const DataVector& body() const;
  };


  class NETWORK_EXPORT TextMessage : public RawMessage {
    DECLARE_MESSAGE( TextMessage, RawMessage, 3 );
    public:
      explicit TextMessage( const MessageConstructionInfo& messageTypes, const std::string& text = "" );

      TextMessage( InArchive& from, const MessageInfo& info );

      std::string text() const;
  };

  struct NETWORK_EXPORT SystemMessage : public TextMessage
  {
    DECLARE_MESSAGE( SystemMessage, TextMessage, 2 );
    public:
      enum Message {
        NoMessage,
        LoginSuccess,
        LoginFailedUnknown,
        BadAuthentication,
        ServerBusy,
        Kicked,
        BadTarget,
        StoredOnServer,
        AlreadyLoggedIn,
        GetUserList,
        SerializationFailed
      };
    private:
      Message msg_;

      template<class Arch>
      void serial( Arch& arch ) {
        arch & msg_;
      }
    public:
      SystemMessage( const MessageConstructionInfo& messageTypes, Message msg, const string& ptext="" );

      SystemMessage( InArchive& arch, const MessageInfo& info );

      virtual void serialize( OutArchive& arch );

      Message message();

      string messageAsString();
  };

  typedef Binder< RawMessage > ::
  Append< TextMessage >
  ::Result::Append<SystemMessage>::Result StandardMessageTypes;
}

// kate: space-indent on; indent-width 2; tab-width 2; replace-tabs on

#endif
