/*
 * Copyright 2000-2016 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 com.intellij.openapi.ui;

import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.keymap.Keymap;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.KeymapManagerListener;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.ui.update.Activatable;
import com.intellij.util.ui.update.UiNotifyConnector;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;

public final class ShadowAction implements Disposable {

  private final AnAction myAction;
  private AnAction myCopyFromAction;
  private final JComponent myComponent;

  private final KeymapManagerListener myKeymapManagerListener;

  private ShortcutSet myShortcutSet;
  private String myActionId;

  private final Keymap.Listener myKeymapListener;
  private Keymap myKeymap;

  private Presentation myPresentation;
  private final UiNotifyConnector myUiNotify;

  public ShadowAction(AnAction action, AnAction copyFromAction, JComponent component, Presentation presentation) {
    this(action, copyFromAction, component);
    myPresentation = presentation;
  }

  public ShadowAction(AnAction action, AnAction copyFromAction, JComponent component) {
    myAction = action;

    myCopyFromAction = copyFromAction;
    myComponent = component;
    myActionId = ActionManager.getInstance().getId(myCopyFromAction);

    myAction.getTemplatePresentation().copyFrom(copyFromAction.getTemplatePresentation());

    myKeymapListener = new Keymap.Listener() {
      @Override
      public void onShortcutChanged(final String actionId) {
        if (myActionId == null || actionId.equals(myActionId)) {
          rebound();
        }
      }
    };

    myKeymapManagerListener = new KeymapManagerListener() {
      @Override
      public void activeKeymapChanged(final Keymap keymap) {
        rebound();
      }
    };

    myUiNotify = new UiNotifyConnector(myComponent, new Activatable() {
      @Override
      public void showNotify() {
        _connect();
      }

      @Override
      public void hideNotify() {
        disconnect();
      }
    });
  }

  private void _connect() {
    disconnect();
    final KeymapManager mgr = getKeymapManager();
    if (mgr == null) return;


    mgr.addKeymapManagerListener(myKeymapManagerListener);
    rebound();
  }

  private void disconnect() {
    final KeymapManager mgr = getKeymapManager();
    if (mgr == null) return;


    mgr.removeKeymapManagerListener(myKeymapManagerListener);
    if (myKeymap != null) {
      myKeymap.removeShortcutChangeListener(myKeymapListener);
    }
  }

  private void rebound() {
    final KeymapManager mgr = getKeymapManager();
    if (mgr == null) return;

    myActionId = ActionManager.getInstance().getId(myCopyFromAction);
    if (myPresentation == null) {
      myAction.copyFrom(myCopyFromAction);
    } else {
      myAction.getTemplatePresentation().copyFrom(myPresentation);
      myAction.copyShortcutFrom(myCopyFromAction);
    }

    unregisterAll();

    myKeymap = mgr.getActiveKeymap();
    myKeymap.addShortcutChangeListener(myKeymapListener);

    if (myActionId == null) return;

    final Shortcut[] shortcuts = myKeymap.getShortcuts(myActionId);
    myShortcutSet = new CustomShortcutSet(shortcuts);
    myAction.registerCustomShortcutSet(myShortcutSet, myComponent);
  }

  private void unregisterAll() {
    if (myShortcutSet != null) {
      myAction.unregisterCustomShortcutSet(myComponent);
    }

    if (myKeymap != null) {
      myKeymap.removeShortcutChangeListener(myKeymapListener);
    }
  }


  @Override
  public void dispose() {
    unregisterAll();
    Disposer.dispose(myUiNotify);
    disconnect();
  }

  @Nullable
  private static KeymapManager getKeymapManager() {
    if (ApplicationManager.getApplication().isDisposed()) return null;
    return KeymapManager.getInstance();
  }

  public void reconnect(AnAction copyFromAction) {
    disconnect();
    myCopyFromAction = copyFromAction;
    _connect();
  }
}
