/* CVS: $Id: UserInterface.java,v 1.43 2001/03/17 14:57:16 gvijf Exp $ */

package gui;

import java.net.URL;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.util.*;
import java.util.ArrayList;
import java.util.Locale;
import java.io.IOException;
import java.io.FileNotFoundException;

import evolution.WorldController;
import evolution.InfoList;
import evolution.SystemMessage;

/**
 * A user interface for the game evolution.
 */
public class UserInterface extends JFrame {
    /**
     * Creates a new form UserInterface.
     */
    public UserInterface() {
        super(TITLE);
        init();
        show();
    }

    /** 
     * This method is called from within the constructor to initialize 
     * the form. 
     */
    private void init() {
        initEvolMenuBar();
        addWindowListener(
            new WindowAdapter() {
                public void windowClosing(WindowEvent evt) {
                    exitWindowEvent(evt);
                }
            });
        setSize(WIDTH, HEIGHT);
	shapesIconList = new ArrayList();
    }

    /**
     * This method initializes the menu bar of the evolution game with only 
     * a create menu. 
     */
    private void initEvolMenuBar() {
        evolMenuBar = new JMenuBar();
        initGameMenu();
        setJMenuBar(evolMenuBar);
    }

    /** 
     * Create a game menu for the evolution game. 
     */
    private void initGameMenu() {
        gameMenu = new JMenu("Game");
        newGame = new JMenuItem("New Game");
	URL url = ClassLoader.getSystemResource(menuIconPath + "pause.gif");
        pauseGameMenuIcon = new ImageIcon(url);
        pauseGame = new JMenuItem("Pause", pauseGameMenuIcon);
	url = ClassLoader.getSystemResource(menuIconPath + "continue.gif");
        continueGameMenuIcon = new ImageIcon(url);
        continueGame = new JMenuItem("Continue", continueGameMenuIcon);
        exitGame = new JMenuItem("Exit");
        pauseGame.setEnabled(false);
        continueGame.setEnabled(false);
        newGame.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    newGameActionPerformed(evt);
                }
            });
        pauseGame.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    pauseGameActionPerformed(evt);
                }
            });
        continueGame.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    continueGameActionPerformed(evt);
                }
            });
        exitGame.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    exitActionPerformed(evt);
                }
            });
        gameMenu.add(newGame);
        gameMenu.add(pauseGame);
        gameMenu.add(continueGame);
        gameMenu.add(exitGame);
        evolMenuBar.add(gameMenu);
    }

    /**
     * Create a new world for this game. The controller world will take care of
     * all the necessary events off this game.
     */
    private void createWorldController() throws FileNotFoundException, IOException {
        worldController = new WorldController("resources/evolution.prop", GAMEBOARDWIDTH, GAMEBOARDHEIGHT);
    }

    /**
      * Intiliaze a new menu for the creation of humans.
      */
    private void initHumanMenu() {
        humanMenu = new JMenu("Human");
		URL url = ClassLoader.getSystemResource(menuIconPath + "human.gif");
        createHumanMenuIcon = new ImageIcon(url);
        createHuman = new JMenuItem("Create a human", createHumanMenuIcon);
        createHuman.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    createHumanActionPerformed();
                }
            });
       	url = ClassLoader.getSystemResource(menuIconPath + "increase.gif");
        increaseRangeIcon = new ImageIcon(url);
		visionIncrease = new JMenuItem("Increase vision range", increaseRangeIcon);
		visionIncrease.addActionListener(
	    	new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    visionRangeActionPerformed(1);
                }
            });
        url = ClassLoader.getSystemResource(menuIconPath + "decrease.gif");
        decreaseRangeIcon = new ImageIcon(url);
		visionDecrease = new JMenuItem("Decrease vision range", decreaseRangeIcon);
		visionDecrease.addActionListener(
		    new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    visionRangeActionPerformed(-1);
                }
            });
        url = ClassLoader.getSystemResource(menuIconPath + "deselect.gif");
        deselectIcon = new ImageIcon(url);
		clearSelection = new JMenuItem("Deselect all humans", deselectIcon);
		clearSelection.addActionListener(
	    new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    clearSelectionActionPerformed();
                }
            });

        humanMenu.add(createHuman);
		humanMenu.add(visionIncrease);
		humanMenu.add(visionDecrease);
		humanMenu.add(clearSelection);
        evolMenuBar.add(humanMenu);
    }

    /**
     * Initialize a new action menu. All the actions of this game are 
     * automatically loaded in this menu.
     */
    private void initActionMenu() {
        actionMenu = new ActionsInfoMenu(worldController.getActionsInfo(), "Action", worldController, menuIconPath);
        actionMenu.add(new JSeparator());
        constructionsMenu = new ConstructionsInfoMenu(worldController.getConstructionsInfo(),
            "Create a construction", worldController, menuIconPath);
        actionMenu.add(constructionsMenu);
        evolMenuBar.add(actionMenu);
    }

    /**
     * Initialize the components of this user interface
     */
    private void initComponents() {
        initIconToolBar();
        initInfoPanel();
        initGameBoard();
    }

    /**
     * Initialize an icon tool bar with icons to continue and pause the game,
     * to create humans and all the possible actions of this game.
     */
    private void initIconToolBar() {
        iconToolBar = new JToolBar();
        continueGameIcon = new ImageIcon(ClassLoader.getSystemResource(iconPath + "continue.gif"), "Continue game");
        continueGameButton = new JButton(continueGameIcon);
        continueGameButton.setToolTipText("Continue game");
        continueGameButton.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    continueGameActionPerformed(evt);
                }
            });
        continueGameButton.setEnabled(false);
        iconToolBar.add(continueGameButton);
        pauseGameIcon = new ImageIcon(ClassLoader.getSystemResource(iconPath + "pause.gif"), "Pause game");
        pauseGameButton = new JButton(pauseGameIcon);
        continueGameButton.setToolTipText("Pause game");
        pauseGameButton.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    pauseGameActionPerformed(evt);
                }
            });
        iconToolBar.add(pauseGameButton);
        iconToolBar.add(
            new JToolBar.Separator());
        humanIcon = new ImageIcon(ClassLoader.getSystemResource(iconPath + "human.gif"), "Create a human");
        humanButton = new JButton(humanIcon);
        humanButton.setToolTipText("Create a human");
        humanButton.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    createHumanActionPerformed();
                }
            });
        iconToolBar.add(humanButton);
        iconToolBar.add(
            new JToolBar.Separator());
        addToolBarIcons(worldController.getActionsInfo(), "Perform the action ", true);
	addToolBarIcons(worldController.getConstructionsInfo(), "Create a ", false);
    }

    /**
     * Add icons from an info list to the icon toolbar of this user interface.
     */
    private void addToolBarIcons(InfoList infoList, String added, boolean isActions) {
        while (infoList.next()) {
            URL url = ClassLoader.getSystemResource(iconPath + infoList.getName() + ".gif");
            if (url != null) {
                ImageIcon icon = new ImageIcon(url);
                JButton button = new JButton(icon);
                button.setToolTipText(added +
                   infoList.getName().toLowerCase(Locale.US));
                button.setActionCommand(infoList.getName());
                if (isActions) {
                    button.addActionListener(
                        new ActionListener() {
                            public void actionPerformed(ActionEvent evt) {
                                String actionCommand = evt.getActionCommand();
                                selectActionPerformed(actionCommand);
                            }
                        });
                } else {
                    button.addActionListener(
                        new ActionListener() {
                            public void actionPerformed(ActionEvent evt) {
                                String constructionName = evt.getActionCommand();
                                constructionActionPerformed(constructionName);
                            }
                        });
                }
                iconToolBar.add(button);
            } else {
                SystemMessage.message("Can't find the the toolbar icon: " + infoList.getName() + ".gif");
            }
        }
        iconToolBar.add(
            new JToolBar.Separator());
    }

    private void addShapeIcons(java.util.List shapes) {
        Iterator it = shapes.iterator();
        while (it.hasNext()) {
            String shape = (String) it.next();
            URL url = ClassLoader.getSystemResource(iconPath + shape.replace(':', '_') + ".gif");
            if (url != null) {
                ImageIcon icon = new ImageIcon(url);
                JButton button = new JButton(icon);
                button.setToolTipText("Construction shape: "+ shape);
                button.setActionCommand(shape);
                button.addActionListener(
                    new ActionListener() {
                        public void actionPerformed(ActionEvent evt) {
                            String actionCommand = evt.getActionCommand();
                            selectShapePerformed(actionCommand);
                        }
                    });
                shapesIconList.add(button);
                iconToolBar.add(button);
            } else SystemMessage.message("Can't find the toolbar icon: " + shape.replace(':', '_') + ".gif");
        }
    }

    private void removeShapeIcons() {
	Iterator it = shapesIconList.iterator();
	while (it.hasNext()) {
	    JButton shapeButton = (JButton) it.next();
	    iconToolBar.remove(shapeButton);
	}
	shapesIconList.clear();
	iconToolBar.revalidate();
	iconToolBar.repaint();
    }

    /**
     * Perform an action with as name actionCommand. If there are no humans
     * selected of the action is not allowed on the selected square of land 
     * nothing will happen.
     */
    private void selectActionPerformed(String actionCommand) {
        worldController.selectActionType(actionCommand);
    }

    private void constructionActionPerformed(String constructionName) {
        worldController.selectConstructionType(constructionName);
	removeShapeIcons();
	addShapeIcons(worldController.getConstructionShapes(constructionName));
    }

    private void selectShapePerformed(String shape) {
	worldController.selectConstructionShape(shape);
	removeShapeIcons();
    }

    /** 
     * Initialize a panel for displaying information about the evolution game.
     */
    private void initInfoPanel() {
        infoPanel = new InfoPanelContainer(worldController, "Info", iconPath);
    }

    /** 
     * Init the scroll panel that hold a text area for displaying messages to 
     * the player.
     */
    private void createSystemOutput() {
	frameContainer = getContentPane();
	frameContainer.setLayout(
			new BorderLayout());
        systemOutput = new JScrollPane();
        outputTextArea = new InfoTextArea("Welcome to the game Evolution\n");
        systemOutput.setViewportView(outputTextArea);
        systemOutput.setBorder(
            new SoftBevelBorder(BevelBorder.RAISED));
	frameContainer.add(BorderLayout.SOUTH, systemOutput);
    }

    /** 
     * Init the game board of the evolution game and add it to a scroll panel.
     */
    private void initGameBoard() {
        gameBoard = new GameBoard(worldController);
        gameBoardSP = new JScrollPane(gameBoard);
    }

    /** Add all the components to this frame */
    private void layoutComponents() {
	frameContainer.add(BorderLayout.NORTH, iconToolBar);
	frameContainer.add(BorderLayout.EAST, infoPanel);
	frameContainer.add(BorderLayout.CENTER, gameBoardSP);
	addWindowListener(
			new WindowAdapter() {
			public void windowClosing(WindowEvent evt) {
			exitWindowEvent(evt);
			}
			});
	show();
    }

    /** 
     * Start a new game. A world is created and all the components of the 
     * user interface are layed out. 
     */
    private void newGameActionPerformed(java.awt.event.ActionEvent evt) {
        try {
    	    createSystemOutput();
            createWorldController();
            initHumanMenu();
            initActionMenu();
            setJMenuBar(evolMenuBar);
            initComponents();
            layoutComponents();
            worldController.startGame();
            newGame.setEnabled(false);
            pauseGame.setEnabled(true);
        }
        catch (Exception e) {
            e.printStackTrace();
            dialog = new MessageDialog(this, "Error", e.toString());
            dialog.show();
        }
    }

    /**
     * Continue the game.
     * @precondition the game must be pause mode.
     */
    private void continueGameActionPerformed(ActionEvent evt) {
        continueGame.setEnabled(false);
        pauseGame.setEnabled(true);
        continueGameButton.setEnabled(false);
        pauseGameButton.setEnabled(true);
        worldController.continueGame();
    }

    /**
     * Pause the game.
     * @precondition the game must be running.
     */
    private void pauseGameActionPerformed(ActionEvent evt) {
        continueGame.setEnabled(true);
        pauseGame.setEnabled(false);
        continueGameButton.setEnabled(true);
        pauseGameButton.setEnabled(false);
        worldController.pauseGame();
    }

    /** The main method off this game */
    public static void main(String[] args) {
        new UserInterface().show();
    }

    /** Toggle create human. */
    private void createHumanActionPerformed() {
        worldController.createHuman();
    }

    private void visionRangeActionPerformed(int value) {
	worldController.modifyVisionRange(value);
    }
    
    /**	Deselect all humans */
    private void clearSelectionActionPerformed() {
	worldController.clearSelection();
    }

    /** Exit the Application */
    private void exitActionPerformed(ActionEvent evt) {
        System.exit(0);
    }

    /** Exit the Application */
    private void exitWindowEvent(WindowEvent evt) {
        System.exit(0);
    }

    private static Container frameContainer;
    private static final int WIDTH = 800;
    private static final int HEIGHT = 600;
    private static final String TITLE = "Evolution";
    private static final int GAMEBOARDWIDTH = 12;
    private static int GAMEBOARDHEIGHT = 12;
    private String iconPath = "gui/icons/";
    private String menuIconPath = "gui/menuicons/";
    private MessageDialog dialog;
    /** the evolution menu bar */
    private JMenuBar evolMenuBar;
    /** the game menu */
    private JMenu gameMenu;
    private JMenuItem newGame;
    private JMenuItem pauseGame;
    private ImageIcon pauseGameMenuIcon;
    private JMenuItem continueGame;
    private ImageIcon continueGameMenuIcon;
    private JMenuItem exitGame;
    /** the human menu */
    private JMenu humanMenu;
    private JMenuItem createHuman;
    private JMenuItem visionIncrease;
    private JMenuItem visionDecrease;
    private JMenuItem clearSelection; 
    private ImageIcon createHumanMenuIcon;
    private ImageIcon increaseRangeIcon;
    private ImageIcon decreaseRangeIcon;
    private ImageIcon deselectIcon;
    /** the action menu */
    private ActionsInfoMenu actionMenu;
    /** the submenu of the action menu; create a construction */
    private ConstructionsInfoMenu constructionsMenu;
    private JMenuItem[] constructionTypes;
    /** a toolbar with icons */
    private JToolBar iconToolBar;
    private ImageIcon continueGameIcon;
    private JButton continueGameButton;
    private ImageIcon pauseGameIcon;
    private JButton pauseGameButton;
    private ImageIcon humanIcon;
    private JButton humanButton;
    private java.util.List shapesIconList; 
    /** a scroll panel for the game board */
    private JScrollPane gameBoardSP;
    private GameBoard gameBoard;
    /** a general info panel to hold the other info panels */
    private InfoPanelContainer infoPanel;
    /** a panel for displaying messages to the player */
    private JScrollPane systemOutput;
    private InfoTextArea outputTextArea;
    /** a boolean that indicates if the game is evolving */
    private boolean evolving;
    /** a connection to the controller world */
    private WorldController worldController;
}
