// Copyright (C) 2009 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.gwtexpui.globalkey.client;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
import com.google.gwtexpui.safehtml.client.SafeHtml;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
import com.google.gwtexpui.user.client.PluginSafePopupPanel;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;


public class KeyHelpPopup extends PluginSafePopupPanel implements
    KeyPressHandler, KeyDownHandler {
  private final FocusPanel focus;

  public KeyHelpPopup() {
    super(true/* autohide */, true/* modal */);
    setStyleName(KeyResources.I.css().helpPopup());

    final Anchor closer = new Anchor(KeyConstants.I.closeButton());
    closer.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(final ClickEvent event) {
        hide();
      }
    });

    final Grid header = new Grid(1, 3);
    header.setStyleName(KeyResources.I.css().helpHeader());
    header.setText(0, 0, KeyConstants.I.keyboardShortcuts());
    header.setWidget(0, 2, closer);

    final CellFormatter fmt = header.getCellFormatter();
    fmt.addStyleName(0, 1, KeyResources.I.css().helpHeaderGlue());
    fmt.setHorizontalAlignment(0, 2, HasHorizontalAlignment.ALIGN_RIGHT);

    final Grid lists = new Grid(0, 7);
    lists.setStyleName(KeyResources.I.css().helpTable());
    populate(lists);
    lists.getCellFormatter().addStyleName(0, 3,
        KeyResources.I.css().helpTableGlue());

    final FlowPanel body = new FlowPanel();
    body.add(header);
    DOM.appendChild(body.getElement(), DOM.createElement("hr"));
    body.add(lists);

    focus = new FocusPanel(body);
    focus.getElement().getStyle().setProperty("outline", "0px");
    focus.getElement().setAttribute("hideFocus", "true");
    focus.addKeyPressHandler(this);
    focus.addKeyDownHandler(this);
    add(focus);
  }

  @Override
  public void setVisible(final boolean show) {
    super.setVisible(show);
    if (show) {
      focus.setFocus(true);
    }
  }

  @Override
  public void onKeyPress(final KeyPressEvent event) {
    if (KeyCommandSet.toMask(event) == ShowHelpCommand.INSTANCE.keyMask) {
      // Block the '?' key from triggering us to show right after
      // we just hide ourselves.
      //
      event.stopPropagation();
      event.preventDefault();
    }
    hide();
  }

  @Override
  public void onKeyDown(final KeyDownEvent event) {
    if (event.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) {
      hide();
    }
  }

  private void populate(final Grid lists) {
    int end[] = new int[5];
    int column = 0;
    for (final KeyCommandSet set : combinedSetsByName()) {
      int row = end[column];
      row = formatGroup(lists, row, column, set);
      end[column] = row;
      if (column == 0) {
        column = 4;
      } else {
        column = 0;
      }
    }
  }

  /**
   * @return an ordered collection of KeyCommandSet, combining sets which share
   *         the same name, so that each set name appears at most once.
   */
  private static Collection<KeyCommandSet> combinedSetsByName() {
    final LinkedHashMap<String, KeyCommandSet> byName =
        new LinkedHashMap<String, KeyCommandSet>();
    for (final KeyCommandSet set : GlobalKey.active.all.getSets()) {
      KeyCommandSet v = byName.get(set.getName());
      if (v == null) {
        v = new KeyCommandSet(set.getName());
        byName.put(v.getName(), v);
      }
      v.add(set);
    }
    return byName.values();
  }

  private int formatGroup(final Grid lists, int row, final int col,
      final KeyCommandSet set) {
    if (set.isEmpty()) {
      return row;
    }

    if (lists.getRowCount() < row + 1) {
      lists.resizeRows(row + 1);
    }
    lists.setText(row, col + 2, set.getName());
    lists.getCellFormatter().addStyleName(row, col + 2,
        KeyResources.I.css().helpGroup());
    row++;

    return formatKeys(lists, row, col, set, null);
  }

  private int formatKeys(final Grid lists, int row, final int col,
      final KeyCommandSet set, final SafeHtml prefix) {
    final CellFormatter fmt = lists.getCellFormatter();
    final int initialRow = row;
    final List<KeyCommand> keys = sort(set);
    if (lists.getRowCount() < row + keys.size()) {
      lists.resizeRows(row + keys.size());
    }
    FORMAT_KEYS: for (int i = 0; i < keys.size(); i++) {
      final KeyCommand k = keys.get(i);

      if (k instanceof CompoundKeyCommand) {
        final SafeHtmlBuilder b = new SafeHtmlBuilder();
        b.append(k.describeKeyStroke());
        row = formatKeys(lists, row, col, ((CompoundKeyCommand) k).getSet(), b);
        continue;
      }

      for (int prior = 0; prior < i; prior++) {
        if (KeyCommand.same(keys.get(prior), k)) {
          final int r = initialRow + prior;
          final SafeHtmlBuilder b = new SafeHtmlBuilder();
          b.append(SafeHtml.get(lists, r, col + 0));
          b.append(" ");
          b.append(KeyConstants.I.orOtherKey());
          b.append(" ");
          if (prefix != null) {
            b.append(prefix);
            b.append(" ");
            b.append(KeyConstants.I.thenOtherKey());
            b.append(" ");
          }
          b.append(k.describeKeyStroke());
          SafeHtml.set(lists, r, col + 0, b);
          continue FORMAT_KEYS;
        }
      }

      if (prefix != null) {
        final SafeHtmlBuilder b = new SafeHtmlBuilder();
        b.append(prefix);
        b.append(" ");
        b.append(KeyConstants.I.thenOtherKey());
        b.append(" ");
        b.append(k.describeKeyStroke());
        SafeHtml.set(lists, row, col + 0, b);
      } else {
        SafeHtml.set(lists, row, col + 0, k.describeKeyStroke());
      }
      lists.setText(row, col + 1, ":");
      lists.setText(row, col + 2, k.getHelpText());

      fmt.addStyleName(row, col + 0, KeyResources.I.css().helpKeyStroke());
      fmt.addStyleName(row, col + 1, KeyResources.I.css().helpSeparator());
      row++;
    }

    return row;
  }

  private List<KeyCommand> sort(final KeyCommandSet set) {
    final List<KeyCommand> keys = new ArrayList<KeyCommand>(set.getKeys());
    Collections.sort(keys, new Comparator<KeyCommand>() {
      @Override
      public int compare(KeyCommand arg0, KeyCommand arg1) {
        if (arg0.keyMask < arg1.keyMask) {
          return -1;
        } else if (arg0.keyMask > arg1.keyMask) {
          return 1;
        }
        return 0;
      }
    });
    return keys;
  }
}
