// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2011 Emweb bvba, Kessel-Lo, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
#ifndef WT_MAIL_MESSAGE_H_
#define WT_MAIL_MESSAGE_H_

#include <Wt/Mail/Mailbox>

namespace Wt {

  class WStringStream;

  namespace Mail {

/*! \brief Enumeration for a recipient type.
 *
 * \sa Message::addRecipient()
 */
enum RecipientType {
  To, //!< To: recipient
  Cc, //!< Cc: recipient
  Bcc //!< Bcc: recipient (is omitted from the recipients in the message itself)
};

/*! \class Message Wt/Mail/Message Wt/Mail/Message
 *  \brief A mail message.
 *
 * This class represents a MIME-compliant mail message.
 *
 * The message can have a plain text body and an optional HTML body,
 * which when present is encoded as an MIME multipart/alternative. It
 * is recommended to send the same contents both in a plain text and
 * an HTML variant.
 *
 * Recipient names, names, and body text may contain unicode text.
 *
 * \sa Client::send()
 *
 * \ingroup mail
 */
class WT_API Message
{
public:
  /*! \class Header
   *  \brief An SMTP message header.
   * 
   * An SMTP message header is a name/value pair, as defined by RFC 822.
   */
  class WT_API Header 
  {
  public:
    /*! \brief Default constructor.
     */
    Header();

    /*! \brief Constructs a header with a given name and value.
     */
    Header(const std::string& name, const std::string& value);

    /*! \brief Copy constructor.
     */
    Header(const Header& other);

    /*! \brief Sets the header name.
     */
    void setName(const std::string& name);

    /*! \brief Returns the header name.
     *
     * \sa setName()
     */
    const std::string& name() const { return name_; }

    /*! \brief Sets the header value.
     */
    void setValue(const std::string& value);

    /*! \brief Returns the header value.
     *
     * \sa setValue()
     */
    const std::string& value() const { return value_; }

  private:
    std::string name_, value_;
  };

  struct Recipient {
    RecipientType type;
    Mailbox mailbox;
  };

  /*! \brief Default constructor.
   *
   * Creates an empty message. You need to add at least a sender and a recipient
   * to create a valid email message.
   */
  Message();

  /*! \brief Sets the sender mailbox.
   */
  void setFrom(const Mailbox& from);

  /*! \brief Returns the sender mailbox.
   *
   * \sa setFrom()
   */
  const Mailbox& from() const { return from_; }

  /*! \brief Sets the reply-to mailbox.
   */
  void setReplyTo(const Mailbox& replyTo);

  /*! \brief Returns the reply-to mailbox.
   *
   * \sa setReplyTo()
   */
  const Mailbox& replyTo() const { return replyTo_; }

  /*! \brief Sets a subject.
   */
  void setSubject(const WString& subject);

  /*! \brief Returns the subject.
   *
   * \sa setSubject()
   */
  const WString& subject() const;

  /*! \brief Sets the plain text body.
   *
   * This is the plain text mail contents.
   *
   * \sa addHtmlBody()
   */
  void setBody(const WString& text);

  /*! \brief Adds a recipient.
   *
   * A mail can have multiple recipients.
   */
  void addRecipient(RecipientType type, const Mailbox& recipient);

  /*! \brief Returns the recipients.
   *
   * \sa addRecipient()
   */
  const std::vector<Recipient>& recipients() const { return recipients_; }

  /*! \brief Sets a header value.
   *
   * If a header with that value was already defined, it is replaced with
   * the new value. Otherwise, the header is added.
   *
   * \sa addHeader()
   */
  void setHeader(const std::string& name, const std::string& value);

  /*! \brief Adds a header value.
   *
   * A header is added, even if a header with the same name already
   * was present.
   *
   * \sa setHeader()
   */
  void addHeader(const std::string& name, const std::string& value);

  /*! \brief Returns the headers.
   */
  const std::vector<Header>& headers() const { return headers_; }

  /*! \brief Returns a header value.
   *
   * Returns 0 if no header with that name is found.
   */
  const std::string *getHeader(const std::string& name) const;

  /*! \brief Adds an HTML body.
   *
   * The \p text should be an HTML version of the plain text body.
   */
  void addHtmlBody(const WString& text);

  void addAttachment(const std::string& mimeType /* ... */);

  /*! \brief Writes the message to the stream.
   *
   * This writes the message as a MIME 1.0 message to the output stream.
   */
  void write(std::ostream& out) const;

private:
  Mailbox from_, replyTo_;
  std::vector<Recipient> recipients_;
  std::vector<Header> headers_;

  WString subject_, body_, htmlBody_;

  static void encodeChar(WStringStream& s, unsigned char c);
  static void encodeWord(const WString& text, std::ostream& out,
			 bool quoteIfNeeded);
  static void encodeQuotedPrintable(const WString& text, std::ostream& out);

  friend class Mailbox;
};

  }
}

#endif // WT_MAIL_MESSAGE_H_
