// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

var rfc2822 = [
  "From", "Sender", "Reply-To", "To", "Cc", "Bcc", "Message-ID",
  "In-Reply-To", "References", "Resent-From", "Resent-Sender", "Resent-To",
  "Resent-Cc", "Resent-Bcc", "Resent-Message-ID", "Return-Path", "Received"
];
var rfc2822NoEmail = [
  "Date", "Subject", "Comments", "Keywords", "Resent-Date"
];

CodeMirror.registerHelper("hintWords", "mbox", rfc2822.concat(rfc2822NoEmail));

var whitespace = /^[ \t]/;
var separator = /^From /; // See RFC 4155
var rfc2822Header = new RegExp("^(" + rfc2822.join("|") + "): ");
var rfc2822HeaderNoEmail = new RegExp("^(" + rfc2822NoEmail.join("|") + "): ");
var header = /^[^:]+:/; // Optional fields defined in RFC 2822
var email = /^[^ ]+@[^ ]+/;
var untilEmail = /^.*?(?=[^ ]+?@[^ ]+)/;
var bracketedEmail = /^<.*?>/;
var untilBracketedEmail = /^.*?(?=<.*>)/;

function styleForHeader(header) {
  if (header === "Subject") return "header";
  return "string";
}

function readToken(stream, state) {
  if (stream.sol()) {
    // From last line
    state.inSeparator = false;
    if (state.inHeader && stream.match(whitespace)) {
      // Header folding
      return null;
    } else {
      state.inHeader = false;
      state.header = null;
    }

    if (stream.match(separator)) {
      state.inHeaders = true;
      state.inSeparator = true;
      return "atom";
    }

    var match;
    var emailPermitted = false;
    if ((match = stream.match(rfc2822HeaderNoEmail)) ||
        (emailPermitted = true) && (match = stream.match(rfc2822Header))) {
      state.inHeaders = true;
      state.inHeader = true;
      state.emailPermitted = emailPermitted;
      state.header = match[1];
      return "atom";
    }

    // Use vim's heuristics: recognize custom headers only if the line is in a
    // block of legitimate headers.
    if (state.inHeaders && (match = stream.match(header))) {
      state.inHeader = true;
      state.emailPermitted = true;
      state.header = match[1];
      return "atom";
    }

    state.inHeaders = false;
    stream.skipToEnd();
    return null;
  }

  if (state.inSeparator) {
    if (stream.match(email)) return "link";
    if (stream.match(untilEmail)) return "atom";
    stream.skipToEnd();
    return "atom";
  }

  if (state.inHeader) {
    var style = styleForHeader(state.header);

    if (state.emailPermitted) {
      if (stream.match(bracketedEmail)) return style + " link";
      if (stream.match(untilBracketedEmail)) return style;
    }
    stream.skipToEnd();
    return style;
  }

  stream.skipToEnd();
  return null;
};

CodeMirror.defineMode("mbox", function() {
  return {
    startState: function() {
      return {
        // Is in a mbox separator
        inSeparator: false,
        // Is in a mail header
        inHeader: false,
        // If bracketed email is permitted. Only applicable when inHeader
        emailPermitted: false,
        // Name of current header
        header: null,
        // Is in a region of mail headers
        inHeaders: false
      };
    },
    token: readToken,
    blankLine: function(state) {
      state.inHeaders = state.inSeparator = state.inHeader = false;
    }
  };
});

CodeMirror.defineMIME("application/mbox", "mbox");
});
