define(['scripts/StringModifier'], function(StringModifier) {
    /**
     * Analyzes command before cursor and retrieves valid command, method or indexer.
     * It removes unneeded command portion, such as inside brackets, before equal sign etc...
     * This helps knowing when a new valid command needs to be analyzed in the C# for autocompletion purpose.
     * @param{object} editor Ace editor instance
     * @param{object} statementProposals Proposals for each portion of the statement.
     */
    function StatementFilterer(editor, statementProposals){

        var _this = this; 
        _this.originalCommand = "";
        // Ex: c = A.B(C.D will return C
        _this.lastValidCommand = "";
        // Ex: c = A.B(C. will return A.B
        _this.lastValidMethod = "";
        // Ex: c = A.B[C will return A.B
        _this.lastValidCommandBeforeSquareBracket = "";
        // Ex: c = A.B[C will return c
        _this.leftHandSideStatement = "";
        //Array containing the position and type of unclosed brackets.
        _this.unclosedBrackets = [];

        //Symbols used to remove characters before them.
        var specialSymbols = "[ \t=,\/?:!;\*-\+\|]";

        function Bracket(start, end, isMatching, type){
            this.start      = start;
            this.end        = end;
            this.isMatching = isMatching;
            this.type       = type;
        }

        /**
         * Finds matching and unmatching brackets.
         * @param{object} textRange The range of the text to analyze
         * @returns {array} An array of Bracket object containing the position and the type of these brackets.
         */
        var getBracketRange = function(textRange){
            var options = {
                needle:        /[\(\[\{]/g,
                range:         textRange,
                caseSensitive: false,
                regExp:        true,
                wrap:          false,
                preventScroll: true,
                backwards:     false
            };
            editor.$search.set(options);
            var bracketsPos = editor.$search.findAll(editor.session);
            var bracketRanges = [];
            if(bracketsPos.length > 0){
                for (var i = 0; i < bracketsPos.length ; i++){
                    var matchingBracketRange = editor.session.getBracketRange(bracketsPos[i].end);
                    var bracketType = editor.session.getTextRange(bracketsPos[i]);
                    if (matchingBracketRange && matchingBracketRange.end.column < textRange.end.column){
                        bracketRanges.push({start:matchingBracketRange.start.column, end: matchingBracketRange.end.column, isMatching: true, type: bracketType});
                    }else{
                        bracketRanges.push({start: bracketsPos[i].end.column, end: null, isMatching: false, type: bracketType});
                    }
                }
            }
            return bracketRanges;
        };

        /**
         * Gets the last valid command from the input text.
         * Ex: c = A.B(C.D will return C.D
         * @param {string} text The input command.
         * @returns {string} The valid last command. 
         */
        var getValidCommand = function(text){
            if (_this.unclosedBrackets.length !== 0){
                text = text.slice(_this.unclosedBrackets[_this.unclosedBrackets.length -1].start);
            }
            text = StringModifier.RemoveBefore(text, specialSymbols, true, true);
            // text = _this.dereferenceVariable(text);
            return text;
        };


        /**
         * Gets the last valid command before the last specified opening bracket.
         * Ex: c = A.B(C. will return A.B
         * @param {string} text The input command.
         * @param {string} bracketType The type of the last opening bracket to search for (can be "(" or "[")
         * @returns {string} The valid command before the last opening bracket.
         */
        var getValidCommandBeforeLastOpenedBracket = function(text, bracketType){
            var validCommand = text;
            var unclosedBracketsNumber = _this.unclosedBrackets.length;
            if (unclosedBracketsNumber === 0){
                return "";
            }
            var currentBracketIndex = unclosedBracketsNumber -1;
            //Search for the last unclosed brackets corresponding to bracketType.
            while(currentBracketIndex >=0 && _this.unclosedBrackets[currentBracketIndex].type !== bracketType){
                currentBracketIndex--;
            }
            if(currentBracketIndex < 0 ){
                return "";
            }
            //Remove after last opening bracket.
            validCommand = validCommand.substr(0, _this.unclosedBrackets[currentBracketIndex].start -1);
            //Cut out what stands before the previous unclosed bracket.
            if (currentBracketIndex >= 1){
                validCommand = validCommand.slice(_this.unclosedBrackets[currentBracketIndex -1].start);
            }
            validCommand = StringModifier.RemoveBefore(validCommand, specialSymbols, true, true);
            return validCommand;
        };


        var getLeftHandSideStatement = function(text){
            var lhsStatement = "";
            if (text.substring(text.length-2, text.length) === "= "){
                lhsStatement = text.replace(/[ \t]/g, '');
                lhsStatement = lhsStatement.substring(0, lhsStatement.length -1);
            }
            return lhsStatement;
        };


        //----INIT----//
        var endPosition      = editor.getSelectionRange().start;
        var startPosition    = {row: endPosition.row, column: 0};
        var textRange        = {start: startPosition, end:endPosition};
        _this.originalCommand     = editor.session.getTextRange(textRange);
        var modifiedText     = _this.originalCommand;
        var brackets = getBracketRange(textRange);

        if(StringModifier.IsInsideQuote(_this.originalCommand) === false){
            var currentPosition  = 0;
            var removedCharCount = 0;
            for(var i = 0 ; i < brackets.length; i++){
                var currentBracket = brackets[i];
                if(currentBracket.start > endPosition.column) continue;
                if(currentBracket.start < currentPosition) continue; //Brackets already removed with bigger brackets.
                if(currentBracket.isMatching){
                    currentPosition = currentBracket.end;

                    //For square brackets, there is an ambiguity: it can be a generic method or an indexer.
                    if(currentBracket.type === "["){
                        var currentCommand = modifiedText.substring(0, currentBracket.start - removedCharCount -1);
                        currentCommand = getValidCommand(currentCommand, _this.unclosedBrackets);
                        var squareBracketType = statementProposals.isIndexerOrGenericBracket(currentCommand);
                        //Do not remove text inside bracket for generictype.
                        //If symbolInfo is not known, also keep it in case.--> will be investigated further.
                        if(squareBracketType === "generic" || squareBracketType === "undefined"){
                            continue;
                        }
                    }

                    //Removes what is inside brackets to avoid re-evaluation.
                    modifiedText = modifiedText.substring(0, currentBracket.start - removedCharCount -1) + modifiedText.substring(currentBracket.end - removedCharCount + 1);
                    currentBracket.start -= removedCharCount;
                    removedCharCount += (currentBracket.end - (currentBracket.start + removedCharCount)) + 2;
                    currentBracket.end -= removedCharCount;
                }else{
                    //Add unclosed brackets to the array.
                    currentPosition = currentBracket.start - removedCharCount;
                    _this.unclosedBrackets.push(new Bracket(currentPosition, null, false, brackets[i].type));
                }
            }
            var validCommand = getValidCommand(modifiedText, _this.unclosedBrackets);
            //Remove symbols after the last dot.
            var splittedText = StringModifier.SplitExceptInsideBrackets(validCommand, "\\.");
            splittedText.pop();
            // //If the first symbol is undefined and may be generic, it must be kept to be analyzed.
            // if(splittedText.length === 0 && _this.mustReAnalyzeCommand === true){
            //     _this.lastValidCommand = validCommand;
            // }else{
            _this.lastValidCommand = validCommand;
            // }
            _this.lastValidMethod = getValidCommandBeforeLastOpenedBracket(modifiedText, "(");
            _this.lastValidCommandBeforeSquareBracket = getValidCommandBeforeLastOpenedBracket(modifiedText, "[");
            _this.leftHandSideStatement = getLeftHandSideStatement(modifiedText);
        }
    }
    return StatementFilterer;
});





