/*
 * Copyright 2003-2015 JetBrains s.r.o.
 *
 * 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 jetbrains.mps.nodeEditor.cells;

import jetbrains.mps.nodeEditor.EditorSettings;
import jetbrains.mps.nodeEditor.cells.contextAssistant.ContextAssistantController;
import jetbrains.mps.nodeEditor.cells.contextAssistant.ContextAssistantPanel;
import jetbrains.mps.nodeEditor.cells.contextAssistant.FocusUtil;
import jetbrains.mps.nodeEditor.cells.contextAssistant.WhatsThisActionItem;
import jetbrains.mps.openapi.editor.EditorComponent;
import jetbrains.mps.openapi.editor.EditorContext;
import jetbrains.mps.openapi.editor.assist.ContextAssistant;
import org.jetbrains.annotations.NotNull;
import jetbrains.mps.openapi.editor.style.StyleRegistry;
import org.jetbrains.mps.openapi.model.SNode;

import javax.swing.AbstractAction;
import javax.swing.JComponent;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

public class EditorCell_ContextAssistantComponent extends EditorCell_ComponentBase {
  private final ContextAssistantController myController;
  private final ContextAssistantPanel myPanel;
  private final TriggerRelayoutComponentListener myComponentListener = new TriggerRelayoutComponentListener();

  public EditorCell_ContextAssistantComponent(EditorContext editorContext, SNode node) {
    super(editorContext, node);
    myPanel = new ContextAssistantPanel();
    myPanel.setBackground(StyleRegistry.getInstance().getEditorBackground());
    myPanel.setEscapeAction(new RequestFocusInEditorAction(editorContext.getEditorComponent()));

    myController = new ContextAssistantController(editorContext, myPanel);
    myController.setHelpAction(new WhatsThisActionItem(myPanel.getComponent()));
    myController.hideMenu();
  }

  @NotNull
  @Override
  public JComponent getComponent() {
    return myPanel.getComponent();
  }

  @Override
  public int getAscent() {
    return myPanel.getBaseline();
  }

  @Override
  public void onAdd() {
    super.onAdd();
    getContext().getContextAssistantManager().register(myController);

    // Relayout the cell when the panel appears/disappears, mainly to ensure that the horizontal scrollbar appears or disappears as necessary.
    myPanel.getComponent().addComponentListener(myComponentListener);
  }

  @Override
  public void onRemove() {
    myPanel.getComponent().removeComponentListener(myComponentListener);
    getContext().getContextAssistantManager().unregister(myController);
    super.onRemove();
  }

  @Override
  public void moveTo(int x, int y) {
    super.moveTo(x, y);
    myPanel.setMaximumWidth(EditorSettings.getInstance().getVerticalBoundWidth() - x);
  }

  @Override
  public void setX(int x) {
    super.setX(x);
    myPanel.setMaximumWidth(EditorSettings.getInstance().getVerticalBoundWidth() - x);
  }

  @Override
  public void relayoutImpl() {
    JComponent component = getComponent();
    setWidth(component.isVisible() ? component.getWidth() : 0);
    setHeight(myPanel.getPreferredHeight() - 1); // do not count the bottom border, hence -1
  }

  @Override
  public void layoutComponent() {
    // Do nothing. Our cell size is updated via the component listener and the superclass behavior would cause endless back-and-forth resizing since
    // the component doesn't have a preferred size.
  }

  public ContextAssistant getContextAssistant() {
    return myController;
  }

  private static class RequestFocusInEditorAction extends AbstractAction {
    private final EditorComponent myEditorComponent;

    RequestFocusInEditorAction(EditorComponent editorComponent) {
      myEditorComponent = editorComponent;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      FocusUtil.requestFocus((Component) myEditorComponent, true);
    }
  }

  private class TriggerRelayoutComponentListener extends ComponentAdapter {
    @Override
    public void componentShown(ComponentEvent e) {
      triggerRelayout();
    }

    @Override
    public void componentHidden(ComponentEvent e) {
      triggerRelayout();
    }

    @Override
    public void componentResized(ComponentEvent e) {
      triggerRelayout();
    }

    private void triggerRelayout() {
      requestRelayout();
      jetbrains.mps.nodeEditor.EditorComponent editorComponent = (jetbrains.mps.nodeEditor.EditorComponent) getEditorComponent();
      editorComponent.relayout();
    }
  }
}
