/*******************************************************************************
 * Copyright (c) 2001, 2008 Mathew A. Nelson and Robocode contributors
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://robocode.sourceforge.net/license/cpl-v10.html
 *
 * Contributors:
 *     Mathew A. Nelson
 *     - Initial API and implementation
 *     Matthew Reeder
 *     - Added keyboard mnemonics to buttons and tabs
 *     Flemming N. Larsen
 *     - Code cleanup
 *     - Replaced FileSpecificationVector with plain Vector
 *     - Changed the F5 key press for refreshing the list of available robots
 *       into 'modifier key' + R to comply with other OSes like e.g. Mac OS
 *     Robert D. Maupin
 *     - Replaced old collection types like Vector and Hashtable with
 *       synchronized List and HashMap
 *******************************************************************************/
package robocode.dialog;


import robocode.battle.BattleProperties;
import robocode.manager.RobocodeManager;
import static robocode.ui.ShortcutUtil.MENU_SHORTCUT_KEY_MASK;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.util.List;


/**
 * @author Mathew A. Nelson (original)
 * @author Matthew Reeder (contributor)
 * @author Flemming N. Larsen (contributor)
 * @author Robert D. Maupin (contributor)
 */
@SuppressWarnings("serial")
public class NewBattleDialog extends JDialog implements WizardListener {

	private final static int MAX_ROBOTS = 256; // 64;
	private final static int MIN_ROBOTS = 1;

	private final EventHandler eventHandler = new EventHandler();
	private JPanel newBattleDialogContentPane;
	private WizardTabbedPane tabbedPane;
	private NewBattleBattleFieldTab battleFieldTab;

	private final BattleProperties battleProperties;

	private NewBattleRulesTab rulesTab;
	private WizardController wizardController;

	private RobotSelectionPanel robotSelectionPanel;

	private final RobocodeManager manager;

	public NewBattleDialog(RobocodeManager manager, BattleProperties battleProperties) {
		super(manager.getWindowManager().getRobocodeFrame(), true);
		this.manager = manager;
		this.battleProperties = battleProperties;

		initialize();
	}

	public void cancelButtonActionPerformed() {
		dispose();
	}

	public void finishButtonActionPerformed() {
		if (robotSelectionPanel.getSelectedRobotsCount() > 24) {
			if (JOptionPane.showConfirmDialog(this,
					"Warning:  The battle you are about to start (" + robotSelectionPanel.getSelectedRobotsCount()
					+ " robots) " + " is very large and will consume a lot of CPU and memory.  Do you wish to proceed?",
					"Large Battle Warning",
					JOptionPane.YES_NO_OPTION,
					JOptionPane.WARNING_MESSAGE)
					== JOptionPane.NO_OPTION) {
				return;
			}
		}
		if (robotSelectionPanel.getSelectedRobotsCount() == 1) {
			if (JOptionPane.showConfirmDialog(this,
					"You have only selected one robot.  For normal battles you should select at least 2.\nDo you wish to proceed anyway?",
					"Just one robot?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE)
					== JOptionPane.NO_OPTION) {
				return;
			}
		}
		battleProperties.setSelectedRobots(robotSelectionPanel.getSelectedRobotsAsString());
		battleProperties.setBattlefieldWidth(getBattleFieldTab().getBattleFieldWidth());
		battleProperties.setBattlefieldHeight(getBattleFieldTab().getBattleFieldHeight());
		battleProperties.setNumRounds(getRobotSelectionPanel().getNumRounds());
		battleProperties.setGunCoolingRate(getRulesTab().getGunCoolingRate());
		battleProperties.setInactivityTime(getRulesTab().getInactivityTime());

		// Dispose this dialog before starting the battle due to pause/resume battle state
		dispose();

		// Start new battle after the dialog has been disposed and hence has called resumeBattle()
		manager.getBattleManager().startNewBattle(battleProperties, false);
	}

	/**
	 * Return the battleFieldTab
	 *
	 * @return JPanel
	 */
	private NewBattleBattleFieldTab getBattleFieldTab() {
		if (battleFieldTab == null) {
			battleFieldTab = new NewBattleBattleFieldTab();
		}
		return battleFieldTab;
	}

	/**
	 * Return the newBattleDialogContentPane
	 *
	 * @return JPanel
	 */
	private JPanel getNewBattleDialogContentPane() {
		if (newBattleDialogContentPane == null) {
			newBattleDialogContentPane = new JPanel();
			newBattleDialogContentPane.setLayout(new BorderLayout());
			newBattleDialogContentPane.add(getWizardController(), BorderLayout.SOUTH);
			newBattleDialogContentPane.add(getTabbedPane(), BorderLayout.CENTER);
			newBattleDialogContentPane.registerKeyboardAction(eventHandler, "Refresh",
					KeyStroke.getKeyStroke(KeyEvent.VK_R, MENU_SHORTCUT_KEY_MASK),
					JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
		}
		return newBattleDialogContentPane;
	}

	/**
	 * Return the rulesTab property value.
	 *
	 * @return robocode.dialog.NewBattleRulesTab
	 */
	private NewBattleRulesTab getRulesTab() {
		if (rulesTab == null) {
			rulesTab = new robocode.dialog.NewBattleRulesTab();
		}
		return rulesTab;
	}

	public List<robocode.repository.FileSpecification> getSelectedRobots() {
		return getRobotSelectionPanel().getSelectedRobots();
	}

	/**
	 * Initialize the class.
	 */
	private void initialize() {
		setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		setTitle("New Battle");
		setContentPane(getNewBattleDialogContentPane());
		addCancelByEscapeKey();

		battleProperties.setNumRounds(manager.getProperties().getNumberOfRounds());
		processBattleProperties();
	}

	private void addCancelByEscapeKey() {
		String CANCEL_ACTION_KEY = "CANCEL_ACTION_KEY";
		int noModifiers = 0;
		KeyStroke escapeKey = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, noModifiers, false);
		InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

		inputMap.put(escapeKey, CANCEL_ACTION_KEY);
		AbstractAction cancelAction = new AbstractAction() {
			public void actionPerformed(ActionEvent e) {
				cancelButtonActionPerformed();
			}
		};

		getRootPane().getActionMap().put(CANCEL_ACTION_KEY, cancelAction);
	}

	/**
	 * Return the wizardController
	 *
	 * @return JButton
	 */
	private WizardController getWizardController() {
		if (wizardController == null) {
			wizardController = getTabbedPane().getWizardController();
			wizardController.setFinishButtonTextAndMnemonic("Start Battle", 'S', 0);
			wizardController.setFocusOnEnabled(true);
		}
		return wizardController;
	}

	/**
	 * Return the Page property value.
	 *
	 * @return JPanel
	 */
	private RobotSelectionPanel getRobotSelectionPanel() {
		if (robotSelectionPanel == null) {
			String selectedRobots = "";

			if (battleProperties != null) {
				selectedRobots = battleProperties.getSelectedRobots();
			}
			robotSelectionPanel = new RobotSelectionPanel(manager, MIN_ROBOTS, MAX_ROBOTS, true,
					"Select robots for the battle", false, false, false, false, false,
					!manager.getProperties().getOptionsTeamShowTeamRobots(), selectedRobots);
		}
		return robotSelectionPanel;
	}

	/**
	 * Return the tabbedPane.
	 *
	 * @return JTabbedPane
	 */
	private WizardTabbedPane getTabbedPane() {
		if (tabbedPane == null) {
			tabbedPane = new WizardTabbedPane(this);
			tabbedPane.insertTab("Robots", null, getRobotSelectionPanel(), null, 0);
			tabbedPane.setMnemonicAt(0, KeyEvent.VK_R);
			tabbedPane.setDisplayedMnemonicIndexAt(0, 0);
			tabbedPane.insertTab("BattleField", null, getBattleFieldTab(), null, 1);
			tabbedPane.setMnemonicAt(1, KeyEvent.VK_F);
			tabbedPane.setDisplayedMnemonicIndexAt(1, 6);
			tabbedPane.insertTab("Rules", null, getRulesTab(), null, 2);
			tabbedPane.setMnemonicAt(2, KeyEvent.VK_U);
			tabbedPane.setDisplayedMnemonicIndexAt(2, 1);
		}
		return tabbedPane;
	}

	private void processBattleProperties() {
		if (battleProperties == null) {
			return;
		}
		getBattleFieldTab().setBattleFieldWidth(battleProperties.getBattlefieldWidth());
		getBattleFieldTab().setBattleFieldHeight(battleProperties.getBattlefieldHeight());
		getRobotSelectionPanel().setNumRounds(battleProperties.getNumRounds());

		getRulesTab().setGunCoolingRate(battleProperties.getGunCoolingRate());
		getRulesTab().setInactivityTime(battleProperties.getInactivityTime());
	}

	private class EventHandler extends WindowAdapter implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			if (e.getActionCommand().equals("Refresh")) {
				getRobotSelectionPanel().refreshRobotList(true);
			}
		}
	}
}
