package accrue.jl5;

import java.io.PrintStream;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import accrue.AccrueExtensionInfo;
import accrue.AccrueJLOptions;

import polyglot.ext.jl5.JL5ExtensionInfo;
import polyglot.ext.jl5.JL5Options;
import polyglot.main.OptFlag;
import polyglot.main.OptFlag.Arg;
import polyglot.main.Options;
import polyglot.main.UsageError;
import polyglot.util.InternalCompilerError;

/**
 * Polyglot extension that pre-processes java5 code with the JL5 extension, converting
 * it to Java 1.4 code, and then performs an analysis pass.
 */
public abstract class AccrueJL5TranslationExtensionInfo extends
        JL5ExtensionInfo {

    /**
     * 
     * @param extInfo The AccrueExtensionInfo to run on the classes once they
     *                have been translated to Java 1.4.
     */
    public AccrueJL5TranslationExtensionInfo(AccrueExtensionInfo extInfo) {
        this.outputExtensionInfo = extInfo;
        extInfo.setIsOutputExtensionInfo(true);
    }

    @Override
    public String defaultFileExtension() {
        return "jl5";
    }

    @Override
    public String[] defaultFileExtensions() {
        String ext = defaultFileExtension();
        return new String[] { ext, "jl", "java" };
    }

    @Override
    public String compilerName() {
        return outputExtensionInfo().compilerName() + "(5)";
    }

    @Override
    protected Options createOptions() {
        return new AccrueJL5TranslationOptions(this);
    }

    /**
     * This options class uses the options of the succeeding info flow extension
     * pass
     */
    public static class AccrueJL5TranslationOptions extends JL5Options {

        /**
         * Create the Options by passing in the extension info an setting it
         * into the {@link Options} for the info flow pass
         * 
         * @param extension
         *            extension info to build these options from
         */
        public AccrueJL5TranslationOptions(
                AccrueJL5TranslationExtensionInfo extInfo) {
            super(extInfo);
            // make sure that we perform translation from Java  to Java 1.4
            this.removeJava5isms = true;
        }

        @Override
        public void usage(PrintStream out) {
            this.extension.outputExtensionInfo().getOptions().usage(out);
        }

        @Override
        protected void populateFlags(Set<OptFlag<?>> flags) {
            super.populateFlags(flags);
            AccrueJLOptions ajlo =
                    (AccrueJLOptions) this.extension.outputExtensionInfo()
                                                    .getOptions();
            ajlo.helper().populateFlags(flags);
        }

        @Override
        protected void handleArg(Arg<?> arg) throws UsageError {
            AccrueJLOptions ajlo =
                    (AccrueJLOptions) this.extension.outputExtensionInfo()
                                                    .getOptions();
            if (ajlo.helper().handleArg(arg)) {
                // the helper was able to handle the argument.
                return;
            }
            super.handleArg(arg);
        }

        @Override
        protected void postApplyArgs() {
            super.postApplyArgs();
            // now pass on the arguments that this extension info swallowed to 
            // the output extension info.
            // Filter the parent's options by the ones the output extension 
            // info understands.
            Options subOpts = this.extension.outputExtensionInfo().getOptions();
            List<Arg<?>> arguments = this.filterArgs(subOpts.flags());
            try {
                System.err.println("Post: " + arguments);
                subOpts.processArguments(arguments,
                                         Collections.<String> emptySet());
            }
            catch (UsageError e) {
                throw new InternalCompilerError("Got usage error while configuring output extension",
                                                e);
            }
        }

    }
}
