/*
 *  Copyright 2010 Alex Objelean.
 */
package ro.isdc.wro.extensions.processor.support.coffeescript;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;

import org.mozilla.javascript.ScriptableObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ro.isdc.wro.extensions.processor.support.linter.LinterException;
import ro.isdc.wro.extensions.script.RhinoScriptBuilder;
import ro.isdc.wro.util.StopWatch;
import ro.isdc.wro.util.WroUtil;


/**
 * CoffeeScript is a little language that compiles into JavaScript. Underneath all of those embarrassing braces and
 * semicolons, JavaScript has always had a gorgeous object model at its heart. CoffeeScript is an attempt to expose the
 * good parts of JavaScript in a simple way.
 * <p/>
 * The underlying implementation use the coffee-script version <code>1.4.0</code> project: {@link https
 * ://github.com/jashkenas/coffee-script}.
 *
 * @author Alex Objelean
 * @since 1.3.6
 */
public class CoffeeScript {
  private static final Logger LOG = LoggerFactory.getLogger(CoffeeScript.class);
  private String[] options;
  private ScriptableObject scope;
  private static final String DEFAULT_COFFE_SCRIPT = "coffee-script-1.6.2.min.js";
  /**
   * Initialize script builder for evaluation.
   */
  private RhinoScriptBuilder initScriptBuilder() {
    try {
      RhinoScriptBuilder builder = null;
      if (scope == null) {
        builder = RhinoScriptBuilder.newChain().evaluateChain(getCoffeeScriptAsStream(), DEFAULT_COFFE_SCRIPT);
        scope = builder.getScope();
      } else {
        builder = RhinoScriptBuilder.newChain(scope);
      }
      return builder;
    } catch (final IOException ex) {
      throw new IllegalStateException("Failed reading init script", ex);
    }
  }


  /**
   * Override this method to use a different version of CoffeeScript. This method is useful for upgrading coffeeScript
   * processor independently of wro4j.
   *
   * @return The stream of the CoffeeScript.
   */
  protected InputStream getCoffeeScriptAsStream() {
    return CoffeeScript.class.getResourceAsStream(DEFAULT_COFFE_SCRIPT);
  }


  /**
   * Validates a js using jsHint and throws {@link LinterException} if the js is invalid. If no exception is thrown, the
   * js is valid.
   *
   * @param data js content to process.
   */
  public String compile(final String data) {
    final StopWatch watch = new StopWatch();
    watch.start("init");
    try {
      final RhinoScriptBuilder builder = initScriptBuilder();
      watch.stop();
      watch.start("compile");
      final String compileScript = String.format("CoffeeScript.compile(%s, %s);", WroUtil.toJSMultiLineString(data),
        buildOptions());
      return (String)builder.evaluate(compileScript, "CoffeeScript.compile");
    } finally {
      watch.stop();
      LOG.debug(watch.prettyPrint());
    }
  }


  /**
   * @return A javascript representation of the options. The result is a json object.
   */
  private String buildOptions() {
    final StringBuffer sb = new StringBuffer("{");
    if (options != null) {
      for (int i = 0; i < options.length; i++) {
        sb.append(options[i]).append(": true");
        if (i < options.length - 1) {
          sb.append(",");
        }
      }
    }
    sb.append("}");
    return sb.toString();
  }


  /**
   * @param options the options to set
   */
  public CoffeeScript setOptions(final String... options) {
    this.options = options == null ? new String[] {} : options;
    LOG.debug("setOptions: {}", Arrays.asList(this.options));
    return this;
  }
}

@@ -1,15 +1,14 @@
 /*%0D%0A *
- 
  Copyrig
@@ -14,30 +14,16 @@
 ght 2010
- Alex Objelean
 .%0D%0A */%0D%0A
@@ -419,44 +419,8 @@
 r;%0D%0A
-import ro.isdc.wro.util.StopWatch;%0D%0A
 impo
@@ -762,42 +762,8 @@
 The 
-underlying implementation use the 
 coff
@@ -784,16 +784,24 @@
 ion 
+is used 
 %3Ccode%3E1.
 4.0%3C
@@ -800,26 +800,18 @@
 e%3E1.
-4.0
+6.2
 %3C/code%3E
- project
 : %7B@
@@ -820,21 +820,16 @@
 nk https
-%0D%0A * 
 ://githu
@@ -1172,16 +1172,18 @@
 n.js%22;%0D%0A
+%0D%0A
   /**%0D%0A 
@@ -1740,34 +1740,32 @@
 %0D%0A    %7D%0D%0A  %7D%0D%0A%0D%0A
-%0D%0A
   /**%0D%0A   * Over
@@ -2100,34 +2100,32 @@
 CRIPT);%0D%0A  %7D%0D%0A%0D%0A
-%0D%0A
   /**%0D%0A   * Vali
@@ -2278,16 +2278,31 @@
 ram data
+%0D%0A   *         
  js cont
@@ -2375,93 +2375,8 @@
  %7B%0D%0A
-    final StopWatch watch = new StopWatch();%0D%0A    watch.start(%22init%22);%0D%0A    try %7B%0D%0A  
     
@@ -2436,62 +2436,8 @@
 );%0D%0A
-      watch.stop();%0D%0A      watch.start(%22compile%22);%0D%0A  
     
@@ -2574,26 +2574,24 @@
 ns());%0D%0A    
-  
 return (Stri
@@ -2593,16 +2593,17 @@
 (String)
+ 
 builder.
@@ -2656,101 +2656,15 @@
 );%0D%0A
-    %7D finally %7B%0D%0A      watch.stop();%0D%0A      LOG.debug(watch.prettyPrint());%0D%0A    %7D%0D%0A
   %7D%0D%0A%0D%0A
-%0D%0A
   /*
@@ -3122,18 +3122,16 @@
 %0A  %7D%0D%0A%0D%0A
-%0D%0A
   /**%0D%0A 
@@ -3148,16 +3148,31 @@
  options
+%0D%0A   *         
  the opt

update javadoc