// Copyright (C) 2015 The Android Open Source Project
//
// 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.gerrit.httpd.raw;

import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.common.base.MoreObjects;
import com.google.common.escape.Escaper;
import com.google.common.html.HtmlEscapers;
import com.google.common.io.ByteStreams;
import com.google.gerrit.common.TimeUtil;
import com.google.gwtexpui.server.CacheHeaders;

import org.eclipse.jgit.util.RawParseUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.PrintWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;

import javax.servlet.http.HttpServletResponse;

class BuckUtils {
  private static final Logger log =
      LoggerFactory.getLogger(BuckUtils.class);

  static void build(Path root, Path gen, String target)
      throws IOException, BuildFailureException {
    log.info("buck build " + target);
    Properties properties = loadBuckProperties(gen);
    String buck = MoreObjects.firstNonNull(properties.getProperty("buck"), "buck");
    ProcessBuilder proc = new ProcessBuilder(buck, "build", target)
        .directory(root.toFile())
        .redirectErrorStream(true);
    if (properties.containsKey("PATH")) {
      proc.environment().put("PATH", properties.getProperty("PATH"));
    }
    long start = TimeUtil.nowMs();
    Process rebuild = proc.start();
    byte[] out;
    try (InputStream in = rebuild.getInputStream()) {
      out = ByteStreams.toByteArray(in);
    } finally {
      rebuild.getOutputStream().close();
    }

    int status;
    try {
      status = rebuild.waitFor();
    } catch (InterruptedException e) {
      throw new InterruptedIOException("interrupted waiting for " + buck);
    }
    if (status != 0) {
      throw new BuildFailureException(out);
    }

    long time = TimeUtil.nowMs() - start;
    log.info(String.format("UPDATED    %s in %.3fs", target, time / 1000.0));
  }

  private static Properties loadBuckProperties(Path gen)
      throws FileNotFoundException, IOException {
    Properties properties = new Properties();
    try (InputStream in = new FileInputStream(
        gen.resolve(Paths.get("tools/buck/buck.properties")).toFile())) {
      properties.load(in);
    }
    return properties;
  }

  static void displayFailure(String rule, byte[] why, HttpServletResponse res)
      throws IOException {
    res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    res.setContentType("text/html");
    res.setCharacterEncoding(UTF_8.name());
    CacheHeaders.setNotCacheable(res);

    Escaper html = HtmlEscapers.htmlEscaper();
    try (PrintWriter w = res.getWriter()) {
      w.write("<html><title>BUILD FAILED</title><body>");
      w.format("<h1>%s FAILED</h1>", html.escape(rule));
      w.write("<pre>");
      w.write(html.escape(RawParseUtils.decode(why)));
      w.write("</pre>");
      w.write("</body></html>");
    }
  }

  static class BuildFailureException extends Exception {
    private static final long serialVersionUID = 1L;

    final byte[] why;

    BuildFailureException(byte[] why) {
      this.why = why;
    }
  }
}

@@ -658,92 +658,112 @@
 tic 
-java.nio.charset.StandardCharsets.UTF_8;%0A%0Aimport com.google.common.base.MoreObjects;
+com.google.common.base.MoreObjects.firstNonNull;%0Aimport static java.nio.charset.StandardCharsets.UTF_8;%0A
 %0Aimp
@@ -1082,78 +1082,8 @@
 y;%0A%0A
-import java.io.FileInputStream;%0Aimport java.io.FileNotFoundException;%0A
 impo
@@ -1197,24 +1197,94 @@
 rintWriter;%0A
+import java.nio.file.Files;%0Aimport java.nio.file.NoSuchFileException;%0A
 import java.
@@ -1722,28 +1722,16 @@
  buck = 
-MoreObjects.
 firstNon
@@ -2717,44 +2717,15 @@
 gen)
-%0A     
  throws
- FileNotFoundException,
  IOE
@@ -2789,58 +2789,16 @@
     
-try (InputStream in = new FileInputStream(%0A       
+Path p =
  gen
@@ -2850,48 +2850,205 @@
 s%22))
-.toFile())) %7B%0A      properties.load(in);
+;%0A    try (InputStream in = Files.newInputStream(p)) %7B%0A      properties.load(in);%0A    %7D catch (NoSuchFileException e) %7B%0A      // Ignore; will be run from PATH, with a descriptive error if it fails.
 %0A   

Support missing buck.properties