package org.coffeebrew.lang.lexer;

import com.intellij.lexer.FlexAdapter;

import java.io.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

/**
 * The lexer is tested by comparing modified CoffeeScript lexer tokens
 * to the tokens generated by CoffeeScriptFlexLexer.
 *
 * 1. Place your tests in CoffeeScript under /resources/coffee-script
 *
 * 2. Start the Ant target 'generate-tokes', which will then pass these example to the CoffeeScript
 * compiler and stores the generated lexer token output to /resources/coffee-script
 *
 * 3. Modify the generated token file to match the plugin token stream and put the CoffeeScript
 * file and the token file into /resources/coffee-script/tests
 *
 * @author Michael Kessler
 * @since 0.1.0
 */
class CoffeeScriptLexerExampleTestCase {

  private static final String NL = System.getProperty("line.separator");
  private static final String FS = System.getProperty("file.separator");

  private enum FileType { TOKENS, COFFEE }

  /**
   * Assert that the CoffeeScript tokens matches the example tokens
   *
   * @param example The name of the example
   */
  protected void assertLexerExample(String example) {
    try {
      assertThat(getExpectedTokens(example), equalTo(getExampleTokens(example)));

    } catch (FileNotFoundException e) {
      fail("File not found: " + e.getMessage());
    } catch (IOException e) {
      fail("Cannot read file: " + e.getMessage());
    }
  }

  /**
   * Uses generated tokens from CoffeeScript
   *
   * @param example The example file name
   * @return the lexer tokens
   * @throws IOException when the example cannot be read
   */
  private static Collection<CoffeeScriptLexerTestToken> getExampleTokens(String example) throws IOException {
    ArrayList<CoffeeScriptLexerTestToken> tokens = new ArrayList<CoffeeScriptLexerTestToken>();
    StringBuffer content = readFile(example, FileType.TOKENS);

    Pattern pattern = Pattern.compile("(\\[[A-Z_]+ .*?\\](?=\\s))", Pattern.MULTILINE);
    Matcher matcher = pattern.matcher(content);

    while (matcher.find()) {
      CoffeeScriptLexerTestToken token = new CoffeeScriptLexerTestToken(content.substring(matcher.start(), matcher.end()));
      tokens.add(token);
    }

    return tokens;
  }

  /**
   * Uses the plugin to generate the lexer tokens for the given filename
   *
   * @param example The example file name
   * @return the lexer tokens
   * @throws IOException when the example cannot be read
   */
  private static Collection<CoffeeScriptLexerTestToken> getExpectedTokens(String example) throws IOException {

    final FlexAdapter lexer = new CoffeeScriptFlexLexer();
    lexer.start(readFile(example, FileType.COFFEE));

    ArrayList<CoffeeScriptLexerTestToken> tokens = new ArrayList<CoffeeScriptLexerTestToken>();
    while (lexer.getCurrentPosition().getOffset() < lexer.getBufferEnd()) {
      CoffeeScriptLexerTestToken token = new CoffeeScriptLexerTestToken(lexer.getTokenType(), lexer.getTokenSequence());
      tokens.add(token);
      lexer.advance();
    }

    return tokens;
  }

  /**
   * Reads the given file and returns its content as StringBuffer
   *
   * @param example The example name
   * @param type The example type
   * @return the content of the file
   * @throws IOException when the example cannot be read
   */
  private static StringBuffer readFile(String example, FileType type) throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader(getExampleFilePath(example, type)));
    StringBuffer buffer = new StringBuffer();
    String line = "";

    while ((line = reader.readLine()) != null) {
      buffer.append(line).append(NL);
    }

    return buffer;
  }

  /**
   * Returns the path and filename to the example file for the given type
   *
   * @param example The example name
   * @param type The example type
   * @return the path and filename
   */
  private static String getExampleFilePath(String example, FileType type) {
    String filename;
    String basePath = getProjectHome() + FS + "resources" + FS + "coffee-script" + FS + "tests" + FS;

    if (type == FileType.COFFEE) {
      filename = basePath + example + ".coffee";
    } else {
      filename = basePath + example + ".tokens";
    }

    return filename;
  }

  /**
   *
   * @return the project home directory
   */
  private static String getProjectHome() {
    Properties props = System.getProperties();
    return props.getProperty("user.dir");
  }

}

@@ -3784,13 +3784,8 @@
 line
- = %22%22
 ;%0A%0A 

Remove unnecessary initialization