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

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



/*

 * =====================================================================================

 *

 *       Filename:  mode/asterisk/asterisk.js

 *

 *    Description:  CodeMirror mode for Asterisk dialplan

 *

 *        Created:  05/17/2012 09:20:25 PM

 *       Revision:  none

 *

 *         Author:  Stas Kobzar (stas@modulis.ca),

 *        Company:  Modulis.ca Inc.

 *

 * =====================================================================================

 */



(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("asterisk", function() {

  var atoms    = ["exten", "same", "include","ignorepat","switch"],

      dpcmd    = ["#include","#exec"],

      apps     = [

                  "addqueuemember","adsiprog","aelsub","agentlogin","agentmonitoroutgoing","agi",

                  "alarmreceiver","amd","answer","authenticate","background","backgrounddetect",

                  "bridge","busy","callcompletioncancel","callcompletionrequest","celgenuserevent",

                  "changemonitor","chanisavail","channelredirect","chanspy","clearhash","confbridge",

                  "congestion","continuewhile","controlplayback","dahdiacceptr2call","dahdibarge",

                  "dahdiras","dahdiscan","dahdisendcallreroutingfacility","dahdisendkeypadfacility",

                  "datetime","dbdel","dbdeltree","deadagi","dial","dictate","directory","disa",

                  "dumpchan","eagi","echo","endwhile","exec","execif","execiftime","exitwhile","extenspy",

                  "externalivr","festival","flash","followme","forkcdr","getcpeid","gosub","gosubif",

                  "goto","gotoif","gotoiftime","hangup","iax2provision","ices","importvar","incomplete",

                  "ivrdemo","jabberjoin","jabberleave","jabbersend","jabbersendgroup","jabberstatus",

                  "jack","log","macro","macroexclusive","macroexit","macroif","mailboxexists","meetme",

                  "meetmeadmin","meetmechanneladmin","meetmecount","milliwatt","minivmaccmess","minivmdelete",

                  "minivmgreet","minivmmwi","minivmnotify","minivmrecord","mixmonitor","monitor","morsecode",

                  "mp3player","mset","musiconhold","nbscat","nocdr","noop","odbc","odbc","odbcfinish",

                  "originate","ospauth","ospfinish","osplookup","ospnext","page","park","parkandannounce",

                  "parkedcall","pausemonitor","pausequeuemember","pickup","pickupchan","playback","playtones",

                  "privacymanager","proceeding","progress","queue","queuelog","raiseexception","read","readexten",

                  "readfile","receivefax","receivefax","receivefax","record","removequeuemember",

                  "resetcdr","retrydial","return","ringing","sayalpha","saycountedadj","saycountednoun",

                  "saycountpl","saydigits","saynumber","sayphonetic","sayunixtime","senddtmf","sendfax",

                  "sendfax","sendfax","sendimage","sendtext","sendurl","set","setamaflags",

                  "setcallerpres","setmusiconhold","sipaddheader","sipdtmfmode","sipremoveheader","skel",

                  "slastation","slatrunk","sms","softhangup","speechactivategrammar","speechbackground",

                  "speechcreate","speechdeactivategrammar","speechdestroy","speechloadgrammar","speechprocessingsound",

                  "speechstart","speechunloadgrammar","stackpop","startmusiconhold","stopmixmonitor","stopmonitor",

                  "stopmusiconhold","stopplaytones","system","testclient","testserver","transfer","tryexec",

                  "trysystem","unpausemonitor","unpausequeuemember","userevent","verbose","vmauthenticate",

                  "vmsayname","voicemail","voicemailmain","wait","waitexten","waitfornoise","waitforring",

                  "waitforsilence","waitmusiconhold","waituntil","while","zapateller"

                 ];



  function basicToken(stream,state){

    var cur = '';

    var ch = stream.next();

    // comment

    if(ch == ";") {

      stream.skipToEnd();

      return "comment";

    }

    // context

    if(ch == '[') {

      stream.skipTo(']');

      stream.eat(']');

      return "header";

    }

    // string

    if(ch == '"') {

      stream.skipTo('"');

      return "string";

    }

    if(ch == "'") {

      stream.skipTo("'");

      return "string-2";

    }

    // dialplan commands

    if(ch == '#') {

      stream.eatWhile(/\w/);

      cur = stream.current();

      if(dpcmd.indexOf(cur) !== -1) {

        stream.skipToEnd();

        return "strong";

      }

    }

    // application args

    if(ch == '$'){

      var ch1 = stream.peek();

      if(ch1 == '{'){

        stream.skipTo('}');

        stream.eat('}');

        return "variable-3";

      }

    }

    // extension

    stream.eatWhile(/\w/);

    cur = stream.current();

    if(atoms.indexOf(cur) !== -1) {

      state.extenStart = true;

      switch(cur) {

        case 'same': state.extenSame = true; break;

        case 'include':

        case 'switch':

        case 'ignorepat':

          state.extenInclude = true;break;

        default:break;

      }

      return "atom";

    }

  }



  return {

    startState: function() {

      return {

        extenStart: false,

        extenSame:  false,

        extenInclude: false,

        extenExten: false,

        extenPriority: false,

        extenApplication: false

      };

    },

    token: function(stream, state) {



      var cur = '';

      if(stream.eatSpace()) return null;

      // extension started

      if(state.extenStart){

        stream.eatWhile(/[^\s]/);

        cur = stream.current();

        if(/^=>?$/.test(cur)){

          state.extenExten = true;

          state.extenStart = false;

          return "strong";

        } else {

          state.extenStart = false;

          stream.skipToEnd();

          return "error";

        }

      } else if(state.extenExten) {

        // set exten and priority

        state.extenExten = false;

        state.extenPriority = true;

        stream.eatWhile(/[^,]/);

        if(state.extenInclude) {

          stream.skipToEnd();

          state.extenPriority = false;

          state.extenInclude = false;

        }

        if(state.extenSame) {

          state.extenPriority = false;

          state.extenSame = false;

          state.extenApplication = true;

        }

        return "tag";

      } else if(state.extenPriority) {

        state.extenPriority = false;

        state.extenApplication = true;

        stream.next(); // get comma

        if(state.extenSame) return null;

        stream.eatWhile(/[^,]/);

        return "number";

      } else if(state.extenApplication) {

        stream.eatWhile(/,/);

        cur = stream.current();

        if(cur === ',') return null;

        stream.eatWhile(/\w/);

        cur = stream.current().toLowerCase();

        state.extenApplication = false;

        if(apps.indexOf(cur) !== -1){

          return "def strong";

        }

      } else{

        return basicToken(stream,state);

      }



      return null;

    }

  };

});



CodeMirror.defineMIME("text/x-asterisk", "asterisk");



});

