package ro.isdc.wro.extensions.processor.js;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.Executor;
import org.apache.commons.exec.PumpStreamHandler;
import org.apache.commons.io.input.ReaderInputStream;
import org.apache.commons.io.output.WriterOutputStream;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ro.isdc.wro.model.resource.Resource;
import ro.isdc.wro.model.resource.ResourceType;
import ro.isdc.wro.model.resource.SupportedResourceType;
import ro.isdc.wro.model.resource.processor.ResourcePostProcessor;
import ro.isdc.wro.model.resource.processor.ResourcePreProcessor;
import ro.isdc.wro.model.resource.processor.SupportAware;


/**
 * @author Janek L.B
 * @since 1.7.4
 * @created 26 Jan 2014
 */
@SupportedResourceType(ResourceType.JS)
public class NgMinProcessor
    implements ResourcePreProcessor, ResourcePostProcessor, SupportAware {

  public static final String ALIAS = "ngMin";
  private static final Logger LOG = LoggerFactory.getLogger(NgMinProcessor.class);

  /**
   * 'ngmin' must be available on the $PATH, and can be installed via npm: 'npm install -g ngmin'
   */
  private static final String NGMIN_COMMAND = "ngmin";

  @Override
  public void process(final Resource resource, final Reader reader, final Writer writer)
      throws IOException {
    final OutputStream out = new WriterOutputStream(writer);
    final InputStream in = new ReaderInputStream(reader);

    try {
      process(in, out);
    } catch (final IOException ex) {
      final String resourceUri = resource == null ? StringUtils.EMPTY : "[" + resource.getUri() + "]";
      LOG.warn("Exception while applying " + getClass().getSimpleName() + " processor on the " + resourceUri
          + " resource, no processing applied...", ex);
      throw ex;
    }
  }

  @Override
  public void process(final Reader reader, final Writer writer)
      throws IOException {
    process(null, reader, writer);
  }

  private void process(final InputStream in, final OutputStream out)
      throws ExecuteException, IOException {
    final ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
    final Executor executor = new DefaultExecutor();
    executor.setStreamHandler(new PumpStreamHandler(out, errorStream, in));
    final int result = executor.execute(CommandLine.parse(NGMIN_COMMAND));
    LOG.debug("result={}", result);
    if (result != 0) {
      throw new ExecuteException("Processing failed: " + new String(errorStream.toByteArray()), result);
    }
  }

  @Override
  public boolean isSupported() {
    try {
      final InputStream input = new ByteArrayInputStream("".getBytes("UTF-8"));
      process(input, null);
    } catch (final Exception e) {
      LOG.debug("The {} processor is not supported. Because: {}", getClass().getName(), e.getMessage());
    }
    return false;
  }

}

@@ -1037,16 +1037,275 @@
 ;%0A%0A%0A/**%0A
+ * Uses ngmin node utility.%0A * %3Cp/%3E%0A * Ngmin is a %22pre-minifier%22 for AngularJS. It modifies Angular code to prevent errors that may arise from minification.%0A * %3Cp/%3E%0A * More details can be found here: http://www.thinkster.io/pick/XlWneEZCqY/angularjs-ngmin%0A *%0A
  * @auth

update javadoc of NgMinProcessor