var TokenType = require('../token-types');

module.exports = (function() {
    /**
    * Mark whitespaces and comments
    */
    function markSC(tokens) {
       var tokensLength = tokens.length;
       var ws = -1, // flag for whitespaces
           sc = -1, // flag for whitespaces and comments
           t; // current token

       // For every token in the token list, mark spaces and line breaks
       // as spaces (set both `ws` and `sc` flags). Mark multiline comments
       // with `sc` flag.
       // If there are several spaces or tabs or line breaks or multiline
       // comments in a row, group them: take the last one's index number
       // and save it to the first token in the group as a reference
       // (e.g., `ws_last = 7` for a group of whitespaces or `sc_last = 9`
       // for a group of whitespaces and comments):
       for (var i = 0; i < tokensLength; i++) {
           t = tokens[i];
           switch (t.type) {
               case TokenType.Space:
               case TokenType.Tab:
               case TokenType.Newline:
                   t.ws = true;
                   t.sc = true;

                   if (ws === -1) ws = i;
                   if (sc === -1) sc = i;

                   break;
               case TokenType.CommentML:
                   if (ws !== -1) {
                       tokens[ws].ws_last = i - 1;
                       ws = -1;
                   }

                   t.sc = true;

                   break;
               default:
                   if (ws !== -1) {
                       tokens[ws].ws_last = i - 1;
                       ws = -1;
                   }

                   if (sc !== -1) {
                       tokens[sc].sc_last = i - 1;
                       sc = -1;
                   }
           }
       }

       if (ws !== -1) tokens[ws].ws_last = i - 1;
       if (sc !== -1) tokens[sc].sc_last = i - 1;
    }

    /**
    * Pair brackets
    */
    function markBrackets(tokens) {
       var tokensLength = tokens.length;
       var ps = [], // parenthesis
           sbs = [], // square brackets
           cbs = [], // curly brackets
           t; // current token

       // For every token in the token list, if we meet an opening (left)
       // bracket, push its index number to a corresponding array.
       // If we then meet a closing (right) bracket, look at the corresponding
       // array. If there are any elements (records about previously met
       // left brackets), take a token of the last left bracket (take
       // the last index number from the array and find a token with
       // this index number) and save right bracket's index as a reference:
       for (var i = 0; i < tokens.length; i++) {
           t = tokens[i];
           switch(t.type) {
               case TokenType.LeftParenthesis:
                   ps.push(i);
                   break;
               case TokenType.RightParenthesis:
                   if (ps.length) {
                       t.left = ps.pop();
                       tokens[t.left].right = i;
                   }
                   break;
               case TokenType.LeftSquareBracket:
                   sbs.push(i);
                   break;
               case TokenType.RightSquareBracket:
                   if (sbs.length) {
                       t.left = sbs.pop();
                       tokens[t.left].right = i;
                   }
                   break;
               case TokenType.LeftCurlyBracket:
                   cbs.push(i);
                   break;
               case TokenType.RightCurlyBracket:
                   if (cbs.length) {
                       t.left = cbs.pop();
                       tokens[t.left].right = i;
                   }
                   break;
           }
       }
    }

    return function(tokens) {
        // Mark paired brackets:
        markBrackets(tokens);
        // Mark whitespaces and comments:
        markSC(tokens);
    }
})();
