/*
 * Copyright 2016-present Facebook, 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.facebook.buck.rage;

import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.model.Pair;
import com.facebook.buck.util.environment.BuildEnvironmentDescription;
import com.facebook.buck.util.unit.SizeUnit;
import com.facebook.buck.util.versioncontrol.VersionControlCommandFailedException;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;

/**
 * Responsible for gathering logs and other interesting information from buck, driven by user
 * interaction.
 */
public class InteractiveReport extends AbstractReport {

  private final BuildLogHelper buildLogHelper;
  private final Optional<VcsInfoCollector> vcsInfoCollector;
  private final UserInput input;
  private final PrintStream output;

  public InteractiveReport(
      DefectReporter defectReporter,
      ProjectFilesystem filesystem,
      PrintStream output,
      InputStream stdin,
      BuildEnvironmentDescription buildEnvironmentDescription,
      Optional<VcsInfoCollector> vcsInfoCollector,
      ExtraInfoCollector extraInfoCollector) {
    super(filesystem, defectReporter, buildEnvironmentDescription, output, extraInfoCollector);
    this.buildLogHelper = new BuildLogHelper(filesystem);
    this.vcsInfoCollector = vcsInfoCollector;
    this.output = output;
    this.input = new UserInput(output, new BufferedReader(new InputStreamReader(stdin)));
  }

  @Override
  protected ImmutableSet<BuildLogEntry> promptForBuildSelection() throws IOException {
    ImmutableList<BuildLogEntry> buildLogs = buildLogHelper.getBuildLogs();
    return input.selectRange(
        "Which buck invocations would you like to report?",
        buildLogs,
        new Function<BuildLogEntry, String>() {
          @Override
          public String apply(BuildLogEntry input) {
            Pair<Double, SizeUnit> humanReadableSize = SizeUnit.getHumanReadableSize(
                input.getSize(),
                SizeUnit.BYTES);
            return String.format(
                "buck [%s] at %s (%.2f %s)",
                input.getCommandArgs().or("unknown args"),
                input.getLastModifiedTime(),
                humanReadableSize.getFirst(),
                humanReadableSize.getSecond().getAbbreviation());
          }
        });
  }

  @Override
  protected Optional<SourceControlInfo> getSourceControlInfo()
      throws IOException, InterruptedException {
    if (!vcsInfoCollector.isPresent() ||
        !input.confirm("Would you like to attach source control information (this includes " +
            "information about commits and changed files)?")) {
      return Optional.absent();
    }

    try {
      return Optional.of(vcsInfoCollector.get().gatherScmInformation());
    } catch (VersionControlCommandFailedException e) {
      output.printf("Failed to get source control information: %s, proceeding regardless.\n", e);
    }
    return Optional.absent();
  }

  @Override
  protected Optional<UserReport> getUserReport() throws IOException {
    UserReport.Builder userReport = UserReport.builder();

    userReport.setUserIssueDescription(
        input.ask("Please describe the problem you wish to report:"));

    return Optional.of(userReport.build());
  }

}

@@ -1240,16 +1240,67 @@
 tStream;
+%0Aimport java.util.ArrayList;%0Aimport java.util.List;
 %0A%0A/**%0A *
@@ -2451,24 +2451,357 @@
 uildLogs();%0A
+%0A    // Commands with unknown args and buck rage should be excluded.%0A    List%3CBuildLogEntry%3E interestingBuildLogs = new ArrayList%3C%3E();%0A    for (BuildLogEntry entry : buildLogs) %7B%0A      if (entry.getCommandArgs().isPresent() && !entry.getCommandArgs().get().contains(%22rage%22)) %7B%0A        interestingBuildLogs.add(entry);%0A      %7D%0A    %7D%0A%0A
     return i
@@ -2886,17 +2886,28 @@
         
-b
+interestingB
 uildLogs
@@ -3232,16 +3232,22 @@
        %22
+%5Ct%25s%5Ct
 buck %5B%25s
@@ -3251,14 +3251,8 @@
 %5B%25s%5D
- at %25s
  (%25.
@@ -3289,39 +3289,25 @@
 .get
-CommandArgs().or(%22unknown args%22
+LastModifiedTime(
 ),%0A 
@@ -3330,32 +3330,27 @@
 nput.get
-LastModifiedTime
+CommandArgs
 (),%0A    

improve list of commands you can rage