/*
 * Copyright 2000-2014 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.ui;

import com.intellij.icons.AllIcons;
import com.intellij.openapi.util.IconLoader;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
 * @author evgeny zakrevsky
 */
public class HideableDecorator {

  private final JPanel myPanel;

  private final TitledSeparator myTitledSeparator;
  private final boolean myAdjustWindow;

  private boolean myOn;
  private JComponent myContent;
  private Dimension myPreviousContentSize;

  public HideableDecorator(JPanel panel, String title, boolean adjustWindow) {
    this(panel, title, adjustWindow, null);
  }

  public HideableDecorator(JPanel panel, String title, boolean adjustWindow, @Nullable JComponent northEastComponent) {
    myPanel = panel;
    myAdjustWindow = adjustWindow;
    myTitledSeparator = new TitledSeparator(title, null) {
      @Override
      public void addNotify() {
        super.addNotify();
        registerMnemonic();
      }
    };
    JPanel northPanel = new JPanel(new BorderLayout());
    northPanel.add(myTitledSeparator, BorderLayout.CENTER);
    if (northEastComponent != null) {
      northPanel.add(northEastComponent, BorderLayout.EAST);
    }

    myPanel.add(northPanel, BorderLayout.NORTH);
    myTitledSeparator.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    updateIcon();
    myTitledSeparator.addMouseListener(new MouseAdapter() {
      @Override
      public void mouseReleased(@NotNull MouseEvent e) {
        if (myOn) {
          off();
        }
        else {
          on();
        }
      }
    });
  }

  private void updateIcon() {
    final Icon icon = myOn ? AllIcons.General.SplitDown : AllIcons.General.SplitRight;
    myTitledSeparator.getLabel().setIcon(icon);
    myTitledSeparator.getLabel().setDisabledIcon(IconLoader.getTransparentIcon(icon, 0.5f));
  }

  public void setContentComponent(@Nullable JComponent content) {
    if (content == null && myContent != null) {
      myPanel.remove(myContent);
    }
    myContent = content;
    if (myContent != null) {
      myContent.setVisible(myOn);
      myPanel.add(myContent, BorderLayout.CENTER);
    }
  }

  public void setOn(boolean on) {
    myOn = on;
    if (myOn) {
      on();
    }
    else {
      off();
    }
  }

  public boolean isExpanded() {
    return myOn;
  }

  public void setTitle(String title) {
    myTitledSeparator.setText(title);
  }

  public String getTitle() {
    return myTitledSeparator.getText();
  }

  protected void on() {
    myOn = true;
    updateIcon();
    myTitledSeparator.getLabel().setIconTextGap(5);
    if (myContent != null) {
      myContent.setVisible(true);
    }
    adjustWindow();
    myPanel.invalidate();
    myPanel.repaint();
  }

  protected void off() {
    myOn = false;
    updateIcon();
    if (myContent != null) {
      myContent.setVisible(false);
      myPreviousContentSize = myContent.getSize();
    }
    adjustWindow();
    myPanel.invalidate();
    myPanel.repaint();
  }

  private void adjustWindow() {
    if (!myAdjustWindow) return;
    final Window window = SwingUtilities.getWindowAncestor(myPanel);
    if (window == null) return;
    final Dimension size = window.getSize();
    final Dimension contentSize = myPreviousContentSize != null && myPreviousContentSize.width > 0 && myPreviousContentSize.height > 0
                                  ? myPreviousContentSize
                                  : myContent.getPreferredSize();
    final Dimension newSize;
    if (myOn) {
      newSize = new Dimension(Math.max(size.width, myContent.getSize().width), size.height + contentSize.height);
    }
    else {
      newSize = new Dimension(size.width, size.height - contentSize.height);
    }
    if (!newSize.equals(size)) {
      SwingUtilities.invokeLater(() -> {
        if (window.isShowing()) {
          window.setSize(newSize);
        }
      });
    }
  }

  public void setEnabled(boolean enabled) {
    myTitledSeparator.setEnabled(enabled);
    myContent.setEnabled(enabled);
  }

  private void registerMnemonic() {
    final int mnemonicIndex = UIUtil.getDisplayMnemonicIndex(getTitle());
    if (mnemonicIndex != -1) {
      myPanel.getActionMap().put("Collapse/Expand on mnemonic", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
          if (myOn) {
            off();
          }
          else {
            on();
          }
        }
      });
      final Character mnemonicCharacter = UIUtil.removeMnemonic(getTitle()).toUpperCase().charAt(mnemonicIndex);
      myPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
        .put(KeyStroke.getKeyStroke(mnemonicCharacter, InputEvent.ALT_MASK, false), "Collapse/Expand on mnemonic");
    }
  }
}
