package org.angularjs.closurerunner;

import com.google.common.collect.ArrayListMultimap;

import com.google.javascript.jscomp.AbstractCompiler;
import com.google.javascript.jscomp.Compiler;
import com.google.javascript.jscomp.CommandLineRunner;
import com.google.javascript.jscomp.CompilerOptions;
import com.google.javascript.jscomp.CompilerPass;
import com.google.javascript.jscomp.CustomPassExecutionTime;

import java.io.InputStream;
import java.io.IOException;
import java.io.PrintStream;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class NgClosureRunner extends CommandLineRunner {

  private boolean minerrPass;
  private String minerrErrors, minerrUrl, minerrSeparator;
  private Compiler cachedCompiler;

  protected NgClosureRunner(String[] args, 
                            boolean minerrPass, 
                            String minerrErrors, 
                            String minerrUrl,
                            String minerrSeparator) {
    super(args);
    this.minerrPass = minerrPass;
    this.minerrSeparator = minerrSeparator;
    
    if (minerrErrors != null) {
      this.minerrErrors = minerrErrors;
    } else {
      this.minerrErrors = "errors.json";
    }
    this.minerrUrl = minerrUrl;
  }

  private String loadTextResource(String asset) throws IOException {
    InputStream stream = getClass().getClassLoader().getResourceAsStream(asset);
    int size = stream.available();
    Scanner input = new Scanner(stream);
    StringBuilder buf = new StringBuilder(size);
    String lineSeparator = System.getProperty("line.separator");

    try {
      while(input.hasNextLine()) {
        buf.append(input.nextLine() + lineSeparator);
      }
      return buf.toString();
    } finally {
      input.close();
    }
  }

  private CompilerPass createMinerrPass() throws IOException {
    AbstractCompiler compiler = createCompiler();
    PrintStream output = new PrintStream(minerrErrors);
    String code = loadTextResource("minErr.js");

    if (minerrUrl != null) {
      return new MinerrPass(compiler,
                            output,
                            MinerrPass.substituteInCode(code, minerrUrl, minerrSeparator));
    }
    return new MinerrPass(compiler, output);
  }

  @Override
  protected CompilerOptions createOptions() {
    CompilerOptions options = super.createOptions();

    if (minerrPass) {
      if (options.customPasses == null) {
        options.customPasses = ArrayListMultimap.create();
      }
      try {
        options.customPasses.put(CustomPassExecutionTime.BEFORE_OPTIMIZATIONS,
          createMinerrPass());
      } catch (IOException e) {
        System.err.println(e);
        System.exit(1);
      }
    }
    return options;
  }

  @Override
  protected Compiler createCompiler() {
    // Always use the same compiler.
    if (cachedCompiler != null) {
      return cachedCompiler;
    }
    cachedCompiler = super.createCompiler();
    return cachedCompiler;
  }

  public static void main(String[] args) {
    boolean minerrPass = false;
    String minerrErrors = "errors.json", minerrUrl = null, minerrSeparator = "/";
    List<String> passthruArgs = new ArrayList<String>();

    for (int i = 0; i < args.length; i++) {
      String arg = args[i];
      if (arg.equals("--minerr_pass")) {
        minerrPass = true;
      } else if (arg.equals("--minerr_errors")) {
        minerrErrors = args[++i];
      } else if (arg.equals("--minerr_url")) {
        minerrUrl = args[++i];
      } else if (arg.equals("--minerr_separate_with_colon")) {
        minerrSeparator = ":";
      } else {
        passthruArgs.add(arg);
      }
    }

    NgClosureRunner runner = new NgClosureRunner(passthruArgs.toArray(new String[]{}), 
      minerrPass, minerrErrors, minerrUrl, minerrSeparator);

    if (runner.shouldRunCompiler()) {
      runner.run();
    } else {
      System.exit(-1);
    }
  }
}
@@ -714,16 +714,55 @@
 arator;%0A
+  private String minerrJsResourcePath;%0A
   privat
@@ -831,17 +831,16 @@
 %5B%5D args,
- 
 %0A       
@@ -879,17 +879,16 @@
 errPass,
- 
 %0A       
@@ -928,17 +928,16 @@
 rErrors,
- 
 %0A       
@@ -1025,16 +1025,73 @@
 eparator
+,%0A                            String minerrJsResourcePath
 ) %7B%0A    
@@ -1185,16 +1185,66 @@
 or;%0A    
+this.minerrJsResourcePath = minerrJsResourcePath;%0A
 %0A    if 
@@ -2138,19 +2138,28 @@
 rce(
-%22
 min
-Err.js%22
+errJsResourcePath
 );%0A%0A
@@ -2219,72 +2219,37 @@
 ass(
-compiler,%0A                            output,%0A                  
+%0A          compiler, output,%0A
     
@@ -3214,17 +3214,28 @@
 rs.json%22
-,
+;%0A    String
  minerrU
@@ -3243,17 +3243,28 @@
 l = null
-,
+;%0A    String
  minerrS
@@ -3279,16 +3279,63 @@
  = %22/%22;%0A
+    String minerrJsResourcePath = %22minErr.js%22;%0A
     List
@@ -3780,16 +3780,118 @@
  = %22:%22;%0A
+      %7D else if (arg.equals(%22--minerr_js_resource_path%22)) %7B%0A        minerrJsResourcePath = args%5B++i%5D;%0A
       %7D 
@@ -3992,16 +3992,25 @@
 eRunner(
+%0A        
 passthru
@@ -4042,10 +4042,11 @@
 %7B%7D),
- 
 %0A
+  
     
@@ -4099,16 +4099,46 @@
 eparator
+,%0A        minerrJsResourcePath
 );%0A%0A    
@@ -4238,8 +4238,9 @@
  %7D%0A  %7D%0A%7D
+%0A

add --minerr_js_resource_path parameter