/*
 * Copyright 2014 Shape Security, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.shapesecurity.shift;

import com.shapesecurity.functional.data.List;
import com.shapesecurity.functional.data.Maybe;
import com.shapesecurity.shift.ast.Block;
import com.shapesecurity.shift.ast.Directive;
import com.shapesecurity.shift.ast.Expression;
import com.shapesecurity.shift.ast.FunctionBody;
import com.shapesecurity.shift.ast.Identifier;
import com.shapesecurity.shift.ast.Script;
import com.shapesecurity.shift.ast.Statement;
import com.shapesecurity.shift.ast.VariableDeclaration;
import com.shapesecurity.shift.ast.VariableDeclarator;
import com.shapesecurity.shift.ast.expression.FunctionExpression;
import com.shapesecurity.shift.ast.expression.IdentifierExpression;
import com.shapesecurity.shift.ast.expression.LiteralBooleanExpression;
import com.shapesecurity.shift.ast.expression.LiteralNullExpression;
import com.shapesecurity.shift.ast.expression.LiteralNumericExpression;
import com.shapesecurity.shift.ast.statement.BlockStatement;
import com.shapesecurity.shift.ast.statement.EmptyStatement;
import com.shapesecurity.shift.ast.statement.ExpressionStatement;
import com.shapesecurity.shift.ast.statement.FunctionDeclaration;
import com.shapesecurity.shift.ast.statement.LabeledStatement;
import com.shapesecurity.shift.ast.statement.VariableDeclarationStatement;
import com.shapesecurity.shift.ast.statement.WhileStatement;
import com.shapesecurity.shift.validator.ValidationError;
import com.shapesecurity.shift.validator.Validator;

import org.junit.Assert;

public class AstHelper extends TestBase {
  public static final EmptyStatement STMT = new EmptyStatement();
  public static final Block BLOCK = new Block(List.<Statement>nil());
  public static final BlockStatement BLOCK_STMT = new BlockStatement(BLOCK);
  public static final FunctionBody EMPTY_BODY =
      new FunctionBody(List.<Directive>nil(), List.<Statement>nil());
  public static final FunctionBody BLOCK_WRAPPED =
      new FunctionBody(List.<Directive>nil(), List.<Statement>list(BLOCK_STMT));
  public static final LiteralNullExpression EXPR = new LiteralNullExpression();
  public static final LiteralNumericExpression NUM = new LiteralNumericExpression(0);
  public static final Identifier ID = new Identifier("a");

  // wrap a statement in a program
  public static Script wrapProgram(Statement s) {
    return new Script(new FunctionBody(List.<Directive>nil(), List.list(s)));
  }

  // wrap a statement in an iteration statement
  public static Statement wrapIter(Statement s) {
    return new WhileStatement(new LiteralBooleanExpression(true), s);
  }

  protected FunctionBody body(Statement... statements) {
    return new FunctionBody(List.nil(), List.from(statements));
  }

  protected IdentifierExpression identExpr(String name) {
    return new IdentifierExpression(ident(name));
  }

  protected Identifier ident(String name) {
    return new Identifier(name);
  }

  public static VariableDeclarator declarator(String d) {
    return new VariableDeclarator(new Identifier(d), Maybe.<Expression>nothing());
  }

  public static VariableDeclarationStatement varss(
      VariableDeclaration.VariableDeclarationKind kind,
      String d0,
      String... d) {
    return new VariableDeclarationStatement(vars(kind, d0, d));
  }

  public static VariableDeclaration vars(VariableDeclaration.VariableDeclarationKind kind, String d0, String... d) {
    return new VariableDeclaration(kind, List.list(d0, d).map(AstHelper::declarator));
  }

  // wrap zero or more statements in a function expression
  public static FunctionExpression FE(Statement s) {
    return new FunctionExpression(Maybe.just(ID), List.<Identifier>nil(), new FunctionBody(List.<Directive>nil(),
        List.list(s)));
  }

  // wrap zero or more statements in a function declaration
  public static FunctionDeclaration FD(Statement s) {
    return new FunctionDeclaration(ID, List.<Identifier>nil(), new FunctionBody(List.<Directive>nil(), List.list(s)));
  }

  // wrap a statement in a LabeledStatement
  public static LabeledStatement label(String l, Statement n) {
    return new LabeledStatement(new Identifier(l), n);
  }

  // wrap an expression in an ExpressionStatement
  public static ExpressionStatement exprStmt(Expression e) {
    return new ExpressionStatement(e);
  }

  public static void printErrs(List<ValidationError> errs) {
    if (!errs.isEmpty()) {
      for (ValidationError validationError : errs) {
        System.out.println("ERROR>>>  " + validationError.message);
      }
    }
  }

  public static void assertOk(List<ValidationError> errs) {
    if (!errs.isEmpty()) {
      printErrs(errs);
    }
    Assert.assertEquals(0, errs.length);
  }

  public static void validStmt(Statement s) {
    assertOk(Validator.validate(wrapProgram(s)));
  }

  public static void invalidStmt(int numExpectedErrs, Statement s) {
    List<ValidationError> errs = Validator.validate(wrapProgram(s));
    Assert.assertTrue(!errs.isEmpty());
    Assert.assertEquals(errs.length, numExpectedErrs);
  }

  public static void validExpr(Expression e) {
    assertOk(Validator.validate(wrapProgram(exprStmt(e))));
  }

  public static void invalidExpr(int numExpectedErrs, Expression e) {
    List<ValidationError> errs = Validator.validate(wrapProgram(exprStmt(e)));
    Assert.assertTrue(!errs.isEmpty());
    Assert.assertEquals(numExpectedErrs, errs.length);
  }
}

@@ -2250,35 +2250,24 @@
  Block(List.
-%3CStatement%3E
 nil());%0A  pu
@@ -2411,35 +2411,24 @@
 onBody(List.
-%3CDirective%3E
 nil(), List.
@@ -2427,27 +2427,16 @@
 ), List.
-%3CStatement%3E
 nil());%0A
@@ -2510,35 +2510,24 @@
 onBody(List.
-%3CDirective%3E
 nil(), List.
@@ -2530,19 +2530,8 @@
 ist.
-%3CStatement%3E
 list
@@ -2896,35 +2896,24 @@
 onBody(List.
-%3CDirective%3E
 nil(), List.
@@ -3543,20 +3543,8 @@
 ybe.
-%3CExpression%3E
 noth
@@ -4143,36 +4143,24 @@
 t(ID), List.
-%3CIdentifier%3E
 nil(), new F
@@ -4172,35 +4172,24 @@
 onBody(List.
-%3CDirective%3E
 nil(),%0A     
@@ -4374,20 +4374,8 @@
 ist.
-%3CIdentifier%3E
 nil(
@@ -4403,19 +4403,8 @@
 ist.
-%3CDirective%3E
 nil(

remove unnecessary type parameters