package com.redhat.ceylon.compiler.java.runtime.tools.impl;

import java.io.File;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.tools.Diagnostic;
import javax.tools.Diagnostic.Kind;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject;

import com.redhat.ceylon.compiler.java.launcher.Main.ExitState;
import com.redhat.ceylon.compiler.java.launcher.Main.ExitState.CeylonState;
import com.redhat.ceylon.compiler.java.runtime.tools.CompilationListener;
import com.redhat.ceylon.compiler.java.runtime.tools.Compiler;
import com.redhat.ceylon.compiler.java.runtime.tools.CompilerOptions;
import com.redhat.ceylon.compiler.java.tools.CeylonTaskListener;
import com.redhat.ceylon.compiler.java.tools.CeyloncTaskImpl;
import com.redhat.ceylon.compiler.java.tools.CeyloncTool;
import com.sun.source.util.TaskEvent;
import com.sun.tools.javac.api.ClientCodeWrapper.Trusted;
import com.sun.tools.javac.file.JavacFileManager;

public class JavaCompilerImpl implements Compiler {

    // if this is not here, this task will be wrapped into a TaskListener that does not implement CeylonTaskListener
    @Trusted
    public static class CompilationListenerAdapter implements DiagnosticListener<JavaFileObject>, CeylonTaskListener {

        private CompilationListener listener;

        public CompilationListenerAdapter(CompilationListener listener) {
            this.listener = listener;
        }

        @Override
        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
            Kind kind = diagnostic.getKind();
            String message = diagnostic.getMessage(Locale.getDefault());
            long line = diagnostic.getLineNumber();
            long column = diagnostic.getColumnNumber();
            JavaFileObject source = diagnostic.getSource();
            File file = null;
            if(source != null) {
                try {
                    file = new File(source.toUri());
                } catch (IllegalArgumentException ignore) {
                    // An entry in a zip file that is not hierarchical
                }
            }
            switch(kind){
            case ERROR:
                listener.error(file, line, column, message);
                break;
            case WARNING:
            case MANDATORY_WARNING:
                listener.warning(file, line, column, message);
                break;
            case NOTE:
            case OTHER:
            default:
                // ignore?
                break;
            }
        }

        @Override
        public void started(TaskEvent e) {
        }

        @Override
        public void finished(TaskEvent e) {
        }

        @Override
        public void moduleCompiled(String name, String version) {
            listener.moduleCompiled(name, version);
        }

    }

    @SuppressWarnings("deprecation")
    @Override
    public boolean compile(CompilerOptions options, 
                           CompilationListener listener) {
        CeyloncTool compiler = new CeyloncTool();
        CompilationListenerAdapter diagnosticListener = new CompilationListenerAdapter(listener);
        Writer writer = null;
        // FIXME: allow the user to capture stdout
        if(!options.isVerbose()){
            // make the tool shut the hell up
            writer = new NullWriter();
        }

        JavacFileManager fileManager = compiler.getStandardFileManager(writer, diagnosticListener, null, null);

        
        Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(options.getFiles());

        CeyloncTaskImpl compilerTask = compiler.getTask(null, fileManager, diagnosticListener, 
                                                        translateOptions(options), options.getModules(), compilationUnits);
        compilerTask.setTaskListener(diagnosticListener);
        ExitState state = compilerTask.call2();
        // print any helpful info if required
        if(options.isVerbose() && state.abortingException != null)
            state.abortingException.printStackTrace();
        return state.ceylonState == CeylonState.OK;
    }

    private List<String> translateOptions(CompilerOptions options) {
        List<String> translatedOptions = new ArrayList<String>();
        // FIXME: translate every option
        if(options.isVerbose())
            translatedOptions.add("-verbose");
        for(File sourcePath : options.getSourcePath()){
            translatedOptions.add("-src");
            translatedOptions.add(sourcePath.getPath());
        }
        for(String rep : options.getUserRepositories()){
            translatedOptions.add("-rep");
            translatedOptions.add(rep);
        }
        if(options.getOutputRepository() != null){
            translatedOptions.add("-out");
            translatedOptions.add(options.getOutputRepository());
        }
        if(options.getSystemRepository() != null){
            translatedOptions.add("-sysrep");
            translatedOptions.add(options.getSystemRepository());
        }
        return translatedOptions;
    }

}

@@ -1784,32 +1784,128 @@
 ColumnNumber();%0A
+            if(column != -1)%0A                column += 1; // make it 1-based, like line numbers%0A
             Java

make columns 1-based like for javascript compiler