/*
 * MegaMek -
 * Copyright (C) 2000,2001,2002,2003,2004,2005 Ben Mazur (bmazur@sev.org)
 *
 *  This program is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the Free
 *  Software Foundation; either version 2 of the License, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 *  for more details.
 */

package megamek.client.ui.AWT;

import java.awt.Button;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Vector;

import megamek.client.Client;
import megamek.client.event.BoardViewEvent;
import megamek.client.event.BoardViewListener;
import megamek.common.Aero;
import megamek.common.BattleArmor;
import megamek.common.Bay;
import megamek.common.BipedMech;
import megamek.common.Building;
import megamek.common.BuildingTarget;
import megamek.common.Compute;
import megamek.common.Coords;
import megamek.common.Entity;
import megamek.common.EntitySelector;
import megamek.common.GameTurn;
import megamek.common.IEntityMovementMode;
import megamek.common.IEntityMovementType;
import megamek.common.IGame;
import megamek.common.IHex;
import megamek.common.Infantry;
import megamek.common.LandAirMech;
import megamek.common.ManeuverType;
import megamek.common.Mech;
import megamek.common.Minefield;
import megamek.common.MiscType;
import megamek.common.Mounted;
import megamek.common.MovePath;
import megamek.common.MoveStep;
import megamek.common.PilotingRollData;
import megamek.common.Protomech;
import megamek.common.Report;
import megamek.common.Tank;
import megamek.common.TargetRoll;
import megamek.common.Targetable;
import megamek.common.TeleMissile;
import megamek.common.Terrains;
import megamek.common.ToHitData;
import megamek.common.VTOL;
import megamek.common.actions.ChargeAttackAction;
import megamek.common.actions.DfaAttackAction;
import megamek.common.actions.RamAttackAction;
import megamek.common.event.GameListener;
import megamek.common.event.GamePhaseChangeEvent;
import megamek.common.event.GameTurnChangeEvent;
import megamek.common.util.Distractable;
import megamek.common.util.DistractableAdapter;

public class MovementDisplay extends StatusBarPhaseDisplay implements
        ActionListener, DoneButtoned, KeyListener, GameListener,
        BoardViewListener, Distractable {
    /**
     * 
     */
    private static final long serialVersionUID = 9136822404087057673L;

    // Distraction implementation.
    private DistractableAdapter distracted = new DistractableAdapter();

    private static final int NUM_BUTTON_LAYOUTS = 4;

    public static final String MOVE_WALK = "moveWalk"; //$NON-NLS-1$
    public static final String MOVE_NEXT = "moveNext"; //$NON-NLS-1$
    public static final String MOVE_JUMP = "moveJump"; //$NON-NLS-1$
    public static final String MOVE_BACK_UP = "moveBackUp"; //$NON-NLS-1$
    public static final String MOVE_TURN = "moveTurn"; //$NON-NLS-1$
    public static final String MOVE_GET_UP = "moveGetUp"; //$NON-NLS-1$
    public static final String MOVE_CHARGE = "moveCharge"; //$NON-NLS-1$
    public static final String MOVE_DFA = "moveDFA"; //$NON-NLS-1$
    public static final String MOVE_GO_PRONE = "moveGoProne"; //$NON-NLS-1$
    public static final String MOVE_FLEE = "moveFlee"; //$NON-NLS-1$
    public static final String MOVE_EJECT = "moveEject"; //$NON-NLS-1$
    public static final String MOVE_LOAD = "moveLoad"; //$NON-NLS-1$
    public static final String MOVE_UNLOAD = "moveUnload"; //$NON-NLS-1$
    public static final String MOVE_UNJAM = "moveUnjam"; //$NON-NLS-1$
    public static final String MOVE_CLEAR = "moveClear"; //$NON-NLS-1$
    public static final String MOVE_CANCEL = "moveCancel"; //$NON-NLS-1$
    public static final String MOVE_RAISE_ELEVATION = "moveRaiseElevation"; //$NON-NLS-1$
    public static final String MOVE_LOWER_ELEVATION = "moveLowerElevation"; //$NON-NLS-1$
    public static final String MOVE_SEARCHLIGHT = "moveSearchlight"; //$NON-NLS-1$
    public static final String MOVE_LAY_MINE = "moveLayMine"; //$NON-NLS-1$
    public static final String MOVE_HULL_DOWN = "moveHullDown"; //$NON-NLS-1$
    public static final String MOVE_CLIMB_MODE = "moveClimbMode"; //$NON-NLS-1$
    public static final String MOVE_SWIM = "moveSwim"; //$NON-NLS-1$
    public static final String MOVE_DIG_IN = "moveDigIn"; //$NON-NLS-1$
    public static final String MOVE_FORTIFY = "moveFortify"; //$NON-NLS-1$
    public static final String MOVE_SHAKE_OFF = "moveShakeOff"; //$NON-NLS-1$
    public static final String MOVE_MODE_MECH = "moveModeMech"; //$NON-NLS-1$
    public static final String MOVE_MODE_AIRMECH = "moveModeAirmech"; //$NON-NLS-1$
    public static final String MOVE_MODE_AIRCRAFT = "moveModeAircraft"; //$NON-NLS-1$
    //Aero Movement
    public static final String      MOVE_ACC = "MoveAccelerate"; //$NON-NLS-1$
    public static final String      MOVE_DEC = "MoveDecelerate"; //$NON-NLS-1$
    public static final String      MOVE_EVADE = "MoveEvade"; //$NON-NLS-1$
    public static final String      MOVE_ACCN = "MoveAccNext"; //$NON-NLS-1$
    public static final String      MOVE_DECN = "MoveDecNext"; //$NON-NLS-1$
    public static final String      MOVE_ROLL = "MoveRoll"; //$NON-NLS-1$
    public static final String    MOVE_LAUNCH = "MoveLaunch"; //$NON-NLS-1$
    public static final String    MOVE_RECOVER = "MoveRecover"; //$NON-NLS-1$
    public static final String    MOVE_DUMP = "MoveDump"; //$NON-NLS-1$
    public static final String    MOVE_RAM = "MoveRam"; //$NON-NLS-1$
    public static final String    MOVE_HOVER = "MoveHover"; //$NON-NLS-1$
    public static final String    MOVE_MANEUVER = "MoveManeuver";
    //Aero Vector Movement
    public static final String    MOVE_TURN_LEFT = "MoveTurnLeft"; //$NON-NLS-1$
    public static final String    MOVE_TURN_RIGHT = "MoveTurnRight"; //$NON-NLS-1$
    public static final String    MOVE_THRUST = "MoveThrust"; //$NON-NLS-1$
    public static final String    MOVE_YAW = "MoveYaw"; //$NON-NLS-1$
    public static final String    MOVE_END_OVER = "MoveEndOver"; //$NON-NLS-1$

    // parent game
    public Client client;
    private ClientGUI clientgui;

    // buttons
    private Panel panButtons;

    private Button butWalk;
    private Button butJump;
    private Button butBackup;
    private Button butTurn;
    private Button butSwim;

    private Button butUp;
    private Button butDown;
    private Button butCharge;
    private Button butDfa;

    private Button butRAC;
    private Button butFlee;
    private Button butEject;

    private Button butLoad;
    private Button butUnload;
    private Button butSpace;

    private Button butClear;

    private Button butNext;
    private Button butDone;
    private Button butMore;

    private Button butRaise;
    private Button butLower;

    private Button butSearchlight;

    private Button butLayMine;

    private Button butHullDown;

    private Button butClimbMode;

    private Button butDigIn;
    private Button butFortify;

    private Button butShakeOff;
    
    private Button            butAcc;
    private Button            butDec;
    private Button              butEvade;
    private Button              butAccN;
    private Button              butDecN;
    private Button              butRoll;
    private Button              butLaunch;
    private Button              butRecover;
    private Button              butDump;
    private Button              butRam;
    private Button              butHover;
    private Button              butManeuver;
    
    private Button              butTurnLeft;
    private Button              butTurnRight;
    private Button              butThrust;
    private Button              butYaw;
    private Button              butEndOver;

    private int buttonLayout;

    // order of buttons for various entity types
    private ArrayList<Button> buttonsMech;
    private ArrayList<Button> buttonsTank;
    private ArrayList<Button> buttonsVtol;
    private ArrayList<Button> buttonsInf;
    private ArrayList<Button> buttonsAero;

    // let's keep track of what we're moving, too
    private int cen = Entity.NONE; // current entity number
    private MovePath cmd; // considering movement data

    // what "gear" is our mech in?
    private int gear;

    // is the shift key held?
    private boolean shiftheld;

    /**
     * A local copy of the current entity's loaded units.
     */
    private Vector<Entity> loadedUnits = null;

    public static final int GEAR_LAND = 0;
    public static final int GEAR_BACKUP = 1;
    public static final int GEAR_JUMP = 2;
    public static final int GEAR_CHARGE = 3;
    public static final int GEAR_DFA = 4;
    public static final int GEAR_TURN = 5;
    public static final int GEAR_SWIM = 6;
    public static final int GEAR_RAM = 7;
    public static final int GEAR_IMMEL = 8;
    public static final int GEAR_SPLIT_S = 9;

    /**
     * Creates and lays out a new movement phase display for the specified
     * client.
     */
    public MovementDisplay(ClientGUI clientgui) {
        this.clientgui = clientgui;
        this.client = clientgui.getClient();
        client.game.addGameListener(this);

        gear = MovementDisplay.GEAR_LAND;

        shiftheld = false;

        clientgui.getBoardView().addBoardViewListener(this);

        setupStatusBar(Messages
                .getString("MovementDisplay.waitingForMovementPhase")); //$NON-NLS-1$

        butClear = new Button(Messages.getString("MovementDisplay.butClear")); //$NON-NLS-1$
        butClear.addActionListener(this);
        butClear.setEnabled(false);
        butClear.setActionCommand(MOVE_CLEAR);
        butClear.addKeyListener(this);

        butWalk = new Button(Messages.getString("MovementDisplay.butWalk")); //$NON-NLS-1$
        butWalk.addActionListener(this);
        butWalk.setEnabled(false);
        butWalk.setActionCommand(MOVE_WALK);
        butWalk.addKeyListener(this);

        butJump = new Button(Messages.getString("MovementDisplay.butJump")); //$NON-NLS-1$
        butJump.addActionListener(this);
        butJump.setEnabled(false);
        butJump.setActionCommand(MOVE_JUMP);
        butJump.addKeyListener(this);

        butSwim = new Button(Messages.getString("MovementDisplay.butSwim")); //$NON-NLS-1$
        butSwim.addActionListener(this);
        butSwim.setEnabled(false);
        butSwim.setActionCommand(MOVE_SWIM);
        butSwim.addKeyListener(this);

        butBackup = new Button(Messages.getString("MovementDisplay.butBackup")); //$NON-NLS-1$
        butBackup.addActionListener(this);
        butBackup.setEnabled(false);
        butBackup.setActionCommand(MOVE_BACK_UP);
        butBackup.addKeyListener(this);

        butTurn = new Button(Messages.getString("MovementDisplay.butTurn")); //$NON-NLS-1$
        butTurn.addActionListener(this);
        butTurn.setEnabled(false);
        butTurn.setActionCommand(MOVE_TURN);
        butTurn.addKeyListener(this);

        butUp = new Button(Messages.getString("MovementDisplay.butUp")); //$NON-NLS-1$
        butUp.addActionListener(this);
        butUp.setEnabled(false);
        butUp.setActionCommand(MOVE_GET_UP);
        butUp.addKeyListener(this);

        butDown = new Button(Messages.getString("MovementDisplay.butDown")); //$NON-NLS-1$
        butDown.addActionListener(this);
        butDown.setEnabled(false);
        butDown.setActionCommand(MOVE_GO_PRONE);
        butDown.addKeyListener(this);

        butCharge = new Button(Messages.getString("MovementDisplay.butCharge")); //$NON-NLS-1$
        butCharge.addActionListener(this);
        butCharge.setEnabled(false);
        butCharge.setActionCommand(MOVE_CHARGE);
        butCharge.addKeyListener(this);

        butDfa = new Button(Messages.getString("MovementDisplay.butDfa")); //$NON-NLS-1$
        butDfa.addActionListener(this);
        butDfa.setEnabled(false);
        butDfa.setActionCommand(MOVE_DFA);
        butDfa.addKeyListener(this);

        butFlee = new Button(Messages.getString("MovementDisplay.butFlee")); //$NON-NLS-1$
        butFlee.addActionListener(this);
        butFlee.setEnabled(false);
        butFlee.setActionCommand(MOVE_FLEE);
        butFlee.addKeyListener(this);

        butEject = new Button(Messages.getString("MovementDisplay.butEject")); //$NON-NLS-1$
        butEject.addActionListener(this);
        butEject.setEnabled(false);
        butEject.setActionCommand(MOVE_EJECT);
        butEject.addKeyListener(this);

        butRAC = new Button(Messages.getString("MovementDisplay.butRAC")); //$NON-NLS-1$
        butRAC.addActionListener(this);
        butRAC.setEnabled(false);
        butRAC.setActionCommand(MOVE_UNJAM);
        butRAC.addKeyListener(this);

        butSearchlight = new Button(Messages
                .getString("MovementDisplay.butSearchlightOn")); //$NON-NLS-1$
        butSearchlight.addActionListener(this);
        butSearchlight.setEnabled(false);
        butSearchlight.setActionCommand(MOVE_SEARCHLIGHT);
        butSearchlight.addKeyListener(this);

        butMore = new Button(Messages.getString("MovementDisplay.butMore")); //$NON-NLS-1$
        butMore.addActionListener(this);
        butMore.setEnabled(false);
        butMore.addKeyListener(this);

        butNext = new Button(Messages.getString("MovementDisplay.butNext")); //$NON-NLS-1$
        butNext.addActionListener(this);
        butNext.setEnabled(false);
        butNext.setActionCommand(MOVE_NEXT);
        butNext.addKeyListener(this);

        butDone = new Button(Messages.getString("MovementDisplay.butDone")); //$NON-NLS-1$
        butDone.addActionListener(this);
        butDone.setEnabled(false);
        butDone.addKeyListener(this);

        butLoad = new Button(Messages.getString("MovementDisplay.butLoad")); //$NON-NLS-1$
        butLoad.addActionListener(this);
        butLoad.setEnabled(false);
        butLoad.setActionCommand(MOVE_LOAD);
        butLoad.addKeyListener(this);

        butUnload = new Button(Messages.getString("MovementDisplay.butUnload")); //$NON-NLS-1$
        butUnload.addActionListener(this);
        butUnload.setEnabled(false);
        butUnload.setActionCommand(MOVE_UNLOAD);
        butUnload.addKeyListener(this);

        butRaise = new Button(Messages.getString("MovementDisplay.butRaise")); //$NON-NLS-1$
        butRaise.addActionListener(this);
        butRaise.setEnabled(false);
        butRaise.setActionCommand(MOVE_RAISE_ELEVATION);
        butRaise.addKeyListener(this);

        butLower = new Button(Messages.getString("MovementDisplay.butLower")); //$NON-NLS-1$
        butLower.addActionListener(this);
        butLower.setEnabled(false);
        butLower.setActionCommand(MOVE_LOWER_ELEVATION);
        butLower.addKeyListener(this);

        butLayMine = new Button(Messages
                .getString("MovementDisplay.butLayMine")); //$NON-NLS-1$
        butLayMine.addActionListener(this);
        butLayMine.setEnabled(false);
        butLayMine.setActionCommand(MOVE_LAY_MINE);
        butLayMine.addKeyListener(this);

        butHullDown = new Button(Messages
                .getString("MovementDisplay.butHullDown")); //$NON-NLS-1$
        butHullDown.addActionListener(this);
        butHullDown.setEnabled(false);
        butHullDown.setActionCommand(MOVE_HULL_DOWN);
        butHullDown.addKeyListener(this);

        butClimbMode = new Button(Messages
                .getString("MovementDisplay.butClimbMode")); //$NON-NLS-1$
        butClimbMode.addActionListener(this);
        butClimbMode.setEnabled(false);
        butClimbMode.setActionCommand(MOVE_CLIMB_MODE);
        butClimbMode.addKeyListener(this);

        butDigIn = new Button(Messages.getString("MovementDisplay.butDigIn")); //$NON-NLS-1$
        butDigIn.addActionListener(this);
        butDigIn.setEnabled(false);
        butDigIn.setActionCommand(MOVE_DIG_IN);
        butDigIn.addKeyListener(this);

        butFortify = new Button(Messages
                .getString("MovementDisplay.butFortify")); //$NON-NLS-1$
        butFortify.addActionListener(this);
        butFortify.setEnabled(false);
        butFortify.setActionCommand(MOVE_FORTIFY);
        butFortify.addKeyListener(this);

        butShakeOff = new Button(Messages
                .getString("MovementDisplay.butShakeOff")); //$NON-NLS-1$
        butShakeOff.addActionListener(this);
        butShakeOff.setEnabled(false);
        butShakeOff.setActionCommand(MOVE_SHAKE_OFF);
        butShakeOff.addKeyListener(this);
        
        butAcc = new Button(Messages.getString("MovementDisplay.butAcc")); //$NON-NLS-1$
        butAcc.addActionListener(this);
        butAcc.setEnabled(false);
        butAcc.setActionCommand(MOVE_ACC);
        butAcc.addKeyListener(this);

        butDec = new Button(Messages.getString("MovementDisplay.butDec")); //$NON-NLS-1$
        butDec.addActionListener(this);
        butDec.setEnabled(false);
        butDec.setActionCommand(MOVE_DEC);
        butDec.addKeyListener(this);
        
        butAccN = new Button(Messages.getString("MovementDisplay.butAccN")); //$NON-NLS-1$
        butAccN.addActionListener(this);
        butAccN.setEnabled(false);
        butAccN.setActionCommand(MOVE_ACCN);
        butAccN.addKeyListener(this);

        butDecN = new Button(Messages.getString("MovementDisplay.butDecN")); //$NON-NLS-1$
        butDecN.addActionListener(this);
        butDecN.setEnabled(false);
        butDecN.setActionCommand(MOVE_DECN);
        butDecN.addKeyListener(this);
        
        butEvade = new Button(Messages.getString("MovementDisplay.butEvade")); //$NON-NLS-1$
        butEvade.addActionListener(this);
        butEvade.setEnabled(false);
        butEvade.setActionCommand(MOVE_EVADE);
        butEvade.addKeyListener(this);
        
        butRoll = new Button(Messages.getString("MovementDisplay.butRoll")); //$NON-NLS-1$
        butRoll.addActionListener(this);
        butRoll.setEnabled(false);
        butRoll.setActionCommand(MOVE_ROLL);
        butRoll.addKeyListener(this);
        
        butLaunch = new Button(Messages.getString("MovementDisplay.butLaunch")); //$NON-NLS-1$
        butLaunch.addActionListener(this);
        butLaunch.setEnabled(false);
        butLaunch.setActionCommand(MOVE_LAUNCH);
        butLaunch.addKeyListener(this);
        
        butRecover = new Button(Messages.getString("MovementDisplay.butRecover")); //$NON-NLS-1$
        butRecover.addActionListener(this);
        butRecover.setEnabled(false);
        butRecover.setActionCommand(MOVE_RECOVER);
        butRecover.addKeyListener(this);
        
        butDump = new Button(Messages.getString("MovementDisplay.butDump")); //$NON-NLS-1$
        butDump.addActionListener(this);
        butDump.setEnabled(false);
        butDump.setActionCommand(MOVE_DUMP);
        butDump.addKeyListener(this);
        
        butRam = new Button(Messages.getString("MovementDisplay.butRam")); //$NON-NLS-1$
        butRam.addActionListener(this);
        butRam.setEnabled(false);
        butRam.setActionCommand(MOVE_RAM);
        butRam.addKeyListener(this);
        
        butHover = new Button(Messages.getString("MovementDisplay.butHover")); //$NON-NLS-1$
        butHover.addActionListener(this);
        butHover.setEnabled(false);
        butHover.setActionCommand(MOVE_HOVER);
        butHover.addKeyListener(this);
        
        butManeuver = new Button(Messages.getString("MovementDisplay.butManeuver")); //$NON-NLS-1$
        butManeuver.addActionListener(this);
        butManeuver.setEnabled(false);
        butManeuver.setActionCommand(MOVE_MANEUVER);
        butManeuver.addKeyListener(this);
        
        butTurnLeft = new Button(Messages.getString("MovementDisplay.butTurnLeft")); //$NON-NLS-1$
        butTurnLeft.addActionListener(this);
        butTurnLeft.setEnabled(false);
        butTurnLeft.setActionCommand(MOVE_TURN_LEFT);
        butTurnLeft.addKeyListener(this);
        
        butTurnRight = new Button(Messages.getString("MovementDisplay.butTurnRight")); //$NON-NLS-1$
        butTurnRight.addActionListener(this);
        butTurnRight.setEnabled(false);
        butTurnRight.setActionCommand(MOVE_TURN_RIGHT);
        butTurnRight.addKeyListener(this);
        
        butThrust = new Button(Messages.getString("MovementDisplay.butThrust")); //$NON-NLS-1$
        butThrust.addActionListener(this);
        butThrust.setEnabled(false);
        butThrust.setActionCommand(MOVE_THRUST);
        butThrust.addKeyListener(this);
        
        butYaw = new Button(Messages.getString("MovementDisplay.butYaw")); //$NON-NLS-1$
        butYaw.addActionListener(this);
        butYaw.setEnabled(false);
        butYaw.setActionCommand(MOVE_YAW);
        butYaw.addKeyListener(this);
        
        butEndOver = new Button(Messages.getString("MovementDisplay.butEndOver")); //$NON-NLS-1$
        butEndOver.addActionListener(this);
        butEndOver.setEnabled(false);
        butEndOver.setActionCommand(MOVE_END_OVER);
        butEndOver.addKeyListener(this);

        butSpace = new Button(".");
        butSpace.setEnabled(false);
        butSpace.addKeyListener(this);

        // add buttons to the lists, except space, more & next
        buttonsMech = new ArrayList<Button>(22);
        buttonsMech.add(butWalk);
        buttonsMech.add(butJump);
        buttonsMech.add(butBackup);
        buttonsMech.add(butTurn);
        buttonsMech.add(butUp);
        buttonsMech.add(butDown);
        buttonsMech.add(butCharge);
        buttonsMech.add(butDfa);
        buttonsMech.add(butLoad);
        buttonsMech.add(butUnload);
        buttonsMech.add(butClimbMode);
        buttonsMech.add(butSearchlight);
        buttonsMech.add(butHullDown);
        buttonsMech.add(butSwim);
        buttonsMech.add(butEject);
        buttonsMech.add(butFlee);
        buttonsMech.add(butRAC);
        // these are last, they won't be used by mechs
        buttonsMech.add(butDigIn);
        buttonsMech.add(butFortify);
        buttonsMech.add(butLayMine);
        buttonsMech.add(butLower);
        buttonsMech.add(butRaise);
        buttonsMech.add(butShakeOff);

        buttonsTank = new ArrayList<Button>(22);
        buttonsTank.add(butWalk);
        buttonsTank.add(butBackup);
        buttonsTank.add(butTurn);
        buttonsTank.add(butLoad);
        buttonsTank.add(butUnload);
        buttonsTank.add(butCharge);
        buttonsTank.add(butClimbMode);
        buttonsTank.add(butSearchlight);
        buttonsTank.add(butHullDown);
        buttonsTank.add(butSwim);
        buttonsTank.add(butEject);
        buttonsTank.add(butFlee);
        buttonsTank.add(butRAC);
        buttonsTank.add(butLayMine);
        buttonsTank.add(butShakeOff);
        // these are last, they won't be used by tanks
        buttonsTank.add(butDfa);
        buttonsTank.add(butUp);
        buttonsTank.add(butDown);
        buttonsTank.add(butJump);
        buttonsTank.add(butDigIn);
        buttonsTank.add(butFortify);
        buttonsTank.add(butLower);
        buttonsTank.add(butRaise);

        buttonsVtol = new ArrayList<Button>(22);
        buttonsVtol.add(butWalk);
        buttonsVtol.add(butBackup);
        buttonsVtol.add(butLower);
        buttonsVtol.add(butRaise);
        buttonsVtol.add(butTurn);
        buttonsVtol.add(butLoad);
        buttonsVtol.add(butUnload);
        buttonsVtol.add(butSearchlight);
        buttonsVtol.add(butEject);
        buttonsVtol.add(butFlee);
        buttonsVtol.add(butRAC);
        buttonsVtol.add(butShakeOff);
        // these are last, they won't be used by vtol
        buttonsVtol.add(butHullDown);
        buttonsVtol.add(butLayMine);
        buttonsVtol.add(butSwim);
        buttonsVtol.add(butClimbMode);
        buttonsVtol.add(butCharge);
        buttonsVtol.add(butDfa);
        buttonsVtol.add(butUp);
        buttonsVtol.add(butDown);
        buttonsVtol.add(butJump);
        buttonsVtol.add(butDigIn);
        buttonsVtol.add(butFortify);

        buttonsInf = new ArrayList<Button>(22);
        buttonsInf.add(butWalk);
        buttonsInf.add(butJump);
        buttonsInf.add(butLower);
        buttonsInf.add(butRaise);
        buttonsInf.add(butTurn);
        buttonsInf.add(butClimbMode);
        buttonsInf.add(butSearchlight);
        buttonsInf.add(butEject);
        buttonsInf.add(butFlee);
        buttonsInf.add(butRAC);
        buttonsInf.add(butLayMine);
        buttonsInf.add(butSwim);
        buttonsInf.add(butDigIn);
        buttonsInf.add(butFortify);
        // these are last, they won't be used by infantry
        buttonsInf.add(butLoad);
        buttonsInf.add(butUnload);
        buttonsInf.add(butBackup);
        buttonsInf.add(butHullDown);
        buttonsInf.add(butCharge);
        buttonsInf.add(butDfa);
        buttonsInf.add(butUp);
        buttonsInf.add(butDown);
        buttonsInf.add(butShakeOff);

        buttonsAero = new ArrayList<Button>(22);
        if(!client.game.useVectorMove()) {
            buttonsAero.add(butWalk);
            buttonsAero.add(butAcc);
            buttonsAero.add(butDec);
            buttonsAero.add(butTurn);
            buttonsAero.add(butAccN);
            buttonsAero.add(butDecN);
            buttonsAero.add(butRoll);
            buttonsAero.add(butEvade);
            buttonsAero.add(butRam);
            buttonsAero.add(butLower);
            buttonsAero.add(butRaise);
            buttonsAero.add(butManeuver);
            buttonsAero.add(butEject);
            buttonsAero.add(butFlee);
            buttonsAero.add(butLaunch);
            buttonsAero.add(butRecover);
            buttonsAero.add(butHover);
            buttonsAero.add(butRAC);   
            buttonsAero.add(butDump);
            //not used
            buttonsAero.add(butFortify);
            buttonsAero.add(butHullDown);
            buttonsAero.add(butShakeOff);
        } else {
            buttonsAero.add(butThrust);
            buttonsAero.add(butTurnLeft);
            buttonsAero.add(butTurnRight);
            buttonsAero.add(butEvade);
            buttonsAero.add(butRoll);
            buttonsAero.add(butYaw);
            buttonsAero.add(butEndOver);
            buttonsAero.add(butRam);
            buttonsAero.add(butEject);
            buttonsAero.add(butFlee);
            buttonsAero.add(butLaunch);
            buttonsAero.add(butRecover);
            buttonsAero.add(butRAC);   
            buttonsAero.add(butDump);
            //not used
            buttonsAero.add(butDfa);
            buttonsAero.add(butUp);
            buttonsAero.add(butDown);
            buttonsAero.add(butJump);
            buttonsAero.add(butDigIn);
            buttonsAero.add(butFortify);
            buttonsAero.add(butHullDown);
            buttonsAero.add(butShakeOff);
        }
        //TODO: allow Aeros to taxi if on the ground
        
        // layout button grid
        panButtons = new Panel();
        buttonLayout = 0;
        setupButtonPanel();

        // layout screen
        GridBagLayout gridbag = new GridBagLayout();
        GridBagConstraints c = new GridBagConstraints();
        setLayout(gridbag);

        c.fill = GridBagConstraints.BOTH;
        c.weightx = 1.0;
        c.weighty = 1.0;
        c.insets = new Insets(1, 1, 1, 1);
        // c.gridwidth = GridBagConstraints.REMAINDER;
        // addBag(clientgui.bv, gridbag, c);

        // c.weightx = 1.0; c.weighty = 0;
        // c.gridwidth = 1;
        // addBag(client.cb.getComponent(), gridbag, c);

        c.gridwidth = GridBagConstraints.REMAINDER;
        c.weightx = 0.0;
        c.weighty = 0.0;
        addBag(panButtons, gridbag, c);

        c.weightx = 1.0;
        c.weighty = 0.0;
        c.gridwidth = GridBagConstraints.REMAINDER;
        addBag(panStatus, gridbag, c);

        clientgui.bv.addKeyListener(this);
        addKeyListener(this);

    }

    private void addBag(Component comp, GridBagLayout gridbag,
            GridBagConstraints c) {
        gridbag.setConstraints(comp, c);
        add(comp);
        comp.addKeyListener(this);
    }

    private void setupButtonPanel() {
        panButtons.removeAll();
        panButtons.setLayout(new GridLayout(0, 8));

        // choose button order based on entity type
        ArrayList<Button> buttonList = buttonsMech;
        final Entity ce = ce();
        if (ce != null) {
            if (ce instanceof Infantry)
                buttonList = buttonsInf;
            else if (ce instanceof VTOL)
                buttonList = buttonsVtol;
            else if (ce instanceof Tank)
                buttonList = buttonsTank;
            else if (ce instanceof Aero)
                buttonList = buttonsAero;
        }
        // should this layout be skipped? (if nothing enabled)
        boolean ok = false;
        while (!ok && buttonLayout != 0) {
            for (int i = buttonLayout * 6; i < (buttonLayout + 1) * 6
                    && i < buttonList.size(); i++) {
                if (buttonList.get(i).isEnabled()) {
                    ok = true;
                    break;
                }
            }
            if (!ok) {
                // skip as nothing was enabled
                buttonLayout++;
                if (buttonLayout * 6 >= buttonList.size())
                    buttonLayout = 0;
            }
        }

        panButtons.add(butNext);
        for (int i = buttonLayout * 6; i < (buttonLayout + 1) * 6
                && i < buttonList.size(); i++) {
            panButtons.add(buttonList.get(i));
        }
        panButtons.add(butMore);

        validate();
    }

    /**
     * Selects an entity, by number, for movement.
     */
    public synchronized void selectEntity(int en) {
        final Entity ce = client.game.getEntity(en);

        // hmm, sometimes this gets called when there's no ready entities?
        if (ce == null) {
            System.err
                    .println("MovementDisplay: tried to select non-existant entity: " + en); //$NON-NLS-1$
            return;
        }

        this.cen = en;
        clientgui.setSelectedEntityNum(en);

        clearAllMoves();
        updateButtons();
        // Update the menu bar.
        clientgui.getMenuBar().setEntity(ce);

        clientgui.getBoardView().highlight(ce.getPosition());
        clientgui.getBoardView().select(null);
        clientgui.getBoardView().cursor(null);
        clientgui.mechD.displayEntity(ce);
        clientgui.mechD.showPanel("movement"); //$NON-NLS-1$
        if (!clientgui.bv.isMovingUnits()) {
            clientgui.bv.centerOnHex(ce.getPosition());
        }
    }

    /**
     * Sets the buttons to their proper states
     */
    private void updateButtons() {
        final Entity ce = ce();
        final boolean isMech = (ce instanceof Mech);
        final boolean isInfantry = (ce instanceof Infantry);
        final boolean isProtomech = (ce instanceof Protomech);
        final boolean isAero      = (ce instanceof Aero);
        // ^-- I suppose these should really be methods, a-la
        // Entity.canCharge(), Entity.canDFA()...

        setWalkEnabled(!ce.isImmobile() && ce.getWalkMP() > 0 && !ce.isStuck());
        setJumpEnabled(!isAero && !ce.isImmobile() && ce.getJumpMP() > 0
                && !(ce.isStuck() && !ce.canUnstickByJumping()));
        setSwimEnabled(!isAero && !ce.isImmobile()
                && ce.hasUMU()
                && client.game.getBoard().getHex(ce.getPosition())
                        .containsTerrain(Terrains.WATER));
        setBackUpEnabled(butWalk.isEnabled() && !isAero);

        setChargeEnabled(ce.canCharge());
        setDFAEnabled(ce.canDFA());
        setRamEnabled(ce.canRam());

        if (isInfantry || isProtomech) {
            if (client.game.containsMinefield(ce.getPosition())) {
                setClearEnabled(true);
            } else {
                setClearEnabled(false);
            }
        } else {
            setClearEnabled(false);
        }

        if (ce.getMovementMode() == IEntityMovementMode.HYDROFOIL
                || ce.getMovementMode() == IEntityMovementMode.NAVAL
                || ce.getMovementMode() == IEntityMovementMode.SUBMARINE
                || ce.getMovementMode() == IEntityMovementMode.INF_UMU
                || ce.getMovementMode() == IEntityMovementMode.VTOL
                || ce.getMovementMode() == IEntityMovementMode.AIRMECH
                || ce.getMovementMode() == IEntityMovementMode.AREOSPACE
                || ce.getMovementMode() == IEntityMovementMode.BIPED_SWIM
                || ce.getMovementMode() == IEntityMovementMode.QUAD_SWIM) {
            butClimbMode.setEnabled(false);
        } else {
            butClimbMode.setEnabled(true);
        }

        if (isInfantry) {
            butDigIn.setEnabled(true);
            butFortify.setEnabled(true);
        } else {
            butDigIn.setEnabled(false);
            butFortify.setEnabled(false);
        }
        setTurnEnabled(!ce.isImmobile() && !ce.isStuck()
                && (ce.getWalkMP() > 0 || ce.getJumpMP() > 0));

        if (ce.isProne()) {
            setGetUpEnabled(!ce.isImmobile() && !ce.isStuck());
            setGoProneEnabled(false);
            setHullDownEnabled(false);
        } else if (ce.isHullDown()) {
            setGetUpEnabled(!ce.isImmobile() && !ce.isStuck());
            setGoProneEnabled(!ce.isImmobile() && isMech && !ce.isStuck());
            setHullDownEnabled(false);
        } else {
            setGetUpEnabled(false);
            setGoProneEnabled(!ce.isImmobile() && isMech && !ce.isStuck());
            setHullDownEnabled(ce.canGoHullDown());
        }
        updateProneButtons();
        updateRACButton();
        updateSearchlightButton();
        updateLoadButtons();
        updateElevationButtons();
        updateRecoveryButton();
        updateDumpButton();

        if(ce instanceof Aero) {
            butThrust.setEnabled(true);
            butYaw.setEnabled(true);
            butEndOver.setEnabled(true);
            butTurnLeft.setEnabled(true);
            butTurnRight.setEnabled(true);
            butEvade.setEnabled(true);  
            setEjectEnabled(true);       
            //no turning for spheroids in atmosphere
            if(((Aero)ce).isSpheroid() && client.game.getBoard().inAtmosphere()) {
                setTurnEnabled(false);
            }
        }
 
        updateSpeedButtons();
        updateThrustButton();
        updateRollButton();
        checkFuel();
        checkOOC();
        checkAtmosphere();
        updateFleeButton();
        updateLaunchButton();
        updateHoverButton();
        updateManeuverButton();
        
        if (isInfantry
                && ce.hasWorkingMisc(MiscType.F_TOOLS, MiscType.S_VIBROSHOVEL))
            butFortify.setEnabled(true);
        else
            butFortify.setEnabled(false);

        if (isInfantry
                && client.game.getOptions().booleanOption("maxtech_dig_in"))
            butDigIn.setEnabled(true);
        else
            butDigIn.setEnabled(false);

        butShakeOff.setEnabled(ce instanceof Tank
                && ce.getSwarmAttackerId() != Entity.NONE);

        setLayMineEnabled(ce.canLayMine());

        setFleeEnabled(ce.canFlee());
        if (client.game.getOptions().booleanOption("vehicles_can_eject")) { //$NON-NLS-1$
            setEjectEnabled((!isInfantry)
                    && !(isMech && ((Mech) ce).getCockpitType() == Mech.COCKPIT_TORSO_MOUNTED)
                    && ce.isActive());
        } else {
            setEjectEnabled(isMech
                    && ((Mech) ce).getCockpitType() != Mech.COCKPIT_TORSO_MOUNTED
                    && ce.isActive());
        }
        setupButtonPanel();

        // handle land air mech transformations
        updateTransformationButtons(ce);
    }

    /**
     * This funtcion is called to update the transformation buttons.
     * 
     * @param ce the current entity
     */
    private void updateTransformationButtons(Entity ce) {
        if (ce instanceof LandAirMech) {
            final LandAirMech lam = (LandAirMech) ce;

            setLAMmechModeEnabled(lam.canConvertToMech());
            setLAMairmechModeEnabled(lam.canConvertToAirmech());
            setLAMaircraftModeEnabled(lam.canConvertToAircraft());
        } else {
            setLAMmechModeEnabled(false);
            setLAMairmechModeEnabled(false);
            setLAMaircraftModeEnabled(false);
        }
    }

    /**
     * Enables relevant buttons and sets up for your turn.
     */
    private void beginMyTurn() {
        setStatusBarText(Messages.getString("MovementDisplay.its_your_turn")); //$NON-NLS-1$
        selectEntity(client.getFirstEntityNum());
        butDone.setLabel(Messages.getString("MovementDisplay.Done")); //$NON-NLS-1$
        butDone.setEnabled(true);
        setNextEnabled(true);
        butMore.setEnabled(true);
        if (!clientgui.bv.isMovingUnits()) {
            clientgui.setDisplayVisible(true);
        }
    }

    /**
     * Clears out old movement data and disables relevant buttons.
     */
    private synchronized void endMyTurn() {
        final Entity ce = ce();

        // end my turn, then.
        disableButtons();
        Entity next = client.game.getNextEntity(client.game.getTurnIndex());
        if (IGame.Phase.PHASE_MOVEMENT == client.game.getPhase() && null != next
                && null != ce && next.getOwnerId() != ce.getOwnerId()) {
            clientgui.setDisplayVisible(false);
        }
        cen = Entity.NONE;
        clientgui.getBoardView().select(null);
        clientgui.getBoardView().highlight(null);
        clientgui.getBoardView().cursor(null);
        clientgui.bv.clearMovementData();
    }

    /**
     * Disables all buttons in the interface
     */
    private void disableButtons() {
        setWalkEnabled(false);
        setJumpEnabled(false);
        setBackUpEnabled(false);
        setTurnEnabled(false);
        setFleeEnabled(false);
        setEjectEnabled(false);
        setUnjamEnabled(false);
        setSearchlightEnabled(false, false);
        setGetUpEnabled(false);
        setGoProneEnabled(false);
        setChargeEnabled(false);
        setDFAEnabled(false);
        setNextEnabled(false);
        butMore.setEnabled(false);
        butDone.setEnabled(false);
        setLoadEnabled(false);
        setUnloadEnabled(false);
        setClearEnabled(false);
        setHullDownEnabled(false);
        setSwimEnabled(false);
        setAccEnabled(false);
        setDecEnabled(false);
        setEvadeEnabled(false);
        setAccNEnabled(false);
        setDecNEnabled(false);
        setRollEnabled(false);
        setLaunchEnabled(false);
        setThrustEnabled(false);
        setYawEnabled(false);
        setEndOverEnabled(false);
        setTurnLeftEnabled(false);
        setTurnRightEnabled(false);
        setDumpEnabled(false);
        setRamEnabled(false);
        setHoverEnabled(false);
        setManeuverEnabled(false);
    }

    /**
     * Clears out the curently selected movement data and resets it.
     */
    private void clearAllMoves() {
        final Entity ce = ce();

        // switch back from swimming to normal mode.
        if (ce.getMovementMode() == IEntityMovementMode.BIPED_SWIM)
            ce.setMovementMode(IEntityMovementMode.BIPED);
        else if (ce.getMovementMode() == IEntityMovementMode.QUAD_SWIM)
            ce.setMovementMode(IEntityMovementMode.QUAD);

        // clear board cursors
        clientgui.getBoardView().select(null);
        clientgui.getBoardView().cursor(null);

        // create new current and considered paths
        cmd = new MovePath(client.game, ce);

        // set to "walk," or the equivalent
        gear = MovementDisplay.GEAR_LAND;

        // update some GUI elements
        clientgui.bv.clearMovementData();
        butDone.setLabel(Messages.getString("MovementDisplay.Done")); //$NON-NLS-1$
        updateProneButtons();
        updateRACButton();
        updateSearchlightButton();
        updateElevationButtons();
        updateFleeButton();
        updateLaunchButton();
        updateHoverButton();
        updateManeuverButton();

        loadedUnits = ce.getLoadedUnits();

        updateLoadButtons();
        updateElevationButtons();
        updateRecoveryButton();
        updateSpeedButtons();
        updateThrustButton();
        updateRollButton();
        checkFuel();
        checkOOC();
        checkAtmosphere();
    }

    private void removeLastStep() {
        cmd.removeLastStep();

        if (cmd.length() == 0) {
            clearAllMoves();
        } else {
            clientgui.bv.drawMovementData(ce(), cmd);

            // Set the button's label to "Done"
            // if the entire move is impossible.
            MovePath possible = cmd.clone();
            possible.clipToPossible();
            if (possible.length() == 0) {
                butDone.setLabel(Messages.getString("MovementDisplay.Done")); //$NON-NLS-1$
            }
        }
    }

    /**
     * Sends a data packet indicating the chosen movement.
     */
    private synchronized void moveTo(MovePath md) {
        
        final Entity ce = ce();
        boolean dontCheckPSR = false;
        if(ce instanceof Aero) {
            
            Aero a = (Aero)ce;
            
            //first check for stalling 
            if(client.game.getBoard().inAtmosphere() && !a.isVSTOL() && 
                    (!a.isSpheroid() && ((md == null && a.getCurrentVelocity() == 0) || 
                    (md != null && md.getFinalVelocity() == 0)))) {
                
                //add a stall to the movement path
                md.addStep(MovePath.STEP_STALL);
            }
            
            //should check to see if md is null. If so I need to check and see if the units
            //current velocity is zero
            if( md != null ) {
                
                boolean isRamming = false;
                if(md.getLastStep() != null && md.getLastStep().getType() == MovePath.STEP_RAM) {
                    isRamming = true;
                }
                
                //if using advanced movement then I need to add on movement steps
                //to get the vessel from point a to point b
                //if the unit is ramming then this is already done
                if(client.game.useVectorMove() && !isRamming) {
                    //get rid of any illegal moves or the rest won't be added
                    md.clipToPossible();
                    md = addSteps(md,ce);
                    
                }
                
                    
                //check to see if the unit is out of control. If so, then set up a new
                //move path for them.  
                //the same should be true if the unit is shutdown or the pilot is unconscious
                if(!client.game.useVectorMove() && 
                        (a.isOutControlTotal() || a.isShutDown() || a.getCrew().isUnconscious())) {

                    MovePath oldmd = md;
                    
                    dontCheckPSR = true;
                    md = new MovePath(client.game, ce);
                    int vel = a.getCurrentVelocity();
                    
                    
                    //need to check for stall here as well
                    if(vel == 0 && !a.isSpheroid() && client.game.getBoard().inAtmosphere()
                            && !a.isVSTOL()) {
                        //add a stall to the movement path
                        md.addStep(MovePath.STEP_STALL);
                    }
                    
                    while(vel > 0) {
                        //check to see if the unit is currently on a border 
                        //and facing a direction that would indicate leaving the map
                        Coords position = a.getPosition();
                        int facing = a.getFacing();
                        MoveStep step = md.getLastStep();
                        if(step != null) {
                            position = step.getPosition();
                            facing = step.getFacing();
                        }
                        boolean evenx = (position.x % 2) == 0;
                        if(((position.x == 0 && (facing == 5 || facing==4)) || 
                             (position.x == client.game.getBoard().getWidth() - 1 && (facing == 1 || facing==2)) ||
                             (position.y == 0 && (facing == 1 || facing==5 || facing==0) && evenx) || 
                             (position.y == 0 && facing==0) || 
                             (position.y == client.game.getBoard().getHeight() - 1 && (facing == 2 || facing==3 || facing==4) && !evenx) ||
                             (position.y == client.game.getBoard().getHeight() - 1 && facing==3))) {
                            //then this birdie go bye-bye
                            //set the conditions for removal
                             md.addStep(MovePath.STEP_OFF);
                             vel = 0;
                        
                        } else {
                            
                            if(a.isRandomMove()) {
                                int roll = Compute.d6(1);
                                switch (roll) {
                                case 1:
                                    md.addStep(MovePath.STEP_FORWARDS);
                                    md.addStep(MovePath.STEP_TURN_LEFT);
                                    md.addStep(MovePath.STEP_TURN_LEFT);
                                case 2:
                                    md.addStep(MovePath.STEP_FORWARDS);
                                    md.addStep(MovePath.STEP_TURN_LEFT);
                                case 3:
                                case 4:
                                    md.addStep(MovePath.STEP_FORWARDS);
                                case 5:
                                    md.addStep(MovePath.STEP_FORWARDS);
                                    md.addStep(MovePath.STEP_TURN_RIGHT);
                                case 6:
                                    md.addStep(MovePath.STEP_FORWARDS);
                                    md.addStep(MovePath.STEP_TURN_RIGHT);
                                    md.addStep(MovePath.STEP_TURN_RIGHT);
                                }
                            } else {
                                md.addStep(MovePath.STEP_FORWARDS);
                            }
                            
                            vel--;
                        }
                        
                    }
                
                    //check to see if old movement path contained a launch and 
                    //we are still on the board
                    if(oldmd.contains(MovePath.STEP_LAUNCH) && !md.contains(MovePath.STEP_OFF)) {
                        //since launches have to be the last step
                        MoveStep lastStep = oldmd.getLastStep();
                        if(lastStep.getType() == MovePath.STEP_LAUNCH)
                            md.addStep(lastStep.getType(),lastStep.getLaunched());
                    }
                    
                } else {
                
                    //I think this should be ok now
                    md.clipToPossible();
                    //check to see if velocity left is zero
                    MoveStep step = md.getLastStep();
                    if( step != null ) {
                        if(step.getVelocityLeft() > 0 && !client.game.useVectorMove() && step.getType() != MovePath.STEP_FLEE) {
                            //pop up some dialog telling the unit that it did not spend enough 
                            String title = Messages.getString("MovementDisplay.VelocityLeft.title"); //$NON-NLS-1$
                            String body = Messages.getString("MovementDisplay.VelocityLeft.message"); //$NON-NLS-1$
                            clientgui.doAlertDialog(title, body);
                            return;
                        }
                    } else {
                        //if the step is null then the unit didn't move. Make sure velocity is zero
                        if(a.getCurrentVelocity() > 0 && !client.game.useVectorMove()) {
                            //pop up some dialog telling the unit that it did not spend enough 
                            String title = Messages.getString("MovementDisplay.VelocityLeft.title"); //$NON-NLS-1$
                            String body = Messages.getString("MovementDisplay.VelocityLeft.message"); //$NON-NLS-1$
                            clientgui.doAlertDialog(title, body);
                            return;
                        }
                    }
                }
                
                //check for G-forces (not for vectored movement)
                String check = doThrustCheck(md);
                if (!client.game.useVectorMove() && 
                        check.length() > 0 && GUIPreferences.getInstance().getNagForPSR()) {
                    ConfirmDialog nag = 
                        new ConfirmDialog(clientgui.frame,
                                          Messages.getString("MovementDisplay.areYouSure"),  //$NON-NLS-1$
                                          Messages.getString("MovementDisplay.ConfirmPilotingRoll")+ //$NON-NLS-1$
                                          check, true);
                    nag.setVisible(true);
                    if (nag.getAnswer()) {
                        // do they want to be bothered again?
                        if (!nag.getShowAgain()) {
                            GUIPreferences.getInstance().setNagForPSR(false);
                        }
                    } else {
                        return;
                    }
                }
            }
        }
        
        md.clipToPossible();
        if (md.length() == 0
                && GUIPreferences.getInstance().getNagForNoAction()) {
            // Hmm....no movement steps, comfirm this action
            String title = Messages
                    .getString("MovementDisplay.ConfirmNoMoveDlg.title"); //$NON-NLS-1$
            String body = Messages
                    .getString("MovementDisplay.ConfirmNoMoveDlg.message"); //$NON-NLS-1$
            ConfirmDialog response = clientgui.doYesNoBotherDialog(title, body);
            if (!response.getShowAgain()) {
                GUIPreferences.getInstance().setNagForNoAction(false);
            }
            if (!response.getAnswer()) {
                return;
            }
        }

        if (md.hasActiveMASC() && GUIPreferences.getInstance().getNagForMASC()) { // pop
                                                                                    // up
                                                                                    // are
                                                                                    // you
                                                                                    // sure
                                                                                    // dialog
            Mech m = (Mech) ce();
            ConfirmDialog nag = new ConfirmDialog(clientgui.frame,
                    Messages.getString("MovementDisplay.areYouSure"), //$NON-NLS-1$
                    Messages
                            .getString(
                                    "MovementDisplay.ConfirmMoveRoll", new Object[] { new Integer(m.getMASCTarget()) }), //$NON-NLS-1$
                    true);
            nag.setVisible(true);
            if (nag.getAnswer()) {
                // do they want to be bothered again?
                if (!nag.getShowAgain()) {
                    GUIPreferences.getInstance().setNagForMASC(false);
                }
            } else {
                return;
            }
        }

        String check = doPSRCheck(md);
        if (check.length() > 0 && GUIPreferences.getInstance().getNagForPSR() && !dontCheckPSR) {
            ConfirmDialog nag = new ConfirmDialog(clientgui.frame, Messages
                    .getString("MovementDisplay.areYouSure"), //$NON-NLS-1$
                    Messages.getString("MovementDisplay.ConfirmPilotingRoll") + //$NON-NLS-1$
                            check, true);
            nag.setVisible(true);
            if (nag.getAnswer()) {
                // do they want to be bothered again?
                if (!nag.getShowAgain()) {
                    GUIPreferences.getInstance().setNagForPSR(false);
                }
            } else {
                return;
            }
        }

        disableButtons();
        clientgui.bv.clearMovementData();
        if (ce().hasUMU() || ce() instanceof LandAirMech) {
            client.sendUpdateEntity(ce());
        }
        client.moveEntity(cen, md);
    }

    private String addNag(PilotingRollData rollTarget) {
        return Messages
                .getString(
                        "MovementDisplay.addNag", new Object[] { rollTarget.getValueAsString(), rollTarget.getDesc() });//$NON-NLS-1$
    }

    /**
     * Checks to see if piloting skill rolls are needed for the currently
     * selected movement. This code is basically a simplified version of
     * Server.processMovement(), except that it just reads information (no
     * writing). Note that MovePath.clipToPossible() is called though, which
     * changes the md object.
     */
    private String doPSRCheck(MovePath md) {

        StringBuffer nagReport = new StringBuffer();

        final Entity entity = ce();

        // okay, proceed with movement calculations
        Coords lastPos = entity.getPosition();
        Coords curPos = entity.getPosition();
        int curFacing = entity.getFacing();
        int distance = 0;
        int moveType = IEntityMovementType.MOVE_NONE;
        int overallMoveType = IEntityMovementType.MOVE_NONE;
        boolean firstStep;
        int prevFacing = curFacing;
        IHex prevHex = null;
        final boolean isInfantry = (entity instanceof Infantry);

        PilotingRollData rollTarget;

        // Compile the move
        md.clipToPossible();

        overallMoveType = md.getLastStepMovementType();

        // iterate through steps
        firstStep = true;
        /* Bug 754610: Revert fix for bug 702735. */
        MoveStep prevStep = null;
        for (final Enumeration<MoveStep> i = md.getSteps(); i.hasMoreElements();) {
            final MoveStep step = i.nextElement();
            boolean isPavementStep = step.isPavementStep();

            // stop for illegal movement
            if (step.getMovementType() == IEntityMovementType.MOVE_ILLEGAL) {
                break;
            }

            if(entity instanceof Aero) {
                //check for more than one roll
                Aero a = (Aero)entity;
                rollTarget = a.checkRolls(step);
                if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                    nagReport.append(addNag(rollTarget));
                }
                
                rollTarget = a.checkManeuver(step);
                if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                    nagReport.append(addNag(rollTarget));
                }
            }
            
            // check piloting skill for getting up
            rollTarget = entity.checkGetUp(step);
            if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                nagReport.append(addNag(rollTarget));
            }

            // set most step parameters
            moveType = step.getMovementType();
            distance = step.getDistance();

            // set last step parameters
            curPos = step.getPosition();
            curFacing = step.getFacing();

            final IHex curHex = client.game.getBoard().getHex(curPos);

            // Check for skid.
            rollTarget = entity.checkSkid(moveType, prevHex, overallMoveType,
                    prevStep, prevFacing, curFacing, lastPos, curPos,
                    isInfantry, distance);
            if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                // Have an entity-meaningful PSR message.
                nagReport.append(addNag(rollTarget));
            }

            // check if we've moved into rubble
            rollTarget = entity.checkRubbleMove(step, curHex, lastPos, curPos);
            if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                nagReport.append(addNag(rollTarget));
            }

            // check for crossing ice
            if (curHex.containsTerrain(Terrains.ICE)
                    && curHex.containsTerrain(Terrains.WATER)
                    && !(curPos.equals(lastPos)) && step.getElevation() == 0
                    && moveType != IEntityMovementType.MOVE_JUMP) {
                nagReport.append(Messages
                        .getString("MovementDisplay.IceMoving"));
            }

            // check if we've moved into water
            rollTarget = entity.checkWaterMove(step, curHex, lastPos, curPos,
                    isPavementStep);
            if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                nagReport.append(addNag(rollTarget));
            }

            // check for non-mech entering a fire
            if (curHex.containsTerrain(Terrains.FIRE)
                    && !(entity instanceof Mech) && step.getElevation() <= 1
                    && moveType != IEntityMovementType.MOVE_JUMP
                    && !(curPos.equals(lastPos))) {
                nagReport.append(Messages.getString(
                        "MovementDisplay.FireMoving",
                        new Object[] { new Integer(8) }));
            }

            // check for magma
            int level = curHex.terrainLevel(Terrains.MAGMA);
            if (level == 1 && step.getElevation() == 0
                    && moveType != IEntityMovementType.MOVE_JUMP
                    && !(curPos.equals(lastPos))) {
                nagReport.append(Messages
                        .getString("MovementDisplay.MagmaCrustMoving"));
            } else if (level == 2 && entity.getElevation() == 0
                    && moveType != IEntityMovementType.MOVE_JUMP
                    && entity.getMovementMode() != IEntityMovementMode.HOVER
                    && entity.getMovementMode() != IEntityMovementMode.WIGE
                    && !(curPos.equals(lastPos))) {
                nagReport.append(Messages
                        .getString("MovementDisplay.MagmaLiquidMoving"));
            }

            if (entity instanceof VTOL
                    || entity.getMovementMode() == IEntityMovementMode.HOVER
                    || entity.getMovementMode() == IEntityMovementMode.WIGE) {
                rollTarget = entity.checkSideSlip(moveType, prevHex,
                        overallMoveType, prevStep, prevFacing, curFacing,
                        lastPos, curPos, distance);
                if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                    nagReport.append(addNag(rollTarget));
                }
            }

            // check if we've moved into swamp
            rollTarget = entity.checkSwampMove(step, curHex, lastPos, curPos,
                    isPavementStep);
            if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                nagReport.append(addNag(rollTarget));
            }

            // check if we used more MPs than the Mech/Vehicle would have in
            // normal gravity
            if (!i.hasMoreElements() && !firstStep) {
                if ((entity instanceof Mech) || (entity instanceof VTOL)) {
                    if ((step.getMovementType() == IEntityMovementType.MOVE_WALK)
                            || (step.getMovementType() == IEntityMovementType.MOVE_VTOL_WALK)
                            || (step.getMovementType() == IEntityMovementType.MOVE_RUN)
                            || (step.getMovementType() == IEntityMovementType.MOVE_VTOL_RUN)) {
                        if (step.getMpUsed() > entity.getRunMP(false, false)) {
                            rollTarget = entity.checkMovedTooFast(step);
                            if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                                nagReport.append(addNag(rollTarget));
                            }
                        }
                    } else if (step.getMovementType() == IEntityMovementType.MOVE_JUMP) {
                        if (step.getMpUsed() > entity.getOriginalJumpMP()) {
                            rollTarget = entity.checkMovedTooFast(step);
                            if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                                nagReport.append(addNag(rollTarget));
                            }
                        }
                    }
                } else if (entity instanceof Tank) {
                    if ((step.getMovementType() == IEntityMovementType.MOVE_WALK)
                            || (step.getMovementType() == IEntityMovementType.MOVE_VTOL_WALK)
                            || (step.getMovementType() == IEntityMovementType.MOVE_RUN)
                            || (step.getMovementType() == IEntityMovementType.MOVE_VTOL_RUN)) {

                        // For Tanks, we need to check if the tank had more MPs
                        // because it was moving along a road
                        if (step.getMpUsed() > entity.getRunMP(false, false)
                                && !step.isOnlyPavement()) {
                            rollTarget = entity.checkMovedTooFast(step);
                            if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                                nagReport.append(addNag(rollTarget));
                            }
                        }
                        // If the tank was moving on a road, he got a +1 bonus.
                        // N.B. The Ask Precentor Martial forum said that a 4/6
                        // tank on a road can move 5/7, **not** 5/8.
                        else if (step.getMpUsed() > entity.getRunMP(false,
                                false) + 1) {
                            rollTarget = entity.checkMovedTooFast(step);
                            if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                                nagReport.append(addNag(rollTarget));
                            }
                        }
                    }
                }
            }

            // Handle non-infantry moving into a building.
            int buildingMove = entity.checkMovementInBuilding(step, prevStep,
                    curPos, lastPos);
            if (buildingMove > 0) {

                // Get the building being exited.
                Building bldgExited = null;
                if ((buildingMove & 1) == 1)
                    bldgExited = client.game.getBoard().getBuildingAt(lastPos);

                // Get the building being entered.
                Building bldgEntered = null;
                if ((buildingMove & 2) == 2)
                    bldgEntered = client.game.getBoard().getBuildingAt(curPos);

                if (bldgExited != null && bldgEntered != null
                        && !bldgExited.equals(bldgEntered)) {
                    // Exiting one building and entering another.
                    // Brave, aren't we?
                    rollTarget = entity.rollMovementInBuilding(bldgExited,
                            distance, "exiting");
                    nagReport.append(addNag(rollTarget));
                    rollTarget = entity.rollMovementInBuilding(bldgEntered,
                            distance, "entering");
                    nagReport.append(addNag(rollTarget));
                } else {
                    Building bldg;
                    if (bldgEntered == null) {
                        // Exiting a building.
                        bldg = bldgExited;
                    } else {
                        // Entering or moving within a building.
                        bldg = bldgEntered;
                    }
                    if (bldg != null) {
                        rollTarget = entity.rollMovementInBuilding(bldg,
                                distance, "");
                        nagReport.append(addNag(rollTarget));
                    }
                }
            }

            if (step.getType() == MovePath.STEP_GO_PRONE) {
                rollTarget = entity.checkDislodgeSwarmers(step);
                if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                    nagReport.append(addNag(rollTarget));
                }
            }

            if ((step.getType() == MovePath.STEP_BACKWARDS
                    || step.getType() == MovePath.STEP_LATERAL_LEFT_BACKWARDS || step
                    .getType() == MovePath.STEP_LATERAL_RIGHT_BACKWARDS)
                    && client.game.getBoard().getHex(lastPos).getElevation() != curHex
                            .getElevation() && !(entity instanceof VTOL)) {
                nagReport.append(Messages
                        .getString("MovementDisplay.BackWardsElevationChange"));
                nagReport.append(addNag(entity.getBasePilotingRoll()));
            }

            // update lastPos, prevStep, prevFacing & prevHex
            lastPos = new Coords(curPos);
            prevStep = step;
            /*
             * Bug 754610: Revert fix for bug 702735. if (prevHex != null &&
             * !curHex.equals(prevHex)) {
             */
            if (!curHex.equals(prevHex)) {
                prevFacing = curFacing;
            }
            prevHex = curHex;

            firstStep = false;
        }

        // running with destroyed hip or gyro needs a check
        rollTarget = entity.checkRunningWithDamage(overallMoveType);
        if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
            nagReport.append(addNag(rollTarget));
        }

        // but the danger isn't over yet! landing from a jump can be risky!
        if (overallMoveType == IEntityMovementType.MOVE_JUMP
                && !entity.isMakingDfa()) {
            // check for damaged criticals
            rollTarget = entity.checkLandingWithDamage();
            if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                nagReport.append(addNag(rollTarget));
            }
            // jumped into water?
            IHex hex = client.game.getBoard().getHex(curPos);
            int waterLevel = hex.terrainLevel(Terrains.WATER);
            if (hex.containsTerrain(Terrains.ICE) && waterLevel > 0) {
                nagReport.append(Messages
                        .getString("MovementDisplay.IceLanding"));
            } else if (!(prevStep.climbMode() && hex.containsTerrain(Terrains.BRIDGE))){
                rollTarget = entity.checkWaterMove(waterLevel);
                if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                    nagReport.append(addNag(rollTarget));
                }
            }
            
        }
        
        if(entity instanceof Aero) {
            //check to see if thrust exceeded SI
            Aero a = (Aero)entity;
            int thrust = md.getMpUsed();
            rollTarget = a.checkThrustSITotal(thrust);
            if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                nagReport.append(addNag(rollTarget));
            }
            
            //Atmospheric checks
            if(client.game.getBoard().inAtmosphere()) {
                //check to see if velocity is 2x thrust
                rollTarget = a.checkVelocityDouble(md.getFinalVelocity());
                if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                    nagReport.append(addNag(rollTarget));
                }
                
                //check to see if descended more than two hexes
                rollTarget = a.checkDown(md.getFinalNDown());
                if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                    nagReport.append(addNag(rollTarget));
                }
                
                //stalling out
                if(md.getFinalVelocity() == 0 && !a.isSpheroid() && client.game.getBoard().inAtmosphere() && !a.isVSTOL()) {
                    rollTarget = a.checkStall(md.getFinalVelocity());
                    nagReport.append(addNag(rollTarget));
                }
                
                //check for hovering
                rollTarget = a.checkHover(md);
                if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                    nagReport.append(addNag(rollTarget));
                }
                
                
            }     
        }

        return nagReport.toString();
    }
    
    /**
     * Checks to see if piloting skill rolls are needed for excessive use of thrust.  
     */
    private String doThrustCheck(MovePath md) {
        
        StringBuffer nagReport = new StringBuffer();

        final Entity entity = ce();
        
        Aero a = (Aero)entity;
        
        PilotingRollData rollTarget;
        
        //cycle through movement.  Collect thrust used until position changes.
        int thrustUsed = 0;
        int j = 0;
        for (final Enumeration<MoveStep> i = md.getSteps(); i.hasMoreElements();) {
            final MoveStep step = i.nextElement();
            
            j++;
            //how do I figure out last step?
            if( step.getDistance() == 0 && md.length() != j) {
                thrustUsed += step.getMp();
            } else {
                //if this was the last move and distance was zero, then add thrust
                if(step.getDistance() == 0 && md.length() == j) {
                    thrustUsed += step.getMp();
                }
                //then we moved to a new hex or the last step so check conditions
                //structural damage
                rollTarget = a.checkThrustSI(thrustUsed);
                if (rollTarget.getValue() != TargetRoll.CHECK_FALSE) {
                    nagReport.append(addNag(rollTarget));
                }
               
                //check for pilot damage
                int hits = entity.getCrew().getHits();
                int health = 6 - hits;
            
                if( thrustUsed > (2*health) ) {
                    int targetroll = 2 + (thrustUsed - 2 * health) + 2 * hits;
                    nagReport.append(Messages.getString("MovementDisplay.addNag", new Object[]{Integer.toString(targetroll), "Thrust exceeded twice pilot's health in single hex"}));
                }
            
                thrustUsed = 0;
            }
        }
        
        return nagReport.toString();
        
    }

    /**
     * Returns the current entity.
     */
    private synchronized Entity ce() {
        return client.game.getEntity(cen);
    }

    /**
     * Returns new MovePath for the currently selected movement type
     */
    private void currentMove(Coords dest) {
        if (shiftheld || gear == GEAR_TURN) {
            cmd.rotatePathfinder(cmd.getFinalCoords().direction(dest), false);
        } else if (gear == GEAR_LAND || gear == GEAR_JUMP) {
            cmd.findPathTo(dest, MovePath.STEP_FORWARDS);
        } else if (gear == GEAR_BACKUP) {
            cmd.findPathTo(dest, MovePath.STEP_BACKWARDS);
        } else if (gear == GEAR_CHARGE) {
            cmd.findPathTo(dest, MovePath.STEP_CHARGE);
        } else if (gear == GEAR_DFA) {
            cmd.findPathTo(dest, MovePath.STEP_DFA);
        } else if (gear == GEAR_SWIM) {
            cmd.findPathTo(dest, MovePath.STEP_SWIM);
        } else if (gear == GEAR_RAM) {
            cmd.findPathTo(dest, MovePath.STEP_FORWARDS);
        } else if (gear == GEAR_IMMEL) {
            cmd.addStep(MovePath.STEP_UP, true, true);
            cmd.addStep(MovePath.STEP_UP, true, true);
            cmd.addStep(MovePath.STEP_DEC, true, true);
            cmd.addStep(MovePath.STEP_DEC, true, true);
            cmd.rotatePathfinder(cmd.getFinalCoords().direction(dest), true);
            gear = GEAR_LAND;
        } else if (gear == GEAR_SPLIT_S) {
            cmd.addStep(MovePath.STEP_DOWN, true, true);
            cmd.addStep(MovePath.STEP_DOWN, true, true);
            cmd.addStep(MovePath.STEP_ACC, true, true);
            cmd.rotatePathfinder(cmd.getFinalCoords().direction(dest), true);
            gear = GEAR_LAND;
        }
    }

    //
    // BoardListener
    //
    public synchronized void hexMoused(BoardViewEvent b) {
        final Entity ce = ce();

        // Are we ignoring events?
        if (this.isIgnoringEvents()) {
            return;
        }
        
        //don't make a movement path for aeros if advanced movement is on
        boolean nopath = ce instanceof Aero && client.game.useVectorMove();

        // ignore buttons other than 1
        if (!client.isMyTurn()
                || (b.getModifiers() & InputEvent.BUTTON1_MASK) == 0) {
            return;
        }
        // control pressed means a line of sight check.
        // added ALT_MASK by kenn
        if ((b.getModifiers() & InputEvent.CTRL_MASK) != 0
                || (b.getModifiers() & InputEvent.ALT_MASK) != 0) {
            return;
        }
        // check for shifty goodness
        if (shiftheld != ((b.getModifiers() & InputEvent.SHIFT_MASK) != 0)) {
            shiftheld = (b.getModifiers() & InputEvent.SHIFT_MASK) != 0;
        }

        if (b.getType() == BoardViewEvent.BOARD_HEX_DRAGGED && !nopath) {
            if (!b.getCoords().equals(clientgui.getBoardView().getLastCursor())
                    || shiftheld || gear == MovementDisplay.GEAR_TURN) {
                clientgui.getBoardView().cursor(b.getCoords());

                // either turn or move
                if (ce != null) {
                    currentMove(b.getCoords());
                    clientgui.bv.drawMovementData(ce, cmd);
                }
            }
        } else if (b.getType() == BoardViewEvent.BOARD_HEX_CLICKED) {

            Coords moveto = b.getCoords();
            clientgui.bv.drawMovementData(ce, cmd);

            clientgui.getBoardView().select(b.getCoords());

            if (shiftheld || gear == MovementDisplay.GEAR_TURN) {
                butDone.setLabel(Messages.getString("MovementDisplay.Move")); //$NON-NLS-1$

                // Set the button's label to "Done"
                // if the entire move is impossible.
                MovePath possible = cmd.clone();
                possible.clipToPossible();
                if (possible.length() == 0) {
                    butDone
                            .setLabel(Messages
                                    .getString("MovementDisplay.Done")); //$NON-NLS-1$
                }
                return;
            }
            
            if(gear == MovementDisplay.GEAR_RAM) {
                //check if target is valid
                final Targetable target = this.chooseTarget(b.getCoords());
                if (target == null || target.equals(ce) || !(target instanceof Aero)) {
                    clientgui
                            .doAlertDialog(
                                    Messages
                                            .getString("MovementDisplay.CantRam"), Messages.getString("MovementDisplay.NoTarget")); //$NON-NLS-1$ //$NON-NLS-2$
                    clearAllMoves();
                    return;
                }
                
                //check if it's a valid ram
                //First I need to add moves to the path if advanced
                if(ce instanceof Aero && client.game.useVectorMove()) {
                    cmd.clipToPossible();
                    cmd = addSteps(cmd,ce);
                }
                
                cmd.addStep(MovePath.STEP_RAM);
                
                ToHitData toHit = new RamAttackAction(cen, target.getTargetType(),target.getTargetId(), target.getPosition()).toHit(client.game, cmd);
                if (toHit.getValue() != TargetRoll.IMPOSSIBLE) {
                
                    //Determine how much damage the charger will take.
                    Aero ta = (Aero)target;
                    Aero ae = (Aero)ce;
                    int toAttacker = RamAttackAction.getDamageTakenBy(ae, ta, cmd.getSecondFinalPosition(ae.getPosition()),  cmd.getHexesMoved(), ta.getCurrentVelocity());
                    int toDefender = RamAttackAction.getDamageFor(ae, ta, cmd.getSecondFinalPosition(ae.getPosition()), cmd.getHexesMoved(), ta.getCurrentVelocity());
                   
                    //Ask the player if they want to charge.
                    if ( clientgui.doYesNoDialog
                         ( Messages.getString("MovementDisplay.RamDialog.title", new Object[]{target.getDisplayName()}), //$NON-NLS-1$
                           Messages.getString("MovementDisplay.RamDialog.message", new Object[]{ //$NON-NLS-1$      
                           toHit.getValueAsString(),new Double(Compute.oddsAbove(toHit.getValue())),toHit.getDesc(),
                           new Integer(toDefender),toHit.getTableDesc(),
                           new Integer(toAttacker)}))) {
                        // if they answer yes, charge the target.
                        cmd.getLastStep().setTarget(target);
                        moveTo(cmd);
                    } else {
                        // else clear movement
                        clearAllMoves();
                    }
                    return;
                }
                // if not valid, tell why
                clientgui.doAlertDialog( Messages.getString("MovementDisplay.CantRam"), //$NON-NLS-1$
                                      toHit.getDesc() );
                clearAllMoves();
                return;                       
            } else if (gear == MovementDisplay.GEAR_CHARGE) {
                // check if target is valid
                final Targetable target = this.chooseTarget(b.getCoords());
                if (target == null || target.equals(ce)) {
                    clientgui
                            .doAlertDialog(
                                    Messages
                                            .getString("MovementDisplay.CantCharge"), Messages.getString("MovementDisplay.NoTarget")); //$NON-NLS-1$ //$NON-NLS-2$
                    clearAllMoves();
                    return;
                }
         
                ToHitData toHit = new ChargeAttackAction(cen, target
                        .getTargetType(), target.getTargetId(), target
                        .getPosition()).toHit(client.game, cmd);
                if (toHit.getValue() != TargetRoll.IMPOSSIBLE) {

                    // Determine how much damage the charger will take.
                    int toAttacker = 0;
                    if (target.getTargetType() == Targetable.TYPE_ENTITY) {
                        Entity te = (Entity) target;
                        toAttacker = ChargeAttackAction
                                .getDamageTakenBy(
                                        ce,
                                        te,
                                        client.game.getOptions().booleanOption(
                                                "maxtech_charge_damage"), cmd.getHexesMoved()); //$NON-NLS-1$
                    } else if ((target.getTargetType() == Targetable.TYPE_FUEL_TANK)
                            || (target.getTargetType() == Targetable.TYPE_BUILDING)) {
                        Building bldg = client.game.getBoard().getBuildingAt(
                                moveto);
                        toAttacker = ChargeAttackAction.getDamageTakenBy(ce,
                                bldg);
                    }

                    // Ask the player if they want to charge.
                    if (clientgui
                            .doYesNoDialog(
                                    Messages
                                            .getString(
                                                    "MovementDisplay.ChargeDialog.title", new Object[] { target.getDisplayName() }), //$NON-NLS-1$
                                    Messages
                                            .getString(
                                                    "MovementDisplay.ChargeDialog.message", new Object[] { //$NON-NLS-1$      
                                                            toHit
                                                                    .getValueAsString(),
                                                            new Double(
                                                                    Compute
                                                                            .oddsAbove(toHit
                                                                                    .getValue())),
                                                            toHit.getDesc(),
                                                            new Integer(
                                                                    ChargeAttackAction
                                                                            .getDamageFor(
                                                                                    ce,
                                                                                    cmd
                                                                                            .getHexesMoved())),
                                                            toHit
                                                                    .getTableDesc(),
                                                            new Integer(
                                                                    toAttacker) }))) {
                        // if they answer yes, charge the target.
                        cmd.getLastStep().setTarget(target);
                        moveTo(cmd);
                    } else {
                        // else clear movement
                        clearAllMoves();
                    }
                    return;
                }
                // if not valid, tell why
                clientgui.doAlertDialog(Messages
                        .getString("MovementDisplay.CantCharge"), //$NON-NLS-1$
                        toHit.getDesc());
                clearAllMoves();
                return;
            } else if (gear == MovementDisplay.GEAR_DFA) {
                // check if target is valid
                final Targetable target = this.chooseTarget(b.getCoords());
                if (target == null || target.equals(ce)) {
                    clientgui
                            .doAlertDialog(
                                    Messages
                                            .getString("MovementDisplay.CantDFA"), Messages.getString("MovementDisplay.NoTarget")); //$NON-NLS-1$ //$NON-NLS-2$
                    clearAllMoves();
                    return;
                }

                // check if it's a valid DFA
                ToHitData toHit = DfaAttackAction.toHit(client.game, cen,
                        target, cmd);
                if (toHit.getValue() != TargetRoll.IMPOSSIBLE) {
                    // if yes, ask them if they want to DFA
                    if (clientgui
                            .doYesNoDialog(
                                    Messages
                                            .getString(
                                                    "MovementDisplay.DFADialog.title", new Object[] { target.getDisplayName() }), //$NON-NLS-1$
                                    Messages
                                            .getString(
                                                    "MovementDisplay.DFADialog.message", new Object[] { //$NON-NLS-1$
                                                            toHit
                                                                    .getValueAsString(),
                                                            new Double(
                                                                    Compute
                                                                            .oddsAbove(toHit
                                                                                    .getValue())),
                                                            toHit.getDesc(),
                                                            new Integer(
                                                                    DfaAttackAction
                                                                            .getDamageFor(
                                                                                    ce,
                                                                                    target instanceof Infantry
                                                                                            && !(target instanceof BattleArmor))),
                                                            toHit
                                                                    .getTableDesc(),
                                                            new Integer(
                                                                    DfaAttackAction
                                                                            .getDamageTakenBy(ce)) }))) {
                        // if they answer yes, DFA the target
                        cmd.getLastStep().setTarget(target);
                        moveTo(cmd);
                    } else {
                        // else clear movement
                        clearAllMoves();
                    }
                    return;

                }
                // if not valid, tell why
                clientgui.doAlertDialog(Messages
                        .getString("MovementDisplay.CantDFA"), //$NON-NLS-1$
                        toHit.getDesc());
                clearAllMoves();
                return;
            }

            butDone.setLabel(Messages.getString("MovementDisplay.Move")); //$NON-NLS-1$
            updateProneButtons();
            updateRACButton();
            updateSearchlightButton();
            updateLoadButtons();
            updateElevationButtons();
            updateFleeButton();
            updateLaunchButton();
            updateHoverButton();
            updateManeuverButton();
            updateSpeedButtons();
            updateThrustButton();
            updateRollButton();
            checkFuel();
            checkOOC();
            checkAtmosphere();
        }
    }

    private synchronized void updateProneButtons() {
        final Entity ce = ce();

        if (ce != null && !ce.isImmobile()) {
            setGetUpEnabled(cmd.getFinalProne() || cmd.getFinalHullDown());
            setGoProneEnabled(!(butUp.isEnabled()) && ce instanceof Mech);
            setHullDownEnabled(!(butUp.isEnabled()) && ce.canGoHullDown());
        } else {
            setGetUpEnabled(false);
            setGoProneEnabled(false);
            setHullDownEnabled(false);
        }
        // TW Rules change: Mechs missing both arms and one leg can't stand up
        if (ce instanceof Mech) {
            Mech mech = (Mech) ce;
            if (mech.cannotStandUp()) {
                setGetUpEnabled(false);
            }
        }

    }

    private void updateRACButton() {
        final Entity ce = ce();

        if (null == ce) {
            return;
        }
        setUnjamEnabled(ce.canUnjamRAC()
                && (gear == MovementDisplay.GEAR_LAND
                        || gear == MovementDisplay.GEAR_TURN || gear == MovementDisplay.GEAR_BACKUP)
                && cmd.getMpUsed() <= ce.getWalkMP());
    }

    private void updateSearchlightButton() {
        final Entity ce = ce();

        if (null == ce) {
            return;
        }
        setSearchlightEnabled(ce.hasSpotlight()
                && !cmd.contains(MovePath.STEP_SEARCHLIGHT), ce()
                .isUsingSpotlight());
    }

    private synchronized void updateElevationButtons() {
        final Entity ce = ce();

        if (null == ce) {
            return;
        }
        
        if(ce instanceof Aero && ((Aero)ce).isOutControlTotal()) {
            setRaiseEnabled(false);
            setLowerEnabled(false);
            return;
        }
        
        setRaiseEnabled(ce.canGoUp(cmd.getFinalElevation(), cmd
                .getFinalCoords()));
        setLowerEnabled(ce.canGoDown(cmd.getFinalElevation(), cmd
                .getFinalCoords()));
    }
    
    private void updateRollButton() {
        final Entity ce = ce();
        if(null==ce) return;
        
        if(!(ce instanceof Aero)) {
            return;
        }
        
        setRollEnabled(true);
        
        if(client.game.getBoard().inAtmosphere()) {
            setRollEnabled(false);
        }
        
        if(cmd.contains(MovePath.STEP_ROLL)) {
            setRollEnabled(false);
        }
        
        return;
        
    }
    
    private void updateHoverButton() {
        final Entity ce = ce();
        if(null==ce) return;
        
        if(!(ce instanceof Aero)) {
            return;
        }
        
        Aero a = (Aero)ce;
         
        if(!a.isSpheroid()) {
            return;
        }
        
        if(!client.game.getBoard().inAtmosphere()) {
            return;
        }
        
        if(!cmd.contains(MovePath.STEP_HOVER)) {
            setHoverEnabled(true);
        } else {
            setHoverEnabled(false);
        }
        
        return;
        
    }
    
    
    private void updateThrustButton() {
        final Entity ce = ce();
        if(null==ce) return;
        
        if(!(ce instanceof Aero)) {
            return;
        }
        
        Aero a = (Aero)ce;
        
        //only allow thrust if there is thrust left to spend
        int mpUsed = 0;
        MoveStep last = cmd.getLastStep();
        if(null != last)
            mpUsed = last.getMpUsed();
        
        if(mpUsed >= a.getRunMP()) {
            setThrustEnabled(false);
        } else {
            setThrustEnabled(true);
        }
        
        return;
    }
    
    private synchronized void updateSpeedButtons() {
        final Entity ce = ce();
        if(null==ce) return;
        
        if(!(ce instanceof Aero)) {
            return;
        }
        
        Aero a = (Aero)ce;
        
        //only allow acceleration and deceleration if the cmd is empty or the last step was 
        //acc/dec
                
        setAccEnabled(false);
        setDecEnabled(false);
        MoveStep last = cmd.getLastStep();
        //figure out implied velocity so you can't decelerate below zero
        int vel = a.getCurrentVelocity();
        int veln = a.getNextVelocity();
        if(null != last) {
            vel = last.getVelocity();
            veln = last.getVelocityN();
        }
        
        if(null == last) {
            setAccEnabled(true);
            if(vel > 0) {
                setDecEnabled(true);
            }
        } else if(last.getType() == MovePath.STEP_ACC) {
            setAccEnabled(true);
        } else if(last.getType() == MovePath.STEP_DEC && vel > 0) {
            setDecEnabled(true);
        }
        
        //if the aero has failed a maneuver this turn, then don't allow 
        if(a.didFailManeuver()) {
            setAccEnabled(false);
            setDecEnabled(false);
        }
        
        //if accelerated/decelerate at the end of last turn then disable
        if(a.didAccLast()) {
            setAccEnabled(false);
            setDecEnabled(false);
        }
        
        //allow acc/dec next if acceleration/deceleration hasn't been used
        setAccNEnabled(false);
        setDecNEnabled(false);
        if(!cmd.contains(MovePath.STEP_ACC) && !cmd.contains(MovePath.STEP_DEC) 
                && !cmd.contains(MovePath.STEP_DECN)) {
            setAccNEnabled(true);
        }
        
        if(!cmd.contains(MovePath.STEP_ACC) && !cmd.contains(MovePath.STEP_DEC) 
                && !cmd.contains(MovePath.STEP_ACCN) && veln > 0) {
            setDecNEnabled(true);
        }
        
        //acc/dec next needs to be disabled if acc/dec used before a failed maneuver
        if(a.didFailManeuver() && a.didAccDecNow()) {
            setDecNEnabled(false);
            setAccNEnabled(false);
        }
        
        
        //if in atmosphere, limit acceleration to 2x safe thrust
        if(vel == (2 * a.getWalkMP())) {
            setAccEnabled(false);
        }
        //velocity next will get halved before next turn so allow up to 4 times
        if(veln == (4 * a.getWalkMP())) {
            setAccNEnabled(false);
        }
        
        //if this is a tele-operated missile then it can't decelerate no matter what
        if(a instanceof TeleMissile) {
            setDecEnabled(false);
            setDecNEnabled(false);
        }
        
        return;
    }
    
    private void updateDumpButton() {
         
        if(ce() instanceof Aero) {
            Aero a = (Aero)ce();
            setDumpEnabled(a.hasBombs() && cmd.length() == 0);
        } else {
            setDumpEnabled(false);
        }
        
    }
    
    private void updateFleeButton() {
        final Entity ce = ce();
        
        //Aeros should be able to flee if they reach a border hex with velocity remaining
        //and facing the right direction 
        if(ce instanceof Aero) {
            MoveStep step = cmd.getLastStep();
            Coords position = ce.getPosition();
            int facing = ce.getFacing();
            Aero a = (Aero)ce;
            int velocityLeft = a.getCurrentVelocity();
            if(step != null) {
                position = step.getPosition();
                facing = step.getFacing();
                velocityLeft = step.getVelocityLeft();
            }          
            boolean evenx = (position.x % 2) == 0;
            if(velocityLeft > 0 && 
                    ((position.x == 0 && (facing == 5 || facing==4)) || 
                     (position.x == client.game.getBoard().getWidth() - 1 && (facing == 1 || facing==2)) ||
                     (position.y == 0 && (facing == 1 || facing==5 || facing==0) && evenx) || 
                     (position.y == 0 && facing==0) || 
                     (position.y == client.game.getBoard().getHeight() - 1 && (facing == 2 || facing==3 || facing==4) && !evenx) ||
                     (position.y == client.game.getBoard().getHeight() - 1 && facing==3))) {
                setFleeEnabled(true);
            } else {
                setFleeEnabled(false);
            }
        }
    }

    private void updateLaunchButton() {
        
        final Entity ce = ce();
        
        if (null == ce ) {
            return;
        }
        
        setLaunchEnabled(ce.getLaunchableFighters().size() > 0 || ce.getLaunchableSmallCraft().size() > 0);
        
    }
    
    private void updateManeuverButton() {
        
        final Entity ce = ce();
        
        if (null == ce ) {
            return;
        }
        
        if(!(ce instanceof Aero))
            return;
        
        Aero a = (Aero)ce;
        
        if(a.isSpheroid())
            return;
        
        if(!a.didFailManeuver() && (null == cmd || !cmd.contains(MovePath.STEP_MANEUVER))) {
            setManeuverEnabled(true);
        }
        return;
    }

    private synchronized void updateLoadButtons() {
        final Entity ce = ce();
        if (null == ce)
            return;

        boolean legalGear = ((gear == MovementDisplay.GEAR_LAND)
                || (gear == MovementDisplay.GEAR_TURN) || (gear == MovementDisplay.GEAR_BACKUP));
        int unloadEl = cmd.getFinalElevation();
        IHex hex = ce.getGame().getBoard().getHex(cmd.getFinalCoords());
        boolean canUnloadHere = false;
        for (Enumeration<Entity> e = loadedUnits.elements(); e
                .hasMoreElements();) {
            Entity en = e.nextElement();
            if (en.isElevationValid(unloadEl, hex) || en.getJumpMP() > 0) {
                canUnloadHere = true;
                break;
            }
        }
        // Disable the "Unload" button if we're in the wrong
        // gear or if the entity is not transporting units.
        if (!legalGear || loadedUnits.size() == 0 || cen == Entity.NONE
                || (!canUnloadHere)) {
            setUnloadEnabled(false);
        } else {
            setUnloadEnabled(true);
        }
        // If the current entity has moved, disable "Load" button.
        if (cmd.length() > 0 || cen == Entity.NONE) {
            setLoadEnabled(false);
        } else {
            // Check the other entities in the current hex for friendly units.
            Entity other = null;
            Enumeration<Entity> entities = client.game.getEntities(ce
                    .getPosition());
            boolean isGood = false;
            while (entities.hasMoreElements()) {
                // Is the other unit friendly and not the current entity?
                other = entities.nextElement();
                if (!ce.getOwner().isEnemyOf(other.getOwner())
                        && !ce.equals(other)) {
                    // Yup. If the current entity has at least 1 MP, if it can
                    // transport the other unit, and if the other hasn't moved
                    // then enable the "Load" button.
                    if (ce.getWalkMP() > 0 && ce.canLoad(other)
                            && other.isLoadableThisTurn()) {
                        setLoadEnabled(true);
                        isGood = true;
                    }

                    // We can stop looking.
                    break;
                }
                // Nope. Discard it.
                other = null;
            } // Check the next entity in this position.
            if (!isGood) {
                setLoadEnabled(false);
            }
        } // End ce-hasn't-moved
    } // private void updateLoadButtons

    /**
     * Get the unit that the player wants to unload. This method will remove the
     * unit from our local copy of loaded units.
     * 
     * @return The <code>Entity</code> that the player wants to unload. This
     *         value will not be <code>null</code>.
     */
    private Entity getUnloadedUnit() {
        Entity ce = ce();
        Entity choice = null;
        // Handle error condition.
        if (this.loadedUnits.size() == 0) {
            System.err
                    .println("MovementDisplay#getUnloadedUnit() called without loaded units."); //$NON-NLS-1$

        }

        // If we have multiple choices, display a selection dialog.
        else if (this.loadedUnits.size() > 1) {
            String[] names = new String[this.loadedUnits.size()];
            String question = Messages.getString(
                    "MovementDisplay.UnloadUnitDialog.message", new Object[] { //$NON-NLS-1$
                    ce.getShortName(), ce.getUnusedString() });
            for (int loop = 0; loop < names.length; loop++) {
                names[loop] = this.loadedUnits.elementAt(loop).getShortName();
            }
            SingleChoiceDialog choiceDialog = new SingleChoiceDialog(
                    clientgui.frame,
                    Messages
                            .getString("MovementDisplay.UnloadUnitDialog.title"), //$NON-NLS-1$
                    question, names);
            choiceDialog.setVisible(true);
            if (choiceDialog.getAnswer() == true) {
                choice = this.loadedUnits.elementAt(choiceDialog.getChoice());
            }
        } // End have-choices

        // Only one choice.
        else {
            choice = this.loadedUnits.elementAt(0);
            this.loadedUnits.removeElementAt(0);
        }

        // Return the chosen unit.
        return choice;
    }
    
    /**
     * FIGHTER RECOVERY
     * fighter recovery will be handled differently than loading other units.  Namely, it will
     * be an action of the fighter not the carrier.  So the fighter just flies right up to a carrier
     * whose movement is ended and hops on.  
     * need a new function
     */
    private synchronized void updateRecoveryButton() {
        
        final Entity ce = ce();
        if(null==ce) return;
        
//      I also want to handle fighter recovery here. If using advanced movement
        //it is not a function of where carrier is but where the carrier will be at the end 
        //of its move
        if(ce instanceof Aero) {
            Coords loadeePos = cmd.getFinalCoords();
            if(client.game.useVectorMove()) {
                //not where you are, but where you will be
                loadeePos = Compute.getFinalPosition(ce.getPosition(), cmd.getFinalVectors());
            }
            Entity other = null;
            Enumeration<Entity> entities = client.game.getEntities(loadeePos);
            boolean isGood = false;
            while (entities.hasMoreElements()) {
                // Is the other unit friendly and not the current entity?
                other = entities.nextElement();
                if (!ce.getOwner().isEnemyOf(other.getOwner())
                        && !ce.equals(other)) {
                    // must be done with its movement
                    // it also must be same heading and velocity
                    if ( other instanceof Aero && 
                            other.isDone()
                            && other.canLoad(ce)
                            && cmd.getFinalFacing() == other.getFacing()) {
                        
                        //now lets check velocity
                        //depends on movement rules
                        Aero oa = (Aero)other;
                        if(client.game.useVectorMove()) {                            
                            //can you do equality with vectors?
                            if(Compute.sameVectors(cmd.getFinalVectors(),oa.getVectors())) {
                                setRecoverEnabled(true);
                                isGood = true;
                            }    
                        } else if(cmd.getFinalVelocity() == oa.getCurrentVelocity()) {
                            setRecoverEnabled(true);
                            isGood = true;
                        }    
                    }
                }
                // Nope. Discard it.
                other = null;
            } // Check the next entity in this position.
            if (!isGood) {
                setRecoverEnabled(false);
            }           
        }
        
    }
    
    /**
     * Get the unit that the player wants to unload. This method will
     * remove the unit from our local copy of loaded units.
     *
     * @return  The <code>Entity</code> that the player wants to unload.
     *          This value will not be <code>null</code>.
     */
    private Vector<Integer[]> getLaunchedUnits() {
        Entity ce  = ce();
        Vector<Integer[]> choices = new Vector<Integer[]>();
        
        Vector<Entity> launchableFighters = ce.getLaunchableFighters();
        Vector<Entity> launchableSmallCraft = ce.getLaunchableSmallCraft();
        
        // Handle error condition.
        if ( launchableFighters.size() <= 0  && launchableSmallCraft.size() <= 0 ) {
            System.err.println( "MovementDisplay#getUnloadedUnit() called without loaded units." ); //$NON-NLS-1$

        } else {
            //cycle through the fighter bays and then the small craft bays
            int bayNum = 1;
            Bay currentBay;
            Vector<Entity> currentFighters = new Vector<Entity>();
            int doors = 0;
            Vector<Bay> FighterBays = ce.getFighterBays();
            for (int i = 0; i < FighterBays.size(); i++) {
                currentBay = FighterBays.elementAt(i);
                currentFighters = currentBay.getLaunchableUnits();
                //crap, this has to be done by doors in order to get the right 
                //bonus to the control roll
                doors = currentBay.getDoors();
                for( int j = 0; j < doors; j++) {
                    if(currentFighters.size() > 0) {
                        String[] names = new String[ currentFighters.size() ];
                        String question = Messages.getString("MovementDisplay.LaunchFighterDialog.message", new Object[]{ //$NON-NLS-1$
                                ce.getShortName(), bayNum, j+1});
                        for ( int loop = 0; loop < names.length; loop++ ) {
                            names[loop] = currentFighters.elementAt(loop).getShortName();
                        }
                        ChoiceDialog choiceDialog =
                            new ChoiceDialog( clientgui.frame,
                                    Messages.getString("MovementDisplay.LaunchFighterDialog.title", new Object[]{ //$NON-NLS-1$
                                            currentBay.getType(), bayNum, j+1}), //$NON-NLS-1$
                                            question,
                                            names );
                        choiceDialog.setVisible(true);
                        if ( choiceDialog.getAnswer() == true ) {
                            //load up the choices
                            int[] unitsLaunched = choiceDialog.getChoices();
                            //get the bonus to the control roll for overlaunching
                            int bonus = unitsLaunched.length - 2;
                            //I need to make the door check here, doesn't seem right but can't figure out better way
                            //Its a hack, I know
                            int doorDamage = 0;
                            boolean alreadyDamaged = false;
                            for(int k = 0; k < unitsLaunched.length; k++) {
                                //add these to the units chosen
                                doorDamage = 0;
                                if((((Aero)ce).isOutControlTotal() || k > 1) && !alreadyDamaged) {
                                    int doorroll = Compute.d6(2);
                                    if(doorroll == 2) {
                                        doorDamage = 1;
                                        alreadyDamaged = true;
                                    }
                                }
                                choices.add(new Integer[]{currentFighters.elementAt(unitsLaunched[k]).getId(), bonus, doorDamage});
                            }
                            //now remove them (must be a better way?)
                            for(int l = unitsLaunched.length; l > 0; l--) {
                                currentFighters.remove(unitsLaunched[l-1]);
                            }
                        }     
                    }
                }
                bayNum++;
            }
        }// End have-choices
        //      Return the chosen unit.
        return choices;
    } 

        
    /**
     * @return the unit id that the player wants to be recovered by
     */
    private int getRecoveryUnit() {
        Entity ce  = ce();
        Vector<Integer> choices = new Vector<Integer>();
        
        //collect all possible choices
        Coords loadeePos = cmd.getFinalCoords();
        if(client.game.useVectorMove()) {
            //not where you are, but where you will be
            loadeePos = Compute.getFinalPosition(ce.getPosition(), cmd.getFinalVectors());
        }
        Entity other = null;
        Enumeration<Entity> entities = client.game.getEntities(loadeePos);
        while (entities.hasMoreElements()) {
            // Is the other unit friendly and not the current entity?
            other = entities.nextElement();
            if (!ce.getOwner().isEnemyOf(other.getOwner())
                    && !ce.equals(other)) {
                // must be done with its movement
                // it also must be same heading and velocity
                if ( other instanceof Aero 
                        && !((Aero)other).isOutControlTotal()
                        && other.isDone()
                        && other.canLoad(ce)
                        && ce.isLoadableThisTurn()
                        &&cmd.getFinalFacing() == other.getFacing()) {
                    
                    //now lets check velocity
                    //depends on movement rules
                    Aero oa = (Aero)other;
                    if(client.game.useVectorMove()) {                            
                        if(Compute.sameVectors(cmd.getFinalVectors(),oa.getVectors())) {
                            choices.add(other.getId());
                        }    
                    } else if(cmd.getFinalVelocity() == oa.getCurrentVelocity()) {
                        choices.add(other.getId());
                    }    
                }
            }
            // Nope. Discard it.
            other = null;
        } // Check the next entity in this position. 
        
        if(choices.size() < 1) {
            return -1;
        }
        
        if(choices.size() == 1) {
            if ( client.game.getEntity(choices.elementAt(0)).mpUsed > 0) {
                if(clientgui.doYesNoDialog
                        ( Messages.getString("MovementDisplay.RecoverSureDialog.title"), //$NON-NLS-1$
                                Messages.getString("MovementDisplay.RecoverSureDialog.message") //$NON-NLS-1$      
                        )) {
                    return choices.elementAt(0);
                } 
            } else {
                return choices.elementAt(0);
            }
            return -1;
        }
        
        String[] names = new String[ choices.size() ];
        for ( int loop = 0; loop < names.length; loop++ ) {
            names[loop] = client.game.getEntity(choices.elementAt(loop)).getShortName();
        }
        String question = Messages.getString("MovementDisplay.RecoverFighterDialog.message");
        SingleChoiceDialog choiceDialog =
            new SingleChoiceDialog( clientgui.frame,
                    Messages.getString("MovementDisplay.RecoverFighterDialog.title"),
                            question,
                            names );
        choiceDialog.setVisible(true);
        
        if(choiceDialog.getAnswer()) {
            //if this unit is thrusting, make sure they are aware            
            if ( client.game.getEntity(choices.elementAt(choiceDialog.getChoice())).mpUsed > 0) {
                if(clientgui.doYesNoDialog
                        ( Messages.getString("MovementDisplay.RecoverSureDialog.title"), //$NON-NLS-1$
                                Messages.getString("MovementDisplay.RecoverSureDialog.message") //$NON-NLS-1$      
                        )) {
                    return choices.elementAt(choiceDialog.getChoice());
                } 
            } else {
                return choices.elementAt(choiceDialog.getChoice());
            }
        }
        return -1;
    }
    
    //check for out of control and adjust buttons
    private void checkOOC() {
        final Entity ce = ce();
        if(null==ce) return;
        
        if(!(ce instanceof Aero)) {
            return;
        }
        
        Aero a = (Aero)ce;
        
        if(a.isOutControlTotal()) {
            disableButtons();
            butDone.setEnabled(true);
            butNext.setEnabled(true);
            butLaunch.setEnabled(true);
        }
        return;
    }
    
    //check for fuel and adjust buttons
    private void checkFuel() {
        final Entity ce = ce();
        if(null==ce) return;
        
        if(!(ce instanceof Aero)) {
            return;
        }
        
        Aero a = (Aero)ce;
        if(a.getFuel() < 1) {
            disableButtons();
            butDone.setEnabled(true);
            butNext.setEnabled(true);
            butLaunch.setEnabled(true);
            updateRACButton();
            updateRecoveryButton();
            updateDumpButton();
        }
        return;
    }
    
    //check for atmosphere and adjust buttons
    private void checkAtmosphere() {
        final Entity ce = ce();
        if(null==ce) return;
        
        if(!(ce instanceof Aero)) {
            return;
        }
        
        Aero a = (Aero)ce;
        if(client.game.getBoard().inAtmosphere()) {
            if(a.isSpheroid()) {
                  butAcc.setEnabled(false);
                butDec.setEnabled(false);
                butAccN.setEnabled(false);
                butDecN.setEnabled(false);
            }             
        }
        return;
    }

    /**
     * Have the player select a target from the entities at the given coords.
     * 
     * @param pos - the <code>Coords</code> containing targets.
     */
    private Targetable chooseTarget(Coords pos) {
        final Entity ce = ce();

        // Assume that we have *no* choice.
        Targetable choice = null;

        // Get the available choices.
        Enumeration<Entity> choices = client.game.getEntities(pos);

        // Convert the choices into a List of targets.
        Vector<Targetable> targets = new Vector<Targetable>();
        while (choices.hasMoreElements()) {
            choice = choices.nextElement();
            if (!ce.equals(choice)) {
                targets.addElement(choice);
            }
        }

        // Is there a building in the hex?
        Building bldg = client.game.getBoard().getBuildingAt(pos);
        if (bldg != null) {
            targets.addElement(new BuildingTarget(pos, client.game.getBoard(),
                    false));
        }

        // Do we have a single choice?
        if (targets.size() == 1) {

            // Return that choice.
            choice = targets.elementAt(0);

        }

        // If we have multiple choices, display a selection dialog.
        else if (targets.size() > 1) {
            String[] names = new String[targets.size()];
            String question = Messages.getString(
                    "MovementDisplay.ChooseTargetDialog.message", new Object[] {//$NON-NLS-1$
                    pos.getBoardNum() });
            for (int loop = 0; loop < names.length; loop++) {
                names[loop] = targets.elementAt(loop).getDisplayName();
            }
            SingleChoiceDialog choiceDialog = new SingleChoiceDialog(
                    clientgui.frame,
                    Messages
                            .getString("MovementDisplay.ChooseTargetDialog.title"), //$NON-NLS-1$
                    question.toString(), names);
            choiceDialog.setVisible(true);
            if (choiceDialog.getAnswer() == true) {
                choice = targets.elementAt(choiceDialog.getChoice());
            }
        } // End have-choices

        // Return the chosen unit.
        return choice;

    } // End private Targetable chooseTarget( Coords )

    private int chooseMineToLay() {
        MineLayingDialog mld = new MineLayingDialog(clientgui.frame, ce());
        mld.setVisible(true);
        if (mld.getAnswer() == true) {
            return mld.getMine();
        }
        return -1;
    }

    private void dumpBombs() {
        
        if(!(ce() instanceof Aero)) {
            return;
        }
        Aero a = (Aero)ce();
        
        //bring up dialog to dump bombs, then make a control roll and report success or failure
        //should update mp available
        BombPayloadDialog dumpBombsDialog = 
            new BombPayloadDialog(clientgui.frame,
                    Messages.getString("MovementDisplay.BombDumpDialog.title"), //$NON-NLS-1$
                    a.getBombChoices(), false, true);
        dumpBombsDialog.setVisible(true); 
        if(dumpBombsDialog.getAnswer()) { 
            int[] bombsDumped = dumpBombsDialog.getChoices();
            //first make a control roll
            PilotingRollData psr = ce().getBasePilotingRoll();
            int ctrlroll = Compute.d6(2);
            Report r = new Report(9500);
            r.subject = ce().getId();
            r.add(ce().getDisplayName());
            r.add(psr.getValue());
            r.add(ctrlroll);
            r.newlines = 0;
            r.indent(1);
            if(ctrlroll < psr.getValue()) {
                r.choose(false);
                //addReport(r);
                String title = Messages.getString("MovementDisplay.DumpingBombs.title"); //$NON-NLS-1$
                String body = Messages.getString("MovementDisplay.DumpFailure.message"); //$NON-NLS-1$
                clientgui.doAlertDialog(title, body);
                //failed the roll, so dump all bombs
                bombsDumped = a.getBombChoices();
            } else {
                //avoided damage
                r.choose(true);
                String title = Messages.getString("MovementDisplay.DumpingBombs.title"); //$NON-NLS-1$
                String body = Messages.getString("MovementDisplay.DumpSuccessful.message"); //$NON-NLS-1$
                clientgui.doAlertDialog(title, body);
                //addReport(r);
            }
            //now unload the bombs
            for(int j = 0; j < bombsDumped.length; j++) {
                if(bombsDumped[j] > 0) {
                    a.removeBombs(bombsDumped[j], j);
                    //Report r = new Report(5115);
                    r.subject = ce().getId();
                    r.addDesc(ce());
                    r.add("" + bombsDumped[j] + " " + Aero.bombNames[j] + "(s)");
                    //addReport(r);    
                }
            }   
            //update the bomb load immediately
            a.updateBombLoad();
            client.sendUpdateEntity(ce());
            //not sure how to update mech display, but everything else is working
        }
    }
    
    /*
     * based on maneuver type add the appropriate steps
     * return true if we should redraw the movement data
     */
    private boolean addManeuver(int type) {       
        cmd.addManeuver(type);
        switch(type) {
            case (ManeuverType.MAN_HAMMERHEAD):
                cmd.addStep(MovePath.STEP_YAW, true, true);
                return true;
            case (ManeuverType.MAN_HALF_ROLL):
                cmd.addStep(MovePath.STEP_ROLL, true, true);
                return true;
            case (ManeuverType.MAN_BARREL_ROLL):
                cmd.addStep(MovePath.STEP_DEC, true, true);
            return true; 
            case(ManeuverType.MAN_IMMELMAN):
                gear = MovementDisplay.GEAR_IMMEL;
                return false;
            case (ManeuverType.MAN_SPLIT_S):
                gear = MovementDisplay.GEAR_SPLIT_S;
                return false;
            case (ManeuverType.MAN_VIFF):
                if(!(ce() instanceof Aero)) {
                    return false;
                }                
                Aero a = (Aero)ce();
                MoveStep last = cmd.getLastStep();
                int vel = a.getCurrentVelocity();
                if(null != last) {
                    vel = last.getVelocityLeft();
                }
                while(vel > 0) {
                    cmd.addStep(MovePath.STEP_DEC, true, true);
                    vel--;
                }
                cmd.addStep(MovePath.STEP_UP);
                return true;
            case (ManeuverType.MAN_SIDE_SLIP_LEFT):
                cmd.addStep(MovePath.STEP_LATERAL_LEFT, true, true);
                return true;
            case (ManeuverType.MAN_SIDE_SLIP_RIGHT):
                cmd.addStep(MovePath.STEP_LATERAL_RIGHT, true, true);
                return true;
            case (ManeuverType.MAN_LOOP):
                cmd.addStep(MovePath.STEP_LOOP, true, true);
                return true;
            default:
                return false;
        }        
    }
    
    //
    // GameListener
    //
    public void gameTurnChange(GameTurnChangeEvent e) {

        // Are we ignoring events?
        if (this.isIgnoringEvents()) {
            return;
        }

        if (client.game.getPhase() != IGame.Phase.PHASE_MOVEMENT) {
            // ignore
            return;
        }
        // else, change turn
        endMyTurn();

        if (client.isMyTurn()) {
            // Can the player unload entities stranded on immobile transports?
            if (client.canUnloadStranded()) {
                unloadStranded();
            } else {
                beginMyTurn();
            }

        } else {
            if (e.getPlayer() == null
                    && client.game.getTurn() instanceof GameTurn.UnloadStrandedTurn) {
                setStatusBarText(Messages
                        .getString("MovementDisplay.waitForAnother")); //$NON-NLS-1$
            } else {
                setStatusBarText(Messages
                        .getString(
                                "MovementDisplay.its_others_turn", new Object[] { e.getPlayer().getName() })); //$NON-NLS-1$
            }
        }
    }

    public void gamePhaseChange(GamePhaseChangeEvent e) {

        // Are we ignoring events?
        if (this.isIgnoringEvents()) {
            return;
        }

        if (client.isMyTurn() && client.game.getPhase() != IGame.Phase.PHASE_MOVEMENT) {
            endMyTurn();
        }
        if (client.game.getPhase() == IGame.Phase.PHASE_MOVEMENT) {
            setStatusBarText(Messages
                    .getString("MovementDisplay.waitingForMovementPhase")); //$NON-NLS-1$
        }
    }

    //
    // ActionListener
    //
    public synchronized void actionPerformed(ActionEvent ev) {
        final Entity ce = ce();

        // Are we ignoring events?
        if (this.isIgnoringEvents()) {
            return;
        }

        if (statusBarActionPerformed(ev, client))
            return;

        if (!client.isMyTurn()) {
            // odd...
            return;
        }

        if (ev.getSource() == butDone) {
            moveTo(cmd);
        } else if (ev.getActionCommand().equals(MOVE_NEXT)) {
            selectEntity(client.getNextEntityNum(cen));
        } else if (ev.getActionCommand().equals(MOVE_CANCEL)) {
            clearAllMoves();
        } else if (ev.getSource() == butMore) {
            buttonLayout++;
            buttonLayout %= NUM_BUTTON_LAYOUTS;
            setupButtonPanel();
        } else if (ev.getActionCommand().equals(MOVE_UNJAM)) {
            if (gear == MovementDisplay.GEAR_JUMP
                    || gear == MovementDisplay.GEAR_CHARGE
                    || gear == MovementDisplay.GEAR_DFA
                    || cmd.getMpUsed() > ce.getWalkMP()
                    || gear == MovementDisplay.GEAR_SWIM
                    || gear == MovementDisplay.GEAR_RAM) { // in the wrong gear
                // clearAllMoves();
                // gear = Compute.GEAR_LAND;
                setUnjamEnabled(false);
            } else {
                cmd.addStep(MovePath.STEP_UNJAM_RAC);
                moveTo(cmd);
            }
        } else if (ev.getActionCommand().equals(MOVE_SEARCHLIGHT)) {
            cmd.addStep(MovePath.STEP_SEARCHLIGHT);
        } else if (ev.getActionCommand().equals(MOVE_WALK)) {
            if (gear == MovementDisplay.GEAR_JUMP
                    || gear == MovementDisplay.GEAR_SWIM) {
                clearAllMoves();
            }
            gear = MovementDisplay.GEAR_LAND;
        } else if (ev.getActionCommand().equals(MOVE_JUMP)) {
            if (ce instanceof LandAirMech
                    && ((LandAirMech) ce).isInMode(LandAirMech.MODE_AIRMECH)) {

                if (cmd.isFlying()) {
                    cmd.addStep(MovePath.STEP_LAND);
                    gear = MovementDisplay.GEAR_JUMP;
                } else {
                    cmd.addStep(MovePath.STEP_TAKEOFF);
                    gear = MovementDisplay.GEAR_JUMP;
                }
            } else {
                if (gear != MovementDisplay.GEAR_JUMP) {
                    clearAllMoves();
                }
                if (!cmd.isJumping()) {
                    cmd.addStep(MovePath.STEP_START_JUMP);
                }
                gear = MovementDisplay.GEAR_JUMP;
            }
        } else if (ev.getActionCommand().equals(MOVE_SWIM)) {
            if (gear != MovementDisplay.GEAR_SWIM) {
                clearAllMoves();
            }
            // dcmd.addStep(MovePath.STEP_SWIM);
            gear = MovementDisplay.GEAR_SWIM;
            ce
                    .setMovementMode((ce instanceof BipedMech) ? IEntityMovementMode.BIPED_SWIM
                            : IEntityMovementMode.QUAD_SWIM);
        } else if (ev.getActionCommand().equals(MOVE_TURN)) {
            gear = MovementDisplay.GEAR_TURN;
        } else if (ev.getActionCommand().equals(MOVE_BACK_UP)) {
            if (gear == MovementDisplay.GEAR_JUMP) {
                clearAllMoves();
            }
            gear = MovementDisplay.GEAR_BACKUP;
        } else if (ev.getActionCommand().equals(MOVE_CLEAR)) {
            clearAllMoves();
            if (!client.game.containsMinefield(ce.getPosition())) {
                clientgui.doAlertDialog(Messages
                        .getString("MovementDisplay.CantClearMinefield"), //$NON-NLS-1$
                        Messages.getString("MovementDisplay.NoMinefield")); //$NON-NLS-1$
                return;
            }

            // Does the entity has a minesweeper?
            int clear = Minefield.CLEAR_NUMBER_INFANTRY;
            int boom = Minefield.CLEAR_NUMBER_INFANTRY_ACCIDENT;
            for (Mounted mounted : ce.getMisc()) {
                if (mounted.getType().hasFlag(MiscType.F_TOOLS)
                        && mounted.getType().hasSubType(MiscType.S_MINESWEEPER)) {
                    int sweeperType = mounted.getType().getToHitModifier();
                    clear = Minefield.CLEAR_NUMBER_SWEEPER[sweeperType];
                    boom = Minefield.CLEAR_NUMBER_SWEEPER_ACCIDENT[sweeperType];
                    break;
                }
            }

            if (clientgui
                    .doYesNoDialog(
                            Messages
                                    .getString("MovementDisplay.ClearMinefieldDialog.title"), //$NON-NLS-1$
                            Messages
                                    .getString(
                                            "MovementDisplay.ClearMinefieldDialog.message", new Object[] { //$NON-NLS-1$
                                            new Integer(clear),
                                                    new Integer(boom) }))) {
                cmd.addStep(MovePath.STEP_CLEAR_MINEFIELD);
                moveTo(cmd);
            }
        } else if (ev.getActionCommand().equals(MOVE_CHARGE)) {
            if (gear != MovementDisplay.GEAR_LAND) {
                clearAllMoves();
            }
            gear = MovementDisplay.GEAR_CHARGE;
        } else if (ev.getActionCommand().equals(MOVE_DFA)) {
            if (gear != MovementDisplay.GEAR_JUMP) {
                clearAllMoves();
            }
            gear = MovementDisplay.GEAR_DFA;
            if (!cmd.isJumping()) {
                cmd.addStep(MovePath.STEP_START_JUMP);
            }
        } else if (ev.getActionCommand().equals(MOVE_RAM)) {
            if (gear != MovementDisplay.GEAR_LAND) {
                clearAllMoves();
            }
            gear = MovementDisplay.GEAR_RAM;
        } else if (ev.getActionCommand().equals(MOVE_GET_UP)) {
            clearAllMoves();
            if (cmd.getFinalProne() || cmd.getFinalHullDown()) {
                cmd.addStep(MovePath.STEP_GET_UP);
            }
            clientgui.bv.drawMovementData(ce, cmd);
            butDone.setLabel(Messages.getString("MovementDisplay.Move")); //$NON-NLS-1$
        } else if (ev.getActionCommand().equals(MOVE_GO_PRONE)) {
            gear = MovementDisplay.GEAR_LAND;
            if (!cmd.getFinalProne()) {
                cmd.addStep(MovePath.STEP_GO_PRONE);
            }
            clientgui.bv.drawMovementData(ce, cmd);
            butDone.setLabel(Messages.getString("MovementDisplay.Move")); //$NON-NLS-1$
        } else if (ev.getActionCommand().equals(MOVE_HULL_DOWN)) {
            gear = MovementDisplay.GEAR_LAND;
            if (!cmd.getFinalHullDown()) {
                cmd.addStep(MovePath.STEP_HULL_DOWN);
            }
            clientgui.bv.drawMovementData(ce, cmd);
            butDone.setLabel(Messages.getString("MovementDisplay.Move")); //$NON-NLS-1$
        } else if (ev.getActionCommand().equals(MOVE_FLEE)
                && clientgui
                        .doYesNoDialog(
                                Messages
                                        .getString("MovementDisplay.EscapeDialog.title"), Messages.getString("MovementDisplay.EscapeDialog.message"))) { //$NON-NLS-1$ //$NON-NLS-2$
            clearAllMoves();
            cmd.addStep(MovePath.STEP_FLEE);
            moveTo(cmd);
        } else if (ev.getActionCommand().equals(MOVE_EJECT)) {
            if (ce instanceof Tank) {
                if (clientgui
                        .doYesNoDialog(
                                Messages
                                        .getString("MovementDisplay.AbandonDialog.title"), Messages.getString("MovementDisplay.AbandonDialog.message"))) { //$NON-NLS-1$ //$NON-NLS-2$
                    clearAllMoves();
                    cmd.addStep(MovePath.STEP_EJECT);
                    moveTo(cmd);
                }
            } else if (clientgui
                    .doYesNoDialog(
                            Messages
                                    .getString("MovementDisplay.AbandonDialog1.title"), Messages.getString("MovementDisplay.AbandonDialog1.message"))) { //$NON-NLS-1$ //$NON-NLS-2$
                clearAllMoves();
                cmd.addStep(MovePath.STEP_EJECT);
                moveTo(cmd);
            }
        } else if (ev.getActionCommand().equals(MOVE_LOAD)) {
            // Find the other friendly unit in our hex, add it
            // to our local list of loaded units, and then stop.
            Entity other = null;
            Enumeration<Entity> entities = client.game.getEntities(ce
                    .getPosition());
            while (entities.hasMoreElements()) {
                other = entities.nextElement();
                if (!ce.getOwner().isEnemyOf(other.getOwner())
                        && !ce.equals(other)) {
                    loadedUnits.addElement(other);
                    break;
                }
                other = null;
            }

            if (other != null) {
                cmd.addStep(MovePath.STEP_LOAD);
                clientgui.bv.drawMovementData(ce, cmd);
                gear = MovementDisplay.GEAR_LAND;
            } // else - didn't find a unit to load
        } else if (ev.getActionCommand().equals(MOVE_UNLOAD)) {
            // Ask the user if we're carrying multiple units.
            Entity other = getUnloadedUnit();

            if (other != null) {
                cmd.addStep(MovePath.STEP_UNLOAD, other);
                clientgui.bv.drawMovementData(ce, cmd);
            } // else - Player canceled the unload.
        } else if (ev.getActionCommand().equals(MOVE_RAISE_ELEVATION)) {
            cmd.addStep(MovePath.STEP_UP);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_LOWER_ELEVATION)) {
            //if this movement path goes down more than two altitudes
            //then add acceleration. 
            //TODO: Is there somewhere better to put this?
            if(ce instanceof Aero && null != cmd.getLastStep()
                    && cmd.getLastStep().getNDown() == 1 
                    && cmd.getLastStep().getVelocity() < 12 
                    && !((Aero)ce).isSpheroid()) {
                cmd.addStep(MovePath.STEP_ACC, true);
            }
            cmd.addStep(MovePath.STEP_DOWN);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_CLIMB_MODE)) {
            MoveStep ms = cmd.getLastStep();
            if (ms != null
                    && (ms.getType() == MovePath.STEP_CLIMB_MODE_ON || ms
                            .getType() == MovePath.STEP_CLIMB_MODE_OFF))
                cmd.removeLastStep();
            else if (cmd.getFinalClimbMode())
                cmd.addStep(MovePath.STEP_CLIMB_MODE_OFF);
            else
                cmd.addStep(MovePath.STEP_CLIMB_MODE_ON);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_LAY_MINE)) {
            clearAllMoves();
            int i = chooseMineToLay();
            if (i != -1) {
                Mounted m = ce().getEquipment(i);
                if (m.getMineType() == Mounted.MINE_VIBRABOMB) {
                    VibrabombSettingDialog vsd = new VibrabombSettingDialog(
                            clientgui.frame);
                    vsd.setVisible(true);
                    m.setVibraSetting(vsd.getSetting());
                }
                cmd.addStep(MovePath.STEP_LAY_MINE, i);
                moveTo(cmd);
            }
        } else if (ev.getActionCommand().equals(MOVE_DIG_IN)) {
            cmd.addStep(MovePath.STEP_DIG_IN);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_FORTIFY)) {
            cmd.addStep(MovePath.STEP_FORTIFY);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_SHAKE_OFF)) {
            cmd.addStep(MovePath.STEP_SHAKE_OFF_SWARMERS);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_MODE_MECH)) {
            clearAllMoves();
            if (ce instanceof LandAirMech) {
                final LandAirMech lam = (LandAirMech) client.getEntity(ce
                        .getId());

                lam.convertToMode(LandAirMech.MODE_MECH);
                updateTransformationButtons(lam);
                clientgui.mechD.displayEntity(lam);
            }
        } else if (ev.getActionCommand().equals(MOVE_MODE_AIRMECH)) {
            clearAllMoves();
            if (ce instanceof LandAirMech) {
                final LandAirMech lam = (LandAirMech) client.getEntity(ce
                        .getId());

                lam.convertToMode(LandAirMech.MODE_AIRMECH);
                updateTransformationButtons(lam);
                clientgui.mechD.displayEntity(lam);
            }
        } else if (ev.getActionCommand().equals(MOVE_MODE_AIRCRAFT)) {
            clearAllMoves();
            if (ce instanceof LandAirMech) {
                final LandAirMech lam = (LandAirMech) client.getEntity(ce
                        .getId());

                lam.convertToMode(LandAirMech.MODE_AIRCRAFT);
                updateTransformationButtons(lam);
                clientgui.mechD.displayEntity(lam);
            }
        } else if (ev.getActionCommand().equals(MOVE_ACCN)) {
            cmd.addStep(MovePath.STEP_ACCN);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_DECN)) {
            cmd.addStep(MovePath.STEP_DECN);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_ACC)) {
            cmd.addStep(MovePath.STEP_ACC);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_DEC)) {
            cmd.addStep(MovePath.STEP_DEC);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_EVADE)) {
            cmd.addStep(MovePath.STEP_EVADE);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_ROLL)) {
            cmd.addStep(MovePath.STEP_ROLL);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_HOVER)) {
            cmd.addStep(MovePath.STEP_HOVER);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_MANEUVER)) {
            ManeuverChoiceDialog choiceDialog = new ManeuverChoiceDialog(
                    clientgui.frame,
                    Messages
                            .getString("MovementDisplay.ManeuverDialog.title"), //$NON-NLS-1$
                    "huh?");
            Aero a = (Aero)ce;
            MoveStep last = cmd.getLastStep();
            int vel = a.getCurrentVelocity();
            int elev = a.getElevation();
            Coords pos = a.getPosition();
            int distance = 0;
            if(null != last) {
                vel = last.getVelocityLeft();
                elev = last.getElevation();
                pos = last.getPosition();
                distance = last.getDistance();
            }
            int ceil = client.game.getBoard().getHex(pos).ceiling();
            choiceDialog.checkPerformability(vel, elev, ceil, a.isVSTOL(), distance);
            choiceDialog.setVisible(true);
            int manType = choiceDialog.getChoice();
            if( manType > ManeuverType.MAN_NONE && addManeuver(manType) ) {
                clientgui.bv.drawMovementData(ce, cmd);
            }
        } else if (ev.getActionCommand().equals(MOVE_LAUNCH)) {
            //The function will bring up a choice dialog that
            //asks the user how many units of each type (small craft and
            //ASF) he wants to launch
            Vector<Integer[]> launched = getLaunchedUnits();
            cmd.addStep(MovePath.STEP_LAUNCH, launched);
            clientgui.bv.drawMovementData(ce, cmd);
        }  else if (ev.getActionCommand().equals(MOVE_RECOVER)) {
            //if more than one unit is available as a carrier
            //then bring up an option dialog
            int recoverer = getRecoveryUnit();
            if(recoverer != -1) {
                cmd.addStep(MovePath.STEP_RECOVER, recoverer);
                clientgui.bv.drawMovementData(ce, cmd);
            }
        } else if (ev.getActionCommand().equals(MOVE_TURN_LEFT)) {
            cmd.addStep(MovePath.STEP_TURN_LEFT);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_TURN_RIGHT)) {
            cmd.addStep(MovePath.STEP_TURN_RIGHT);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_THRUST)) {
            cmd.addStep(MovePath.STEP_THRUST);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_YAW)) {
            cmd.addStep(MovePath.STEP_YAW);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_END_OVER)) {
            cmd.addStep(MovePath.STEP_YAW);
            cmd.addStep(MovePath.STEP_ROLL);
            clientgui.bv.drawMovementData(ce, cmd);
        } else if (ev.getActionCommand().equals(MOVE_DUMP)) {
            dumpBombs();
        }

        updateProneButtons();
        updateRACButton();
        updateSearchlightButton();
        updateLoadButtons();
        updateElevationButtons();
        updateFleeButton();
        updateLaunchButton();
        updateHoverButton();
        updateManeuverButton();
        updateDumpButton();
        updateSpeedButtons();
        updateThrustButton();
        updateRollButton();
        checkFuel();
        checkOOC();
        checkAtmosphere();
    }

    /**
     * Give the player the opportunity to unload all entities that are stranded
     * on immobile transports. <p/> According to <a
     * href="http://www.classicbattletech.com/w3t/showflat.php?Cat=&Board=ask&Number=555466&page=2&view=collapsed&sb=5&o=0&fpart=">
     * Randall Bills</a>, the "minimum move" rule allow stranded units to
     * dismount at the start of the turn.
     */
    private void unloadStranded() {
        Vector<Entity> stranded = new Vector<Entity>();
        String[] names = null;
        Entity entity = null;
        Entity transport = null;

        // Let the player know what's going on.
        setStatusBarText(Messages.getString("MovementDisplay.AllPlayersUnload")); //$NON-NLS-1$

        // Collect the stranded entities into the vector.
        // TODO : get a better interface to "game" and "turn"
        Enumeration<Entity> entities = client
                .getSelectedEntities(new EntitySelector() {
                    private final IGame game = MovementDisplay.this.client.game;
                    private final GameTurn turn = MovementDisplay.this.client.game
                            .getTurn();
                    private final int ownerId = MovementDisplay.this.client
                            .getLocalPlayer().getId();

                    public boolean accept(Entity entity) {
                        if (turn.isValid(ownerId, entity, game))
                            return true;
                        return false;
                    }
                });
        while (entities.hasMoreElements()) {
            stranded.addElement(entities.nextElement());
        }

        // Construct an array of stranded entity names
        names = new String[stranded.size()];
        for (int index = 0; index < names.length; index++) {
            entity = stranded.elementAt(index);
            transport = client.getEntity(entity.getTransportId());
            String buffer;
            if (null == transport) {
                buffer = entity.getDisplayName();
            } else {
                buffer = Messages
                        .getString(
                                "MovementDisplay.EntityAt", new Object[] { entity.getDisplayName(), transport.getPosition().getBoardNum() }); //$NON-NLS-1$ 
            }
            names[index] = buffer.toString();
        }

        // Show the choices to the player

        int[] indexes = clientgui
                .doChoiceDialog(
                        Messages
                                .getString("MovementDisplay.UnloadStrandedUnitsDialog.title"), //$NON-NLS-1$
                        Messages
                                .getString("MovementDisplay.UnloadStrandedUnitsDialog.message"), //$NON-NLS-1$
                        names);

        // Convert the indexes into selected entity IDs and tell the server.
        int[] ids = null;
        if (null != indexes) {
            ids = new int[indexes.length];
            for (int index = 0; index < indexes.length; index++) {
                entity = stranded.elementAt(index);
                ids[index] = entity.getId();
            }
        }
        client.sendUnloadStranded(ids);
    }

    //
    // KeyListener
    //
    public void keyPressed(KeyEvent ev) {
        final Entity ce = ce();

        // Are we ignoring events?
        if (this.isIgnoringEvents()) {
            return;
        }
        if (ev.getKeyCode() == KeyEvent.VK_ESCAPE) {
            clearAllMoves();
        }
        if (ev.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
            if (client.isMyTurn()) {
                removeLastStep();
            }
        }
        if (ev.getKeyCode() == KeyEvent.VK_ENTER && ev.isControlDown()) {
            if (client.isMyTurn()) {
                moveTo(cmd);
            }
        }
        if (ev.getKeyCode() == KeyEvent.VK_SHIFT && !shiftheld) {
            shiftheld = true;
            if (client.isMyTurn()
                    && clientgui.getBoardView().getLastCursor() != null
                    && !clientgui.getBoardView().getLastCursor().equals(
                            clientgui.getBoardView().getSelected())) {
                // switch to turning
                // clientgui.bv.clearMovementData();
                currentMove(clientgui.getBoardView().getLastCursor());
                clientgui.bv.drawMovementData(ce, cmd);
            }
        }

        // arrow can also rotate when shift is down
        if (shiftheld
                && client.isMyTurn()
                && (ev.getKeyCode() == KeyEvent.VK_LEFT || ev.getKeyCode() == KeyEvent.VK_RIGHT)) {
            int curDir = cmd.getFinalFacing();
            int dir = curDir;
            if (ev.getKeyCode() == KeyEvent.VK_LEFT) {
                dir = (dir + 5) % 6;
            } else {
                dir = (dir + 7) % 6;
            }
            Coords curPos = cmd.getFinalCoords();
            Coords target = curPos.translated(dir);
            currentMove(target);
            clientgui.bv.drawMovementData(ce, cmd);
        }
    }

    public void keyReleased(KeyEvent ev) {

        // Are we ignoring events?
        if (this.isIgnoringEvents()) {
            return;
        }

        if (ev.getKeyCode() == KeyEvent.VK_SHIFT && shiftheld) {
            shiftheld = false;
            if (client.isMyTurn()
                    && clientgui.getBoardView().getLastCursor() != null
                    && !clientgui.getBoardView().getLastCursor().equals(
                            clientgui.getBoardView().getSelected())) {
                // switch to movement
                clientgui.bv.clearMovementData();
                currentMove(clientgui.getBoardView().getLastCursor());
                clientgui.bv.drawMovementData(ce(), cmd);
            }
        }
    }

    public void keyTyped(KeyEvent ev) {
    }

    // board view listener
    public void finishedMovingUnits(BoardViewEvent b) {
        final Entity ce = ce();

        // Are we ignoring events?
        if (this.isIgnoringEvents()) {
            return;
        }

        if (client.isMyTurn() && ce != null) {
            clientgui.setDisplayVisible(true);
            clientgui.bv.centerOnHex(ce.getPosition());
        }
    }

    public void unitSelected(BoardViewEvent b) {

        // Are we ignoring events?
        if (this.isIgnoringEvents()) {
            return;
        }

        Entity e = client.game.getEntity(b.getEntityId());
        if (null == e) {
            return;
        }
        if (client.isMyTurn()) {
            if (client.game.getTurn().isValidEntity(e, client.game)) {
                selectEntity(e.getId());
            }
        } else {
            clientgui.setDisplayVisible(true);
            clientgui.mechD.displayEntity(e);
            if (e.isDeployed()) {
                clientgui.bv.centerOnHex(e.getPosition());
            }
        }
    }

    private void setWalkEnabled(boolean enabled) {
        butWalk.setEnabled(enabled);
        clientgui.getMenuBar().setMoveWalkEnabled(enabled);
    }

    private void setTurnEnabled(boolean enabled) {
        butTurn.setEnabled(enabled);
        clientgui.getMenuBar().setMoveTurnEnabled(enabled);
    }

    private void setNextEnabled(boolean enabled) {
        butNext.setEnabled(enabled);
        clientgui.getMenuBar().setMoveNextEnabled(enabled);
    }

    private void setLayMineEnabled(boolean enabled) {
        butLayMine.setEnabled(enabled);
        clientgui.getMenuBar().setMoveLayMineEnabled(enabled);
    }

    private void setLoadEnabled(boolean enabled) {
        butLoad.setEnabled(enabled);
        clientgui.getMenuBar().setMoveLoadEnabled(enabled);
    }

    private void setUnloadEnabled(boolean enabled) {
        butUnload.setEnabled(enabled);
        clientgui.getMenuBar().setMoveUnloadEnabled(enabled);
    }

    private void setJumpEnabled(boolean enabled) {
        butJump.setEnabled(enabled);
        clientgui.getMenuBar().setMoveJumpEnabled(enabled);
    }

    private void setSwimEnabled(boolean enabled) {
        butSwim.setEnabled(enabled);
        clientgui.getMenuBar().setMoveSwimEnabled(enabled);
    }

    private void setBackUpEnabled(boolean enabled) {
        butBackup.setEnabled(enabled);
        clientgui.getMenuBar().setMoveBackUpEnabled(enabled);
    }

    private void setChargeEnabled(boolean enabled) {
        butCharge.setEnabled(enabled);
        clientgui.getMenuBar().setMoveChargeEnabled(enabled);
    }

    private void setDFAEnabled(boolean enabled) {
        butDfa.setEnabled(enabled);
        clientgui.getMenuBar().setMoveDFAEnabled(enabled);
    }

    private void setGoProneEnabled(boolean enabled) {
        butDown.setEnabled(enabled);
        clientgui.getMenuBar().setMoveGoProneEnabled(enabled);
    }

    private void setFleeEnabled(boolean enabled) {
        butFlee.setEnabled(enabled);
        clientgui.getMenuBar().setMoveFleeEnabled(enabled);
    }

    private void setEjectEnabled(boolean enabled) {
        butEject.setEnabled(enabled);
        clientgui.getMenuBar().setMoveEjectEnabled(enabled);
    }

    private void setUnjamEnabled(boolean enabled) {
        butRAC.setEnabled(enabled);
        clientgui.getMenuBar().setMoveUnjamEnabled(enabled);
    }

    private void setSearchlightEnabled(boolean enabled, boolean state) {
        if (state)
            butSearchlight.setLabel(Messages
                    .getString("MovementDisplay.butSearchlightOff")); //$NON-NLS-1$
        else
            butSearchlight.setLabel(Messages
                    .getString("MovementDisplay.butSearchlightOn")); //$NON-NLS-1$
        butSearchlight.setEnabled(enabled);
        clientgui.getMenuBar().setMoveSearchlightEnabled(enabled);
    }

    private void setHullDownEnabled(boolean enabled) {
        butHullDown.setEnabled(enabled);
        clientgui.getMenuBar().setMoveHullDownEnabled(enabled);
    }

    private void setClearEnabled(boolean enabled) {
        butClear.setEnabled(enabled);
        clientgui.getMenuBar().setMoveClearEnabled(enabled);
    }

    private void setGetUpEnabled(boolean enabled) {
        butUp.setEnabled(enabled);
        clientgui.getMenuBar().setMoveGetUpEnabled(enabled);
    }

    private void setRaiseEnabled(boolean enabled) {
        butRaise.setEnabled(enabled);
        clientgui.getMenuBar().setMoveRaiseEnabled(enabled);
    }

    private void setLowerEnabled(boolean enabled) {
        butLower.setEnabled(enabled);
        clientgui.getMenuBar().setMoveLowerEnabled(enabled);
    }

    private void setLAMmechModeEnabled(boolean enabled) {
        clientgui.getMenuBar().setMoveLAMmechModeEnabled(enabled);
    }

    private void setLAMairmechModeEnabled(boolean enabled) {
        clientgui.getMenuBar().setMoveLAMairmechModeEnabled(enabled);
    }

    private void setLAMaircraftModeEnabled(boolean enabled) {
        clientgui.getMenuBar().setMoveLAMaircraftModeEnabled(enabled);
    }
    private void setAccEnabled(boolean enabled) {
        butAcc.setEnabled(enabled);
        clientgui.getMenuBar().setMoveAccEnabled(enabled);
    }
    private void setDecEnabled(boolean enabled) {
        butDec.setEnabled(enabled);
        clientgui.getMenuBar().setMoveDecEnabled(enabled);
    }
    private void setAccNEnabled(boolean enabled) {
        butAccN.setEnabled(enabled);
        clientgui.getMenuBar().setMoveAccNEnabled(enabled);
    }
    private void setDecNEnabled(boolean enabled) {
        butDecN.setEnabled(enabled);
        clientgui.getMenuBar().setMoveDecNEnabled(enabled);
    }
    private void setEvadeEnabled(boolean enabled) {
        butEvade.setEnabled(enabled);
        clientgui.getMenuBar().setMoveEvadeEnabled(enabled);
    }
    private void setRollEnabled(boolean enabled) {
        butRoll.setEnabled(enabled);
        clientgui.getMenuBar().setMoveRollEnabled(enabled);
    }
    private void setLaunchEnabled(boolean enabled) {
        butLaunch.setEnabled(enabled);
        clientgui.getMenuBar().setMoveLaunchEnabled(enabled);
    }
    private void setRecoverEnabled(boolean enabled) {
        butRecover.setEnabled(enabled);
        clientgui.getMenuBar().setMoveRecoverEnabled(enabled);
    }
    private void setDumpEnabled(boolean enabled) {
        butDump.setEnabled(enabled);
        clientgui.getMenuBar().setMoveDumpEnabled(enabled);
    }
    private void setRamEnabled(boolean enabled) {
        butRam.setEnabled(enabled);
        clientgui.getMenuBar().setMoveRamEnabled(enabled);
    }
    private void setHoverEnabled(boolean enabled) {
        butHover.setEnabled(enabled);
        clientgui.getMenuBar().setMoveHoverEnabled(enabled);
    }
    private void setManeuverEnabled(boolean enabled) {
        butManeuver.setEnabled(enabled);
        clientgui.getMenuBar().setMoveManeuverEnabled(enabled);
    }
    private void setTurnLeftEnabled(boolean enabled) {
        butTurnLeft.setEnabled(enabled);
        clientgui.getMenuBar().setMoveTurnLeftEnabled(enabled);
    }
    private void setTurnRightEnabled(boolean enabled) {
        butTurnRight.setEnabled(enabled);
        clientgui.getMenuBar().setMoveTurnRightEnabled(enabled);
    }
    private void setThrustEnabled(boolean enabled) {
        butThrust.setEnabled(enabled);
        clientgui.getMenuBar().setMoveThrustEnabled(enabled);
    }
    private void setYawEnabled(boolean enabled) {
        butYaw.setEnabled(enabled);
        clientgui.getMenuBar().setMoveYawEnabled(enabled);
    }
    private void setEndOverEnabled(boolean enabled) {
        butEndOver.setEnabled(enabled);
        clientgui.getMenuBar().setMoveEndOverEnabled(enabled);
    }
    
    /**
     * Determine if the listener is currently distracted.
     * 
     * @return <code>true</code> if the listener is ignoring events.
     */
    public boolean isIgnoringEvents() {
        return this.distracted.isIgnoringEvents();
    }

    /**
     * Specify if the listener should be distracted.
     * 
     * @param distracted <code>true</code> if the listener should ignore
     *            events <code>false</code> if the listener should pay
     *            attention again. Events that occured while the listener was
     *            distracted NOT going to be processed.
     */
    public void setIgnoringEvents(boolean distracted) {
        this.distracted.setIgnoringEvents(distracted);
    }

    /**
     * Retrieve the "Done" button of this object.
     * 
     * @return the <code>java.awt.Button</code> that activates this object's
     *         "Done" action.
     */
    public Button getDoneButton() {
        return butDone;
    }

    /**
     * Stop just ignoring events and actually stop listening to them.
     */
    public void removeAllListeners() {
        client.game.removeGameListener(this);
        clientgui.getBoardView().removeBoardViewListener(this);
    }
    /*
     * Add steps for advanced vector movement based on the given vectors
     * when splitting hexes, choose the hex with less tonnage in case OOC
     */
    private MovePath addSteps(MovePath md, Entity en) {

        //if the last step is a launch or recovery, then I want to keep that at the end
        MoveStep lastStep = md.getLastStep();
        if(lastStep != null && (lastStep.getType() == MovePath.STEP_LAUNCH || lastStep.getType() == MovePath.STEP_RECOVER)) {
            md.removeLastStep();
        }
        
        //        get the start and end
        Coords start = en.getPosition();
        Coords end = Compute.getFinalPosition(start, md.getFinalVectors());
        //Coords end = md.getFinalVectors().getFinalPosition(start);
        
        //(see LosEffects.java)
        ArrayList<Coords> in = Coords.intervening(start, end);
        //first check whether we are splitting hexes
        boolean split = false;
        double degree = start.degree(end);
        if (degree % 60 == 30) {
            split = true;
            in = Coords.intervening(start, end, true);
        }
                
        Coords current = start;
        int facing = md.getFinalFacing();
        for (int i = 1; i < in.size(); i++) {
            
            
            //check for split hexes
            //check for some number after a multiple of 3 (1,4,7,etc)            
            if((i % 3) == 1 && split) {
                    
                Coords left = in.get(i);
                Coords right = in.get(i+1);
                    
                //get the total tonnage in each hex
                Enumeration<Entity> leftTargets = client.game.getEntities( left );
                double leftTonnage = 0;
                while ( leftTargets.hasMoreElements() ) { 
                    leftTonnage += leftTargets.nextElement().getWeight();
                }
                Enumeration<Entity> rightTargets = client.game.getEntities( right );
                double rightTonnage = 0;
                while ( rightTargets.hasMoreElements() ) { 
                    rightTonnage += rightTargets.nextElement().getWeight();
                }
                    
                //TODO: I will need to update this to account for asteroids
                    
                //I need to consider both of these passed through 
                //for purposes of bombing
                en.addPassedThrough(right);
                en.addPassedThrough(left);
                client.sendUpdateEntity(en);
                
                //if the left is preferred, increment i so next one is skipped
                if(leftTonnage < rightTonnage) {
                    i++;                    
                } else {                    
                    continue;
                }
                
            }
            
                
            Coords c = in.get(i);
                
            //check if the next move would put vessel off the map
            if(!client.game.getBoard().contains(c)) {
                md.addStep(MovePath.STEP_OFF);
                break;
            }
                
            //which direction is this from the current hex?
            int dir = current.direction(c);
            //what kind of step do I need to get there?
            int diff = dir - facing;
            if(diff == 0) {
                md.addStep(MovePath.STEP_FORWARDS);
            } else if (diff == 1 || diff == -5) {
                md.addStep(MovePath.STEP_LATERAL_RIGHT);
            } else if (diff == -2 || diff == 4) {
                md.addStep(MovePath.STEP_LATERAL_RIGHT_BACKWARDS);
            } else if (diff == -1 || diff == 5) {
                md.addStep(MovePath.STEP_LATERAL_LEFT);
            } else if (diff == 2 || diff == -4) {
                md.addStep(MovePath.STEP_LATERAL_LEFT_BACKWARDS);
            } else if (diff == 3 || diff == -3) {
                md.addStep(MovePath.STEP_BACKWARDS);
            }
            
            current = c;
                
        }
        
        //do I now need to add on the last step again?
        if(lastStep != null && lastStep.getType() == MovePath.STEP_LAUNCH) {
            md.addStep(MovePath.STEP_LAUNCH,lastStep.getLaunched());
        }
        
        if(lastStep != null && lastStep.getType() == MovePath.STEP_RECOVER) {
            md.addStep(MovePath.STEP_RECOVER,lastStep.getRecoveryUnit());
        }
        
        return md;
    }

}
