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

// Distributed under an MIT license: http://codemirror.net/LICENSE



/**********************************************************

* This script provides syntax highlighting support for

* the Ntriples format.

* Ntriples format specification:

*     http://www.w3.org/TR/rdf-testcases/#ntriples

***********************************************************/



/*

    The following expression defines the defined ASF grammar transitions.



    pre_subject ->

        {

        ( writing_subject_uri | writing_bnode_uri )

            -> pre_predicate

                -> writing_predicate_uri

                    -> pre_object

                        -> writing_object_uri | writing_object_bnode |

                          (

                            writing_object_literal

                                -> writing_literal_lang | writing_literal_type

                          )

                            -> post_object

                                -> BEGIN

         } otherwise {

             -> ERROR

         }

*/



(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";



CodeMirror.defineMode("ntriples", function() {



  var Location = {

    PRE_SUBJECT         : 0,

    WRITING_SUB_URI     : 1,

    WRITING_BNODE_URI   : 2,

    PRE_PRED            : 3,

    WRITING_PRED_URI    : 4,

    PRE_OBJ             : 5,

    WRITING_OBJ_URI     : 6,

    WRITING_OBJ_BNODE   : 7,

    WRITING_OBJ_LITERAL : 8,

    WRITING_LIT_LANG    : 9,

    WRITING_LIT_TYPE    : 10,

    POST_OBJ            : 11,

    ERROR               : 12

  };

  function transitState(currState, c) {

    var currLocation = currState.location;

    var ret;



    // Opening.

    if     (currLocation == Location.PRE_SUBJECT && c == '<') ret = Location.WRITING_SUB_URI;

    else if(currLocation == Location.PRE_SUBJECT && c == '_') ret = Location.WRITING_BNODE_URI;

    else if(currLocation == Location.PRE_PRED    && c == '<') ret = Location.WRITING_PRED_URI;

    else if(currLocation == Location.PRE_OBJ     && c == '<') ret = Location.WRITING_OBJ_URI;

    else if(currLocation == Location.PRE_OBJ     && c == '_') ret = Location.WRITING_OBJ_BNODE;

    else if(currLocation == Location.PRE_OBJ     && c == '"') ret = Location.WRITING_OBJ_LITERAL;



    // Closing.

    else if(currLocation == Location.WRITING_SUB_URI     && c == '>') ret = Location.PRE_PRED;

    else if(currLocation == Location.WRITING_BNODE_URI   && c == ' ') ret = Location.PRE_PRED;

    else if(currLocation == Location.WRITING_PRED_URI    && c == '>') ret = Location.PRE_OBJ;

    else if(currLocation == Location.WRITING_OBJ_URI     && c == '>') ret = Location.POST_OBJ;

    else if(currLocation == Location.WRITING_OBJ_BNODE   && c == ' ') ret = Location.POST_OBJ;

    else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '"') ret = Location.POST_OBJ;

    else if(currLocation == Location.WRITING_LIT_LANG && c == ' ') ret = Location.POST_OBJ;

    else if(currLocation == Location.WRITING_LIT_TYPE && c == '>') ret = Location.POST_OBJ;



    // Closing typed and language literal.

    else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '@') ret = Location.WRITING_LIT_LANG;

    else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '^') ret = Location.WRITING_LIT_TYPE;



    // Spaces.

    else if( c == ' ' &&

             (

               currLocation == Location.PRE_SUBJECT ||

               currLocation == Location.PRE_PRED    ||

               currLocation == Location.PRE_OBJ     ||

               currLocation == Location.POST_OBJ

             )

           ) ret = currLocation;



    // Reset.

    else if(currLocation == Location.POST_OBJ && c == '.') ret = Location.PRE_SUBJECT;



    // Error

    else ret = Location.ERROR;



    currState.location=ret;

  }



  return {

    startState: function() {

       return {

           location : Location.PRE_SUBJECT,

           uris     : [],

           anchors  : [],

           bnodes   : [],

           langs    : [],

           types    : []

       };

    },

    token: function(stream, state) {

      var ch = stream.next();

      if(ch == '<') {

         transitState(state, ch);

         var parsedURI = '';

         stream.eatWhile( function(c) { if( c != '#' && c != '>' ) { parsedURI += c; return true; } return false;} );

         state.uris.push(parsedURI);

         if( stream.match('#', false) ) return 'variable';

         stream.next();

         transitState(state, '>');

         return 'variable';

      }

      if(ch == '#') {

        var parsedAnchor = '';

        stream.eatWhile(function(c) { if(c != '>' && c != ' ') { parsedAnchor+= c; return true; } return false;});

        state.anchors.push(parsedAnchor);

        return 'variable-2';

      }

      if(ch == '>') {

          transitState(state, '>');

          return 'variable';

      }

      if(ch == '_') {

          transitState(state, ch);

          var parsedBNode = '';

          stream.eatWhile(function(c) { if( c != ' ' ) { parsedBNode += c; return true; } return false;});

          state.bnodes.push(parsedBNode);

          stream.next();

          transitState(state, ' ');

          return 'builtin';

      }

      if(ch == '"') {

          transitState(state, ch);

          stream.eatWhile( function(c) { return c != '"'; } );

          stream.next();

          if( stream.peek() != '@' && stream.peek() != '^' ) {

              transitState(state, '"');

          }

          return 'string';

      }

      if( ch == '@' ) {

          transitState(state, '@');

          var parsedLang = '';

          stream.eatWhile(function(c) { if( c != ' ' ) { parsedLang += c; return true; } return false;});

          state.langs.push(parsedLang);

          stream.next();

          transitState(state, ' ');

          return 'string-2';

      }

      if( ch == '^' ) {

          stream.next();

          transitState(state, '^');

          var parsedType = '';

          stream.eatWhile(function(c) { if( c != '>' ) { parsedType += c; return true; } return false;} );

          state.types.push(parsedType);

          stream.next();

          transitState(state, '>');

          return 'variable';

      }

      if( ch == ' ' ) {

          transitState(state, ch);

      }

      if( ch == '.' ) {

          transitState(state, ch);

      }

    }

  };

});



CodeMirror.defineMIME("text/n-triples", "ntriples");



});

