/*
 * 作成日: 2007/06/07
 */
package net.sourceforge.swingx;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;


/**
 * 汎用的オプションペイン.
 * サイズ変更が可能.
 * 複数のボタンを設定可能.
 * あらかじめ代表的なボタンとその組み合わせを用意しているが、独自のボタンも指定できる。
 * @author Asan
 */
public class SxOptionPane extends JDialog {
	
	static final Icon ERROR_ICON 		= SxResource.getImageIcon("/javax/swing/plaf/metal/icons/Error.gif"); 
	static final Icon INFORMATION_ICON 	= SxResource.getImageIcon("/javax/swing/plaf/metal/icons/Inform.gif"); 
	static final Icon WARNING_ICON 		= SxResource.getImageIcon("/javax/swing/plaf/metal/icons/Warn.gif"); 
	static final Icon QUESTION_ICON 	= SxResource.getImageIcon("/javax/swing/plaf/metal/icons/Question.gif"); 

	public static final int PLAIN_MESSAGE = JOptionPane.PLAIN_MESSAGE;
	public static final int ERROR_MESSAGE = JOptionPane.ERROR_MESSAGE;
	public static final int INFORMATION_MESSAGE = JOptionPane.INFORMATION_MESSAGE;
	public static final int WARNING_MESSAGE = JOptionPane.WARNING_MESSAGE;
	public static final int QUESTION_MESSAGE = JOptionPane.QUESTION_MESSAGE;

    public static final int CLOSED = -1;
	public static final int OK = 1;
	public static final int CANCEL = 2;
    public static final int ABOUT = 4;
    public static final int RETRY = 8;
    public static final int IGNORE = 16;
	public static final int YES = 32;
	public static final int NO = 61;
    
	public static final int DEFAULT_OPTION = -1;
	public static final int YES_NO_OPTION = YES | NO;
	public static final int YES_NO_CANCEL_OPTION = YES | NO | CANCEL;
	public static final int OK_CANCEL_OPTION = OK | CANCEL;
	public static final int OK_ONLY_OPTION = OK;
	public static final int ABOUT_RETRY_IGNORE_OPTION = ABOUT | RETRY | IGNORE;
	public static final int RETRY_CANCEL_OPTION = RETRY | CANCEL;
	
	protected int returnValue = CLOSED;
	
	
	
	/** ダイアログの南に位置し、ボタンなどを格納する窓. */
	protected JPanel buttonPanel = new JPanel();

	/**
	 * アイコンは西に設定します。
	 * @param owner
	 * @param title
	 * @param messageType
	 * @param optionType	DEFAULT_OPTION, YES_NO_OPTION, YES_NO_CANCEL_OPTION,
	 *						OK_CANCEL_OPTION のいずれか 
	 */
	public SxOptionPane(JFrame owner, String title, int messageType, int optionType) {
		super(owner, title, true);
		init(messageType, optionType);
	}
	public SxOptionPane(JDialog owner, String title, int messageType, int optionType) {
		super(owner, title, true);
		init(messageType, optionType);
	}
	/**
	 * オプションペインを作成します。 
	 *
	 * @param owner	オーナーダイアログ。JDialogかJFrameである必要があります。
	 * @param title
	 */
	public SxOptionPane(JFrame owner, String title) {
		this(owner, title, PLAIN_MESSAGE, DEFAULT_OPTION);
	}
	private void init(int messageType, int optionType) {
		this.getContentPane().setLayout(new BorderLayout(10, 10));
		JPanel panel = (JPanel) this.getContentPane();
		panel.setBorder(new EmptyBorder(10, 10, 10, 10));
		this.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
		assert messageType == ERROR_MESSAGE ||
			messageType == INFORMATION_MESSAGE||
			messageType == WARNING_MESSAGE||
			messageType == QUESTION_MESSAGE||
			messageType == PLAIN_MESSAGE: messageType;
		assert optionType == DEFAULT_OPTION ||
			optionType == YES_NO_OPTION ||
			optionType == YES_NO_CANCEL_OPTION ||
			optionType == OK_CANCEL_OPTION ||
			optionType == OK_ONLY_OPTION ||
			optionType == ABOUT_RETRY_IGNORE_OPTION ||
			optionType == RETRY_CANCEL_OPTION: optionType;
		// アイコンを東に設定する
		switch (messageType) {
		case ERROR_MESSAGE:			setIcon(ERROR_ICON);		break;
		case INFORMATION_MESSAGE:	setIcon(INFORMATION_ICON);	break;
		case WARNING_MESSAGE:		setIcon(WARNING_ICON);		break;
		case QUESTION_MESSAGE:		setIcon(QUESTION_ICON);		break;
		case PLAIN_MESSAGE:			break;			// 何も設定しない
		default:					assert false: messageType;
		}
		KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
		switch (optionType) {
		case DEFAULT_OPTION:
			break;
		case YES_NO_OPTION:
			addOptionButton(YES, "はい(Y)", true);
			addOptionButton(NO, "いいえ(N)", false);
			break;
		case YES_NO_CANCEL_OPTION:
			addOptionButton(YES, "はい(Y)", true);
			addOptionButton(NO, "いいえ(N)", false);
			addOptionButton(CANCEL, "キャンセル", false);
			break;
		case OK_CANCEL_OPTION:
			addOptionButton(OK, "OK", true);
			addOptionButton(CANCEL, "キャンセル", false);
			break;
		case OK_ONLY_OPTION:
			addOptionButton(OK, "OK", true);
			break;
		case ABOUT_RETRY_IGNORE_OPTION:
			addOptionButton(ABOUT, "中断(B)", true);
			addOptionButton(RETRY, "再実行(R)", false);
			addOptionButton(IGNORE, "無視(I)", false);
			break;
		case RETRY_CANCEL_OPTION: 
			addOptionButton(RETRY, "再実行(R)", true);
			addOptionButton(CANCEL, "キャンセル", false);
			break;
		default:
			assert false: optionType;
		}
	}
	private void addOptionButton(int id, String name2, boolean isDefault) {
		class OptionPaneButtonAction extends AbstractAction {
			private int value;
			OptionPaneButtonAction(String name, int value, int mnemonic, KeyStroke stroke) {
				super(name);
				this.value = value;
				if (mnemonic != -1) {
					putValue(MNEMONIC_KEY, new Integer(mnemonic)); 
				}
				if (stroke != null) {
					putValue(ACCELERATOR_KEY, stroke);
					// ↑これではEscapeを押しても終了しない。Why?
//					JPanel panel = (JPanel) SxOptionPane.this.getContentPane();
//					panel.getInputMap().put(stroke, id);
//					panel.getActionMap().put(id, this);
				}
			}
			public void actionPerformed(ActionEvent event) {
				System.out.println(getName() + event);
				dispose();
				returnValue = value; 
			}
		}
		Action action = null;
		JButton button = null;
		switch (id) {
		case OK:
			action = new OptionPaneButtonAction("OK", OK, 'K', null);
			button = new JButton(action);
			button.setName("OK");
			addButton(button, isDefault);
			break;
		case CANCEL:
			action = new OptionPaneButtonAction("キャンセル", CANCEL, -1, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0));
			button = new JButton(action);
			button.setName("CANCEL");
			addButton(button, isDefault);
			break;
		case YES:
			action = new OptionPaneButtonAction("はい(Y)", YES, 'Y', null);
			button = new JButton(action);
			button.setName("YES");
			addButton(button, isDefault);
			break;
		case NO:
			action = new OptionPaneButtonAction("いいえ(N)", NO, 'N', null);
			button = new JButton(action);
			button.setName("NO");
			addButton(button, isDefault);
			break;
		case ABOUT:
			action = new OptionPaneButtonAction("中断(B)", ABOUT, 'B', null);
			button = new JButton(action);
			button.setName("ABOUT");
			addButton(button, isDefault);
			break;
		case RETRY:
			action = new OptionPaneButtonAction("再実行(R)", RETRY, 'R', null);
			button = new JButton(action);
			button.setName("RETRY");
			addButton(button, isDefault);
			break;
		case IGNORE:
			action = new OptionPaneButtonAction("無視(I)", IGNORE, 'I', null);
			button = new JButton(action);
			button.setName("IGNORE");
			addButton(button, isDefault);
			break;
		}
	}

	/**
	 * アイコンを西に設定します。
	 * @param icon	アイコン.
	 */
	public void setIcon(Icon icon) {
		// TODO:アイコンを中央ではなく上にできないか？
		this.getContentPane().add(new JLabel(icon), BorderLayout.WEST); 
	}
	public void setDefaultButton(JButton button) {
		this.getRootPane().setDefaultButton(button);
	}
	public void addButton(JButton button, boolean isDefault) {
		buttonPanel.add(button);
		if (isDefault) {
			setDefaultButton(button);
		}
	}
	public void addButton(JButton button) {
		this.addButton(button, false);
	}
	public JButton getButton(String value) {
		return (JButton) SxUtilities.getComponent(this, value);
	}


	
	public int getReturnValue() {
		return returnValue;
	}
	public static int showMessageDialog(Component parentComponent, 
			Object message, String title, int optionType, int messageType, Icon icon) {
		assert parentComponent != null;
		assert title != null;
		assert optionType == DEFAULT_OPTION ||
		optionType == YES_NO_OPTION ||
		optionType == YES_NO_CANCEL_OPTION ||
		optionType == OK_CANCEL_OPTION ||
		optionType == OK_ONLY_OPTION ||
		optionType == ABOUT_RETRY_IGNORE_OPTION ||
		optionType == RETRY_CANCEL_OPTION: optionType;
		assert messageType == ERROR_MESSAGE ||
		messageType == INFORMATION_MESSAGE||
		messageType == WARNING_MESSAGE||
		messageType == QUESTION_MESSAGE||
		messageType == PLAIN_MESSAGE: messageType;
		// 親ウィンドウを特定し、ダイアログを作成する。
		Component owner = SwingUtilities.getRoot(parentComponent);
		SxOptionPane pane = null;
		if (owner instanceof JFrame) {
			pane = new SxOptionPane((JFrame) owner, title, messageType, optionType);
		} else if (owner instanceof JDialog) {
			pane = new SxOptionPane((JDialog) owner, title, messageType, optionType);
		} else {
			assert false: parentComponent;
		}
		// アイコン、メッセージを設定
		if (icon != null) pane.setIcon(icon);
		if (message instanceof JComponent) {
			pane.getContentPane().add((JComponent) message, BorderLayout.CENTER);
		} else {
			pane.getContentPane().add(new JLabel(message.toString()), BorderLayout.CENTER);
		}
		// 表示
		pane.pack();
		pane.setLocationRelativeTo(owner);
		pane.setVisible(true);
		// 戻り値を返す。
		return pane.getReturnValue();
	}

	
}
