package jshinter.analyzer;

import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;

import jshinter.antlr.ECMAScriptBaseListener;
import jshinter.antlr.ECMAScriptParser;
import jshinter.antlr.ECMAScriptParser.AssignmentOperatorContext;
import jshinter.antlr.ECMAScriptParser.BitAndExpressionContext;
import jshinter.antlr.ECMAScriptParser.BitNotExpressionContext;
import jshinter.antlr.ECMAScriptParser.BitOrExpressionContext;
import jshinter.antlr.ECMAScriptParser.BitShiftExpressionContext;
import jshinter.antlr.ECMAScriptParser.BitXOrExpressionContext;
import jshinter.antlr.ECMAScriptParser.EqualityExpressionContext;

public class JSHinterListener extends ECMAScriptBaseListener {

	private ECMAScriptParser parser;
	
	private final Boolean DEBUG;
	
	public JSHinterListener(ECMAScriptParser parser) {
		this.parser = parser;
		this.DEBUG = false;
	}
	
	public JSHinterListener(ECMAScriptParser parser, Boolean debugMode) {
		this.parser = parser;
		this.DEBUG = debugMode;
	}
	
	private void reportError(String msg, Token t) {
		System.out.printf("%d,%d: %s.\n", t.getLine(), t.getCharPositionInLine() + t.getText().length() + 1, msg);
	}

	@Override
	public void enterBitXOrExpression(BitXOrExpressionContext ctx) {
		TokenStream ts = parser.getTokenStream();

		reportError(String.format("Unexpected use of '%s'", ctx.getChild(1).getText()), ts.get(ctx.getChild(1).getSourceInterval().a));
	}

	@Override
	public void enterBitShiftExpression(BitShiftExpressionContext ctx) {
		TokenStream ts = parser.getTokenStream();

		reportError(String.format("Unexpected use of '%s'", ctx.getChild(1).getText()), ts.get(ctx.getChild(1).getSourceInterval().a));
	}

	@Override
	public void enterBitNotExpression(BitNotExpressionContext ctx) {
		TokenStream ts = parser.getTokenStream();

		reportError(String.format("Unexpected use of '%s'", ctx.getChild(1).getText()), ts.get(ctx.getChild(1).getSourceInterval().a));
	}

	@Override
	public void enterBitAndExpression(BitAndExpressionContext ctx) {
		TokenStream ts = parser.getTokenStream();

		reportError(String.format("Unexpected use of '%s'", ctx.getChild(1).getText()), ts.get(ctx.getChild(1).getSourceInterval().a));
	}

	@Override
	public void enterBitOrExpression(BitOrExpressionContext ctx) {
		TokenStream ts = parser.getTokenStream();

		reportError(String.format("Unexpected use of '%s'", ctx.getChild(1).getText()), ts.get(ctx.getChild(1).getSourceInterval().a));
	}

	@Override
	public void enterAssignmentOperator(AssignmentOperatorContext ctx) {
		Token t = ctx.getStart();
		int type = t.getType();
		
		if (type >= 45 || type <= 50) {
			reportError(String.format("Unexpected use of '%s'", t.getText()), t);
		}
	}

	@Override
	public void enterEqualityExpression(EqualityExpressionContext ctx) {
		TokenStream ts = parser.getTokenStream();
		Token t = ts.get(ctx.getChild(1).getSourceInterval().b);
		String operator = t.getText();
		
		String shouldBe = null;
		
		if (operator.equals("==")) {
			shouldBe = "===";
		} else if (operator.equals("!=")) {
			shouldBe = "!==";
		}
		
		if (!shouldBe.equals(null)) {
			reportError(String.format("Expected '%s' and instead saw '%s'", shouldBe, operator), t);
		}
	}
}

@@ -21,16 +21,65 @@
 lyzer;%0A%0A
+import java.util.Arrays;%0Aimport java.util.List;%0A%0A
 import o
@@ -685,16 +685,144 @@
 Context;
+%0Aimport jshinter.antlr.ECMAScriptParser.SingleExpressionContext;%0Aimport jshinter.antlr.ECMAScriptParser.TypeofExpressionContext;
 %0A%0Apublic
@@ -3250,17 +3250,16 @@
 if (
-!
 shouldBe
 .equ
@@ -3258,22 +3258,17 @@
 ldBe
-.equals(
+ != 
 null)
-)
  %7B%0A%09
@@ -3362,13 +3362,651 @@
 t);%0A%09%09%7D%0A
+%09%09%0A%09%09if (ctx.getChild(0) instanceof TypeofExpressionContext) %7B%0A%09%09%09processTypeofExpression(ctx);%0A%09%09%7D%0A%09%7D%0A%0A%09private void processTypeofExpression(EqualityExpressionContext ctx) %7B%0A%09%09TokenStream ts = parser.getTokenStream();%0A%09%09Token t = ts.get(ctx.getChild(2).getSourceInterval().a);%0A%09%09%0A%09%09List%3CString%3E allowedTypeof = Arrays.asList(%22undefined%22, %22boolean%22, %22number%22, %22string%22, %22function%22, %22object%22);%0A%09%09%0A%09%09if (t.getType() == 99) %7B%0A%09%09%09String literal = t.getText();%0A%09%09%09literal = literal.substring(1, literal.length() - 1);%0A%09%09%09if (!allowedTypeof.contains(literal)) %7B%0A%09%09%09%09reportError(String.format(%22Invalid typeof value '%25s'%22, literal), t);%0A%09%09%09%7D%0A%09%09%7D%0A
 %09%7D%0A%7D%0A

Include typeof rule