package org.jtwig.parser.parboiled.expression;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Multimaps;
import org.jtwig.model.expression.BinaryOperationExpression;
import org.jtwig.parser.parboiled.ParserContext;
import org.jtwig.parser.parboiled.base.PositionTrackerParser;
import org.jtwig.parser.parboiled.base.SpacingParser;
import org.jtwig.parser.parboiled.expression.operator.BinaryOperatorParser;
import org.jtwig.render.expression.calculator.operation.binary.BinaryOperator;
import org.parboiled.Rule;
import org.parboiled.annotations.Label;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class BinaryOperationSuffixExpressionParser extends ExpressionParser<BinaryOperationExpression> {
    final Collection<BinaryOperator> operators;

    public BinaryOperationSuffixExpressionParser(ParserContext context, Collection<BinaryOperator> operators) {
        super(BinaryOperationSuffixExpressionParser.class, context);
        this.operators = operators;
    }

    @Override
    @Label("BinaryOperationSuffix Expression")
    public Rule ExpressionRule() {
        Rule initialExpression = null;
        ImmutableListMultimap<Integer, BinaryOperator> index = Multimaps.index(operators, precedence());

        List<Integer> integers = new ArrayList<>(index.keySet());
        Collections.sort(integers);
        for (Integer integer : integers) {
            initialExpression = BinaryOperation(initialExpression, index.get(integer));
        }
        return initialExpression;
    }

    Function<BinaryOperator, Integer> precedence() {
        return new Function<BinaryOperator, Integer>() {
            @Override
            public Integer apply(BinaryOperator input) {
                return input.precedence();
            }
        };
    }

    Rule BinaryOperation(Rule expressionRule, List<BinaryOperator> operators) {
        if (expressionRule == null) {
            return Sequence(
                    parserContext().parser(SpacingParser.class).Spacing(),
                    ZeroOrMore(
                            parserContext().parser(PositionTrackerParser.class).PushPosition(),
                            parserContext().parser(BinaryOperatorParser.class).BinaryOperator(operators),
                            parserContext().parser(SpacingParser.class).Spacing(),
                            parserContext().parser(PrimaryExpressionParser.class).ExpressionRule(),
                            push(new BinaryOperationExpression(
                                    parserContext().parser(PositionTrackerParser.class).pop(2),
                                    pop(2),
                                    parserContext().parser(BinaryOperatorParser.class).pop(1),
                                    pop()
                            ))
                    )
            );

        } else {
            return Sequence(
                    expressionRule,
                    parserContext().parser(SpacingParser.class).Spacing(),
                    ZeroOrMore(
                            parserContext().parser(PositionTrackerParser.class).PushPosition(),
                            parserContext().parser(BinaryOperatorParser.class).BinaryOperator(operators),
                            parserContext().parser(SpacingParser.class).Spacing(),
                            Sequence(
                                    parserContext().parser(PrimaryExpressionParser.class).ExpressionRule(),
                                    expressionRule
                            ),
                            push(new BinaryOperationExpression(
                                    parserContext().parser(PositionTrackerParser.class).pop(2),
                                    pop(2),
                                    parserContext().parser(BinaryOperatorParser.class).pop(1),
                                    pop()
                            ))
                    )

            );
        }
    }
}

@@ -1248,20 +1248,21 @@
 ssion = 
-null
+EMPTY
 ;%0A      
@@ -2001,1055 +2001,57 @@
     
-if (expressionRule == null) %7B%0A            return Sequence(%0A                    parserContext().parser(SpacingParser.class).Spacing(),%0A                    ZeroOrMore(%0A                            parserContext().parser(PositionTrackerParser.class).PushPosition(),%0A                            parserContext().parser(BinaryOperatorParser.class).BinaryOperator(operators),%0A                            parserContext().parser(SpacingParser.class).Spacing(),%0A                            parserContext().parser(PrimaryExpressionParser.class).ExpressionRule(),%0A                            push(new BinaryOperationExpression(%0A                                    parserContext().parser(PositionTrackerParser.class).pop(2),%0A                                    pop(2),%0A                                    parserContext().parser(BinaryOperatorParser.class).pop(1),%0A                                    pop()%0A                            ))%0A                    )%0A            );%0A%0A        %7D else %7B%0A            return Sequence(%0A                    expressionRule,%0A    
+return Sequence(%0A                expressionRule,%0A
     
@@ -2133,20 +2133,16 @@
         
-    
 ZeroOrMo
@@ -2161,36 +2161,32 @@
                 
-   
- 
 parserContext().
@@ -2233,28 +2233,24 @@
 Position(),%0A
-    
             
@@ -2339,20 +2339,16 @@
 ators),%0A
-    
         
@@ -2442,20 +2442,16 @@
         
-    
 Sequence
@@ -2444,36 +2444,32 @@
       Sequence(%0A
-    
                 
@@ -2580,36 +2580,32 @@
                 
-    
 expressionRule%0A 
@@ -2627,20 +2627,16 @@
         
-    
 ),%0A     
@@ -2654,20 +2654,16 @@
         
- 
-   
 push(new
@@ -2690,20 +2690,16 @@
 ession(%0A
-    
         
@@ -2818,20 +2818,16 @@
     
- 
-   
 pop(2),%0A
     
@@ -2814,36 +2814,32 @@
         pop(2),%0A
-    
                 
@@ -2949,22 +2949,14 @@
     
-    
 pop()%0A
-    
     
@@ -2994,20 +2994,16 @@
         
-    
 )%0A%0A     
@@ -3009,24 +3009,10 @@
     
- 
-   );%0A        %7D
+);
 %0A   

simplify BinaryOperationSuffixExpressionParser by using the empty Matcher