// CodeMirror, copyright (c) by Marijn Haverbeke and others

// Distributed under an MIT license: https://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");

});

