text: /**
   * Back-end draft abstraction.
   *
   * Drafts are saved to folder storage and look almost exactly like received
   * messages.  The primary difference is that attachments that are in the
   * process of being attached are stored in an `attaching` field on the
   * `BodyInfo` instance and that they are discarded on load if still present
   * (indicating a crash/something like a crash during the save process).
   *
   **/
  
  define(function(require) {
  
  var mailRep = require('../db/mail_rep');
  
  /**
   * Create a new header and body for a draft by extracting any useful state
   * from the previous draft's persisted header/body and the revised draft.
   *
   * @method mergeDraftStates
   * @param oldHeader {HeaderInfo}
   * @param oldBody {BodyInfo}
   * @param newDraftRep {DraftRep}
   * @param newDraftInfo {Object}
   * @param newDraftInfo.id {Number}
   * @param newDraftInfo.suid {SUID}
   * @param newDraftInfo.date {Number}
   */
  function mergeDraftStates(oldHeader, oldBody,
                            newDraftRep, newDraftInfo,
                            universe) {
  
    var identity = universe.getIdentityForSenderIdentityId(newDraftRep.senderId);
  
    // -- convert from compose rep to header/body rep
    var newHeader = mailRep.makeHeaderInfo({
      id: newDraftInfo.id,
      srvid: null, // stays null
      suid: newDraftInfo.suid, // filled in by the job
      // we currently don't generate a message-id for drafts, but we'll need to
      // do this when we start appending to the server.
      guid: oldHeader ? oldHeader.guid : null,
      author: { name: identity.name, address: identity.address},
      to: newDraftRep.to,
      cc: newDraftRep.cc,
      bcc: newDraftRep.bcc,
      replyTo: identity.replyTo,
      date: newDraftInfo.date,
      flags: [],
      hasAttachments: oldHeader ? oldHeader.hasAttachments : false,
      subject: newDraftRep.subject,
      snippet: newDraftRep.body.text.substring(0, 100),
    });
    var newBody = mailRep.makeBodyInfo({
      date: newDraftInfo.date,
      size: 0,
      attachments: oldBody ? oldBody.attachments.concat() : [],
      relatedParts: oldBody ? oldBody.relatedParts.concat() : [],
      references: newDraftRep.referencesStr,
      bodyReps: []
    });
    newBody.bodyReps.push(mailRep.makeBodyPart({
      type: 'plain',
      part: null,
      sizeEstimate: newDraftRep.body.text.length,
      amountDownloaded: newDraftRep.body.text.length,
      isDownloaded: true,
      _partInfo: {},
      content: [0x1, newDraftRep.body.text]
    }));
    if (newDraftRep.body.html) {
      newBody.bodyReps.push(mailRep.makeBodyPart({
        type: 'html',
        part: null,
        sizeEstimate: newDraftRep.body.html.length,
        amountDownloaded: newDraftRep.body.html.length,
        isDownloaded: true,
        _partInfo: {},
        content: newDraftRep.body.html
      }));
    }
  
    return {
      header: newHeader,
      body: newBody
    };
  }
  
  function convertHeaderAndBodyToDraftRep(account, header, body) {
    var composeBody = {
      text: '',
      html: null,
    };
  
    // Body structure should be guaranteed, but add some checks.
    if (body.bodyReps.length >= 1 &&
        body.bodyReps[0].type === 'plain' &&
        body.bodyReps[0].content.length === 2 &&
        body.bodyReps[0].content[0] === 0x1) {
      composeBody.text = body.bodyReps[0].content[1];
    }
    // HTML is optional, but if present, should satisfy our guard
    if (body.bodyReps.length == 2 &&
        body.bodyReps[1].type === 'html') {
      composeBody.html = body.bodyReps[1].content;
    }
  
    var attachments = [];
    body.attachments.forEach(function(att) {
      attachments.push({
        name: att.name,
        blob: att.file
      });
    });
  
    var draftRep = {
      identity: account.identities[0],
      subject: header.subject,
      body: composeBody,
      to: header.to,
      cc: header.cc,
      bcc: header.bcc,
      referencesStr: body.references,
      attachments: attachments
    };
  }
  
  /**
   * Given the HeaderInfo and BodyInfo for a draft, create a new header and body
   * suitable for saving to the sent folder for a POP3 account.  Specifically:
   * - mark the message as read
   * - make sure body.attaching does not make it through
   * - strip the Blob references so we don't accidentally keep the base64
   *   encoded attachment parts around forever and clog up the disk.
   * - avoid accidental use of the same instances between the drafts folder and
   *   the sent folder
   *
   * @param header {HeaderInfo}
   * @param body {BodyInfo}
   * @param newInfo
   * @param newInfo.id
   * @param newInfo.suid {SUID}
   * @return { header, body }
   */
  function cloneDraftMessageForSentFolderWithoutAttachments(header, body,
                                                            newInfo) {
    // clone the header (drops excess fields)
    var newHeader = mailRep.makeHeaderInfo(header);
    // clobber the id/suid
    newHeader.id = newInfo.id;
    newHeader.suid = newInfo.suid;
    // Mark the message as read.  We are clobbering other flags, but we don't
    // currently support a way for them to exist.
    newHeader.flags = ['\\Seen'];
  
    // clone the body, dropping excess fields like "attaching".
    var newBody = mailRep.makeBodyInfo(body);
    // transform attachments
    if (newBody.attachments) {
      newBody.attachments = newBody.attachments.map(function(oldAtt) {
        var newAtt =  mailRep.makeAttachmentPart(oldAtt);
        // mark the attachment as non-downloadable
        newAtt.type = 'application/x-gelam-no-download';
        // get rid of the blobs!
        newAtt.file = null;
        // we will keep around the sizeEstimate so they know how much they sent
        // and we keep around encoding/charset/textFormat because we don't care
  
        return newAtt;
      });
    }
    // We currently can't generate related parts, but just in case.
    if (newBody.relatedParts) {
      newBody.relatedParts = [];
    }
    // Body parts can be transferred verbatim.
    newBody.bodyReps = newBody.bodyReps.map(function(oldRep) {
      return mailRep.makeBodyPart(oldRep);
    });
  
    return { header: newHeader, body: newBody };
  }
  
  
  return {
    mergeDraftStates: mergeDraftStates,
    convertHeaderAndBodyToDraftRep: convertHeaderAndBodyToDraftRep,
    cloneDraftMessageForSentFolderWithoutAttachments:
      cloneDraftMessageForSentFolderWithoutAttachments
  };
  
  }); // end define
  