/*
 * Copyright 2000-2012 JetBrains s.r.o.
 *
 * 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 org.rust.jps;


import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.builders.DirtyFilesHolder;
import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor;
import org.jetbrains.jps.incremental.*;
import org.jetbrains.jps.incremental.messages.BuildMessage;
import org.jetbrains.jps.incremental.messages.CompilerMessage;
import org.jetbrains.jps.model.module.JpsModule;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class RustBuilder extends ModuleLevelBuilder {

    public RustBuilder() {
        super(BuilderCategory.TRANSLATOR);
    }


    public ExitCode build(final CompileContext context,
                          final ModuleChunk chunk,
                          final DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder,
                          final OutputConsumer outputConsumer) throws ProjectBuildException, IOException {

        context.processMessage(new CompilerMessage("rust", BuildMessage.Kind.INFO, "Start"));

        for (JpsModule module : chunk.getModules()) {
            String path = getContentRootPath(module);

            ProcessBuilder processBuilder = new ProcessBuilder("cargo", "build");
            processBuilder.redirectErrorStream(true);
            processBuilder.directory(new File(path));
            final Process process = processBuilder.start();
            processOut(context, process);
            try {
                if (process.waitFor() != 0) {
                    return ExitCode.ABORT;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }



        return ExitCode.OK;
    }

    private void processOut(CompileContext context, Process process) throws IOException {
        Iterator<String> processOut = collectOutput(process);

        while (processOut.hasNext()) {
            String line = processOut.next();
            context.processMessage(new CompilerMessage("rust", BuildMessage.Kind.INFO, line));
        }
    }

    private Iterator<String> collectOutput(Process process) throws IOException {
        final BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        return new Iterator<String>() {

            String line = null;

            @Override
            public boolean hasNext() {
                return fetch() != null;
            }

            private String fetch() {
                if (line == null) {
                    try {
                        line = reader.readLine();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                return line;
            }

            @Override
            public String next() {
                String result = fetch();
                line = null;
                return result;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }

    private String getContentRootPath(JpsModule module) {
        final List<String> urls = module.getContentRootsList().getUrls();
        if (urls.size() == 0) {
            throw new RuntimeException("Can't find content root in module");
        }
        String url = urls.get(0);
        return url.substring("file://".length());
    }


    @Override
    public List<String> getCompilableFileExtensions() {
        return Collections.singletonList("rs");
    }


    @Override
    public String toString() {
        return getPresentableName();
    }

    @NotNull
    public String getPresentableName() {
        return "Cargo builder";
    }

}

@@ -1356,25 +1356,24 @@
 OR);%0A    %7D%0A%0A
-%0A
     public E
@@ -1731,36 +1731,37 @@
 ompilerMessage(%22
-rust
+cargo
 %22, BuildMessage.
@@ -1776,13 +1776,19 @@
 O, %22
-Start
+cargo build
 %22));
@@ -2171,16 +2171,24 @@
 cessOut(
+module, 
 context,
@@ -2232,20 +2232,16 @@
         
-if (
 process.
@@ -2253,77 +2253,9 @@
 or()
- != 0) %7B%0A                    return ExitCode.ABORT;%0A                %7D
+;
 %0A   
@@ -2341,32 +2341,129 @@
 ;%0A            %7D%0A
+            if (process.exitValue() != 0) %7B%0A                return ExitCode.ABORT;%0A            %7D%0A
         %7D%0A%0A%0A%0A   
@@ -2457,18 +2457,16 @@
      %7D%0A%0A
-%0A%0A
         
@@ -2520,16 +2520,34 @@
 cessOut(
+JpsModule module, 
 CompileC
@@ -2751,102 +2751,908 @@
 ();%0A
-            context.processMessage(new CompilerMessage(%22rust%22, BuildMessage.Kind.INFO, line));
+%0A            Matcher matcher = Pattern.compile(%22(.*):(%5C%5Cd+):(%5C%5Cd+): (%5C%5Cd+):(%5C%5Cd+) error:(.*)%22).matcher(line);%0A            if (matcher.find()) %7B%0A                String file = matcher.group(1);%0A%0A                String sourcePath = getContentRootPath(module) + %22/%22 + file.replace('%5C%5C', '/');%0A%0A                long startLineNum = Long.parseLong(matcher.group(2));%0A                long startColNum = Long.parseLong(matcher.group(3));%0A                long endLineNum = Long.parseLong(matcher.group(4));%0A                long endColNum = Long.parseLong(matcher.group(5));%0A                String msg = matcher.group(6);%0A%0A                context.processMessage(new CompilerMessage(%0A                    %22cargo%22,%0A                    BuildMessage.Kind.ERROR,%0A                    msg,%0A                    sourcePath,%0A                    -1L, -1L, -1L,%0A                    startLineNum, startColNum));%0A            %7D
 %0A   
@@ -3657,32 +3657,33 @@
        %7D%0A    %7D%0A%0A
+%0A
     private Iter

Add error message parsing