// Copyright 2016 Google Inc. All Rights Reserved.
package com.google.copybara;

import static com.google.copybara.WorkflowOptions.CHANGE_REQUEST_PARENT_FLAG;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.copybara.Origin.ChangesVisitor;
import com.google.copybara.Origin.VisitResult;
import com.google.copybara.Workflow.RunHelper;
import com.google.copybara.doc.annotations.DocField;
import com.google.copybara.transform.ValidationException;
import com.google.copybara.util.console.ProgressPrefixConsole;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Workflow type to run between origin an destination
 */
public enum WorkflowMode {
  /**
   * Create a single commit in the destination with new tree state.
   */
  @DocField(description = "Create a single commit in the destination with new tree state.")
  SQUASH {
    @Override
    <R extends Origin.Reference> void run(Workflow<R>.RunHelper runHelper)
        throws RepoException, IOException, EnvironmentException, ValidationException {
      runHelper.migrate(
          runHelper.getResolvedRef(),
          // SQUASH workflows always use the default author
          runHelper.getAuthoring().getDefaultAuthor(),
          runHelper.getConsole(),
          runHelper.changesSummaryMessage());
    }
  },

  /**
   * Import each origin change individually.
   */
  @DocField(description = "Import each origin change individually.")
  ITERATIVE {
    @Override
    <R extends Origin.Reference> void run(Workflow<R>.RunHelper runHelper)
        throws RepoException, IOException, EnvironmentException, ValidationException {
      ImmutableList<Change<R>> changes = runHelper.changesSinceLastImport();
      for (int i = 0; i < changes.size(); i++) {
        Change<R> change = changes.get(i);
        String prefix = String.format(
            "[%2d/%d] Migrating change %s: ", i + 1, changes.size(),
            change.getReference().asString());

        runHelper.migrate(
            change.getReference(),
            change.getAuthor(),
            new ProgressPrefixConsole(prefix, runHelper.getConsole()),
            change.getMessage());
      }
    }
  },
  @DocField(description = "Import an origin tree state diffed by a common parent"
      + " in destination. This could be a GH Pull Request, a Gerrit Change, etc.")
  CHANGE_REQUEST {
    @Override
    <R extends Origin.Reference> void run(Workflow<R>.RunHelper helper)
        throws RepoException, IOException, EnvironmentException, ValidationException {
      final AtomicReference<String> requestParent = new AtomicReference<>(
          helper.workflowOptions().changeBaseline);
      final String originLabelName = helper.getDestination().getLabelNameWhenOrigin();
      if (Strings.isNullOrEmpty(requestParent.get())) {
        helper.getOrigin().visitChanges(helper.getResolvedRef(), new ChangesVisitor() {
          @Override
          public VisitResult visit(Change<?> change) {
            if (change.getLabels().containsKey(originLabelName)) {
              requestParent.set(change.getLabels().get(originLabelName));
              return VisitResult.TERMINATE;
            }
            return VisitResult.CONTINUE;
          }
        });
      }

      if (Strings.isNullOrEmpty(requestParent.get())) {
        throw new ValidationException(
            "Cannot find matching parent commit in in the destination. Use '"
                + CHANGE_REQUEST_PARENT_FLAG
                + "' flag to force a parent commit to use as baseline in the destination.");
      }
      Change<R> change = helper.getOrigin().change(helper.getResolvedRef());
      helper.migrate(helper.getResolvedRef(), change.getAuthor(), helper.getConsole(),
          change.getMessage(), requestParent.get());
    }
  },

  // TODO(copybara): Implement
  @DocField(description = "Mirror individual changes from origin to destination. Requires that "
      + "origin and destination are of the same type and that they support mirroring.",
      undocumented = true)
  MIRROR {
    @Override
    <R extends Origin.Reference> void run(Workflow<R>.RunHelper helper)
        throws RepoException, IOException, EnvironmentException, ValidationException {
      throw new UnsupportedOperationException("WorkflowMode 'MIRROR' not implemented.");
    }
  };

  abstract <R extends Origin.Reference> void run(Workflow<R>.RunHelper runHelper)
      throws RepoException, IOException, EnvironmentException, ValidationException;
}

@@ -341,55 +341,8 @@
 lt;%0A
-import com.google.copybara.Workflow.RunHelper;%0A
 impo
@@ -1851,37 +1851,31 @@
     
-%22%5B%252d/%25d%5D Migrating change %25s
+  %22Change %25d of %25d (%25s)
 : %22,
@@ -1893,36 +1893,24 @@
 nges.size(),
-%0A           
  change.getR

Make iterative progress message shorter