// 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.googlesource.gerrit.plugins.xdocs.client;

import com.google.gerrit.plugin.client.Plugin;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.ImageResourceRenderer;
import com.google.gwt.user.client.ui.InlineHyperlink;
import com.google.gwt.user.client.ui.Label;

import com.googlesource.gerrit.plugins.xdocs.client.ChangeInfo.RevisionInfo;

public class PatchSetSelectBox extends FlowPanel {

  public enum DisplaySide {
    A, B
  }

  public static enum DiffView {
    SIDE_BY_SIDE,
    UNIFIED_DIFF
  }

  private static final String COMMIT_MSG = "/COMMIT_MSG";

  private final DiffView diffView;
  private final DisplaySide side;
  private final ChangeInfo change;
  private final Integer basePatchSet;
  private final int patchSet;
  private final String path;

  public PatchSetSelectBox(DiffView diffView, DisplaySide side,
      ChangeInfo change, Integer basePatchSet, int patchSet, String path) {
    this.diffView = diffView;
    this.side = side;
    this.change = change;
    this.path = path;
    this.basePatchSet = basePatchSet;
    this.patchSet = patchSet;

    init();
  }

  private void init() {
    setStyleName("xdocs-patch-set-select-box");
    if (isSideBySideDiff()) {
      addStyleName("xdocs-patch-set-select-box-side-by-side");
    }

    addPatchSetLabel();

    if (sideA()) {
      add(createBaseLink());
    } else if (isUnifiedDiff()) {
      // create hidden 'Base' link to align the patch set links with side A
      add(createHiddenBaseLink());
    }

    JsArray<RevisionInfo> list = change.revisions().values();
    RevisionInfo.sortRevisionInfoByNumber(list);
    for (int i = 0; i < list.length(); i++) {
      add(createLink(list.get(i)));
    }

    if (!COMMIT_MSG.equals(path)) {
      add(createDownloadLink());
    }

    if (showEditIcon()) {
      add(createEditIcon());
    }
  }

  private void addPatchSetLabel() {
    add(new Label("Patch Set"));
    if (isUnifiedDiff()) {
      Label l = new Label(sideA() ? "(-)" : "(+)");
      l.addStyleName("xdocs-monospace");
      add(l);
    }
  }

  private boolean isSideBySideDiff() {
    return diffView == DiffView.SIDE_BY_SIDE;
  }

  private boolean isUnifiedDiff() {
    return diffView == DiffView.UNIFIED_DIFF;
  }

  private boolean sideA() {
    return side == DisplaySide.A;
  }

  private InlineHyperlink createBaseLink() {
    InlineHyperlink link = new InlineHyperlink("Base",
        getUrl(change._number(), null, patchSet, path, diffView));
    if (isBaseSelected()) {
      link.setStyleName("xdocs-patch-set-select-box-selected");
    }
    return link;
  }

  private InlineHyperlink createHiddenBaseLink() {
    InlineHyperlink link = new InlineHyperlink("Base", null);
    link.addStyleName("xdocs-hidden");
    return link;
  }

  private InlineHyperlink createLink(RevisionInfo r) {
    String label = r.is_edit() ? "edit" : Integer.toString(r._number());
    Integer patchSetIdA = sideA() ? Integer.valueOf(r._number()) : basePatchSet;
    int patchSetIdB = sideA() ? patchSet : r._number();
    InlineHyperlink link = new InlineHyperlink(label,
        getUrl(change._number(), patchSetIdA, patchSetIdB, path, diffView));
    if (isSelected(r._number())) {
      link.setStyleName("xdocs-patch-set-select-box-selected");
    }
    return link;
  }

  private Anchor createDownloadLink() {
    String base = GWT.getHostPageBaseURL() + "cat/";
    String sideUrl = isBaseSelected() ? "1" : "0";
    int ps = isBaseSelected()
        ? change.revision(change.current_revision())._number()
        : getSelectedPatchSet();
    Anchor anchor = new Anchor(
        new ImageResourceRenderer().render(XDocsPlugin.RESOURCES.downloadIcon()),
        base + URL.encode(change._number() + "," + ps + "," + path) + "^" + sideUrl);
    anchor.setTitle("Download");
    return anchor;
  }

  private boolean showEditIcon() {
    if (sideA() || !change.isOpen() || !Plugin.get().isSignedIn()) {
      return false;
    }

    if (change.has_edit()) {
      return patchSet == 0;
    } else {
      return patchSet == change.revision(change.current_revision())._number();
    }
  }

  private Anchor createEditIcon() {
    Anchor anchor = new Anchor(
        new ImageResourceRenderer().render(XDocsPlugin.RESOURCES.edit()),
        "#" + getEditUrl(change._number(), patchSet, path));
    anchor.setTitle("Edit");
    return anchor;
  }

  private Integer getSelectedPatchSet() {
    return sideA() ? basePatchSet : Integer.valueOf(patchSet);
  }

  private boolean isBaseSelected() {
    return getSelectedPatchSet() == null;
  }

  private boolean isSelected(int ps) {
    return getSelectedPatchSet() != null
        && getSelectedPatchSet().intValue() == ps;
  }

  private static String getUrl(int changeId, Integer patchSetIdA,
      int patchSetIdB, String path, DiffView diffView) {
    StringBuilder url = new StringBuilder();
    url.append("/x/");
    url.append(Plugin.get().getName());
    url.append("/c/");
    url.append(changeId);
    url.append("/");
    if (patchSetIdA != null) {
      url.append(patchSetIdA);
      url.append("..");
    }
    url.append(patchSetIdB);
    url.append("/");
    url.append(path);
    if (diffView == DiffView.UNIFIED_DIFF) {
      url.append(",unified");
    }
    return url.toString();
  }

  private static String getEditUrl(int changeId, int patchSetId, String path) {
    StringBuilder url = new StringBuilder();
    url.append("/c/");
    url.append(changeId);
    url.append("/");
    url.append(patchSetId);
    url.append("/");
    url.append(path);
    url.append(",edit");
    return url.toString();
  }
}

@@ -704,16 +704,64 @@
 Plugin;%0A
+import com.google.gerrit.reviewdb.client.Patch;%0A
 import c
@@ -1373,67 +1373,8 @@
  %7D%0A%0A
-  private static final String COMMIT_MSG = %22/COMMIT_MSG%22;%0A%0A
   pr
@@ -2503,16 +2503,22 @@
    if (!
+Patch.
 COMMIT_M

Use Patch.COMMIT_MSG instead of redefining this constant in the plugin