// Copyright (C) 2008 Google 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.google.caja.tools;

import com.google.caja.parser.quasiliteral.DojoRuleDoclet;
import com.google.caja.parser.quasiliteral.HtmlRuleDoclet;
import com.google.caja.parser.quasiliteral.JsonRuleDoclet;
import com.google.caja.parser.quasiliteral.Rewriter;
import com.google.caja.parser.quasiliteral.RuleDoclet;
import com.google.caja.parser.quasiliteral.TextRuleDoclet;
import com.google.caja.parser.quasiliteral.WikiRuleDoclet;
import com.google.caja.reporting.BuildInfo;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

/**
 * ANT task that extracts and generates documentation on rewrite rules
 *
 * @author jasvir@gmail.com (Jasvir Nagra)
 */
public class DocletAntTask extends Task {

  private String outputDir;
  private RuleDoclet output;
  private Rewriter rewriter;

  public void setOutputDir(String outputDir) {
    this.outputDir = outputDir;
  }

  /**
   * Sets the type of output generated by the doclet.
   * @param output Valid options are text|html|wiki|json|dojo
   */
  public void setOutput(String output) {
    if(output.equals("text")) {
      this.output = new TextRuleDoclet();
    } else if(output.equals("html")) {
      this.output = new HtmlRuleDoclet();
    } else if(output.equals("json")) {
      this.output = new JsonRuleDoclet();
    } else if(output.equals("text")) {
      this.output = new WikiRuleDoclet();
    } else if(output.equals("dojo")) {
      this.output = new DojoRuleDoclet();
    } else {
      throw new BuildException("Unsupported doclet type");
    }
  }

  public void setRewriter(String className) {
    try {
      Class<? extends Rewriter> rewriterClass = Class.forName(className)
          .asSubclass(Rewriter.class);
      Constructor<? extends Rewriter> ctor = publicCtor(rewriterClass);
      Object[] actuals = new Object[ctor.getParameterTypes().length];
      int i = 0;
      for (Class<?> ptype : ctor.getParameterTypes()) {
        if (Boolean.TYPE.equals(ptype)) {
          actuals[i] = Boolean.FALSE;  // No logging
        } else if (BuildInfo.class.isAssignableFrom(ptype)) {
          actuals[i] = BuildInfo.getInstance();
        }
        ++i;
      }
      this.rewriter = ctor.newInstance(actuals);
    } catch (InstantiationException e) {
      throw new BuildException(e);
    } catch (InvocationTargetException e) {
      throw new BuildException(e);
    } catch (IllegalAccessException e) {
      throw new BuildException(e);
    } catch (ClassNotFoundException e) {
      throw new BuildException(e);
    }
  }

  @SuppressWarnings("unchecked")
  private static <T> Constructor<T> publicCtor(Class<T> cl)
      throws IllegalAccessException {
    for (Constructor<?> c : cl.getDeclaredConstructors()) {
      if (Modifier.isPublic(c.getModifiers())) {
        return (Constructor<T>) c;
      }
    }
    throw new IllegalAccessException();  // No public ctor
  }

  private void checkValidParameters() {
    if (null == output) {
      throw new BuildException("Doclet \"output\" type not set");
    }
    if (null == rewriter) {
      throw new BuildException("Doclet \"rewriter\" not set");
    }
    if (null == outputDir) {
      throw new BuildException("Doclet \"outputDir\" not set");
    }
  }

  /**
   * Constructs output file name for a given rewriter and output directory
   */
  private String getOutputFileName() {
    String simpleFileName = rewriter.getClass().getSimpleName();
    String dirFileName = outputDir.endsWith("/")
       ? outputDir + simpleFileName
       : outputDir + '/' + simpleFileName;
    String completeFileName = dirFileName + '.' + output.getDefaultExtension();
    return completeFileName;

  }

  @Override
  public void execute() throws BuildException {
    try {
      checkValidParameters();
      output.setRewriter(rewriter);
      String outputFile = getOutputFileName();
      BufferedWriter outputStream = new BufferedWriter(
          new OutputStreamWriter(new FileOutputStream(outputFile), "UTF-8"));
      output.generateDocumentation(outputStream);
      outputStream.close();
    } catch (IOException e) {
      throw new BuildException(e);
    }
  }
}

@@ -1065,16 +1065,116 @@
 ildInfo;
+%0Aimport com.google.caja.reporting.MessageQueue;%0Aimport com.google.caja.reporting.SimpleMessageQueue;
 %0A%0Aimport
@@ -3072,24 +3072,138 @@
 Instance();%0A
+        %7D else if (MessageQueue.class.isAssignableFrom(ptype)) %7B%0A          actuals%5Bi%5D = new SimpleMessageQueue();%0A
         %7D%0A  

Fix doclet ant task. http://codereview.appspot.com/110097