// 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.client.account;

import static java.util.Comparator.comparing;

import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.info.GpgKeyInfo;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.NativeMap;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.ui.FancyFlexTable;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.http.client.Response;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.StatusCodeException;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwtexpui.clippy.client.CopyableLabel;
import com.google.gwtexpui.globalkey.client.NpTextArea;
import java.util.ArrayList;
import java.util.List;

public class MyGpgKeysScreen extends SettingsScreen {
  interface Binder extends UiBinder<HTMLPanel, MyGpgKeysScreen> {}

  private static final Binder uiBinder = GWT.create(Binder.class);

  @UiField(provided = true)
  GpgKeyTable keys;

  @UiField Button deleteKey;
  @UiField Button addKey;

  @UiField VerticalPanel addKeyBlock;
  @UiField NpTextArea keyText;

  @UiField VerticalPanel errorPanel;
  @UiField Label errorText;

  @UiField Button clearButton;
  @UiField Button addButton;
  @UiField Button closeButton;

  @Override
  protected void onInitUI() {
    super.onInitUI();
    keys = new GpgKeyTable();
    add(uiBinder.createAndBindUi(this));
    keys.updateDeleteButton();
  }

  @Override
  protected void onLoad() {
    super.onLoad();
    refreshKeys();
  }

  @UiHandler("deleteKey")
  void onDeleteKey(@SuppressWarnings("unused") ClickEvent e) {
    keys.deleteChecked();
  }

  @UiHandler("addKey")
  void onAddKey(@SuppressWarnings("unused") ClickEvent e) {
    showAddKeyBlock(true);
  }

  @UiHandler("clearButton")
  void onClearButton(@SuppressWarnings("unused") ClickEvent e) {
    keyText.setText("");
    keyText.setFocus(true);
    errorPanel.setVisible(false);
  }

  @UiHandler("closeButton")
  void onCloseButton(@SuppressWarnings("unused") ClickEvent e) {
    showAddKeyBlock(false);
  }

  @UiHandler("addButton")
  void onAddButton(@SuppressWarnings("unused") ClickEvent e) {
    doAddKey();
  }

  private void refreshKeys() {
    AccountApi.self()
        .view("gpgkeys")
        .get(
            NativeMap.copyKeysIntoChildren(
                "id",
                new GerritCallback<NativeMap<GpgKeyInfo>>() {
                  @Override
                  public void onSuccess(NativeMap<GpgKeyInfo> result) {
                    List<GpgKeyInfo> list = Natives.asList(result.values());
                    // TODO(dborowitz): Sort on something more meaningful, like
                    // created date?
                    list.sort(comparing(GpgKeyInfo::id));
                    keys.clear();
                    keyText.setText("");
                    errorPanel.setVisible(false);
                    addButton.setEnabled(true);
                    if (!list.isEmpty()) {
                      keys.setVisible(true);
                      for (GpgKeyInfo k : list) {
                        keys.addOneKey(k);
                      }
                      showKeyTable(true);
                      showAddKeyBlock(false);
                    } else {
                      keys.setVisible(false);
                      showAddKeyBlock(true);
                      showKeyTable(false);
                    }

                    display();
                  }
                }));
  }

  private void showAddKeyBlock(boolean show) {
    addKey.setVisible(!show);
    addKeyBlock.setVisible(show);
  }

  private void showKeyTable(boolean show) {
    keys.setVisible(show);
    deleteKey.setVisible(show);
    addKey.setVisible(show);
  }

  private void doAddKey() {
    if (keyText.getText().isEmpty()) {
      return;
    }
    addButton.setEnabled(false);
    keyText.setEnabled(false);
    AccountApi.addGpgKey(
        "self",
        keyText.getText(),
        new AsyncCallback<NativeMap<GpgKeyInfo>>() {
          @Override
          public void onSuccess(NativeMap<GpgKeyInfo> result) {
            keyText.setEnabled(true);
            refreshKeys();
          }

          @Override
          public void onFailure(Throwable caught) {
            keyText.setEnabled(true);
            addButton.setEnabled(true);
            if (caught instanceof StatusCodeException) {
              StatusCodeException sce = (StatusCodeException) caught;
              if (sce.getStatusCode() == Response.SC_CONFLICT
                  || sce.getStatusCode() == Response.SC_BAD_REQUEST) {
                errorText.setText(sce.getEncodedResponse());
              } else {
                errorText.setText(sce.getMessage());
              }
            } else {
              errorText.setText("Unexpected error saving key: " + caught.getMessage());
            }
            errorPanel.setVisible(true);
          }
        });
  }

  private class GpgKeyTable extends FancyFlexTable<GpgKeyInfo> {
    private final ValueChangeHandler<Boolean> updateDeleteHandler;

    GpgKeyTable() {
      table.setWidth("");
      table.setText(0, 1, Util.C.gpgKeyId());
      table.setText(0, 2, Util.C.gpgKeyFingerprint());
      table.setText(0, 3, Util.C.gpgKeyUserIds());

      FlexCellFormatter fmt = table.getFlexCellFormatter();
      fmt.addStyleName(0, 0, Gerrit.RESOURCES.css().iconHeader());
      fmt.addStyleName(0, 1, Gerrit.RESOURCES.css().dataHeader());
      fmt.addStyleName(0, 2, Gerrit.RESOURCES.css().dataHeader());
      fmt.addStyleName(0, 3, Gerrit.RESOURCES.css().dataHeader());

      updateDeleteHandler =
          new ValueChangeHandler<Boolean>() {
            @Override
            public void onValueChange(ValueChangeEvent<Boolean> event) {
              updateDeleteButton();
            }
          };
    }

    private void addOneKey(GpgKeyInfo k) {
      int row = table.getRowCount();
      table.insertRow(row);
      applyDataRowStyle(row);

      CheckBox sel = new CheckBox();
      sel.addValueChangeHandler(updateDeleteHandler);
      table.setWidget(row, 0, sel);
      table.setWidget(row, 1, new CopyableLabel(k.id()));
      table.setText(row, 2, k.fingerprint());

      VerticalPanel userIds = new VerticalPanel();
      for (int i = 0; i < k.userIds().length(); i++) {
        userIds.add(new InlineLabel(k.userIds().get(i)));
      }
      table.setWidget(row, 3, userIds);

      FlexCellFormatter fmt = table.getFlexCellFormatter();
      fmt.addStyleName(row, 0, Gerrit.RESOURCES.css().iconCell());
      fmt.addStyleName(row, 1, Gerrit.RESOURCES.css().dataCell());
      fmt.addStyleName(row, 2, Gerrit.RESOURCES.css().dataCell());
      fmt.addStyleName(row, 3, Gerrit.RESOURCES.css().dataCell());

      setRowItem(row, k);
    }

    private void updateDeleteButton() {
      for (int row = 1; row < table.getRowCount(); row++) {
        if (isChecked(row)) {
          deleteKey.setEnabled(true);
          return;
        }
      }
      deleteKey.setEnabled(false);
    }

    private void deleteChecked() {
      deleteKey.setEnabled(false);
      List<String> toDelete = new ArrayList<>(table.getRowCount());
      for (int row = 1; row < table.getRowCount(); row++) {
        if (isChecked(row)) {
          toDelete.add(getRowItem(row).fingerprint());
        }
      }
      AccountApi.deleteGpgKeys(
          "self",
          toDelete,
          new GerritCallback<NativeMap<GpgKeyInfo>>() {
            @Override
            public void onSuccess(NativeMap<GpgKeyInfo> result) {
              refreshKeys();
            }

            @Override
            public void onFailure(Throwable caught) {
              deleteKey.setEnabled(true);
              super.onFailure(caught);
            }
          });
    }

    private boolean isChecked(int row) {
      return ((CheckBox) table.getWidget(row, 0)).getValue();
    }

    private void clear() {
      while (table.getRowCount() > 1) {
        table.removeRow(1);
      }
      for (int i = table.getRowCount() - 1; i >= 1; i++) {
        table.removeRow(i);
      }
    }
  }
}
