package net.sf.colossus.gui;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import net.sf.colossus.common.Constants;
import net.sf.colossus.game.Legion;
import net.sf.colossus.guiutil.KDialog;
import net.sf.colossus.guiutil.SaveWindow;
import net.sf.colossus.variant.CreatureType;
/**
* Class SplitLegion allows a player to split a Legion into two Legions.
*
* @author David Ripton
*/
final class SplitLegion extends KDialog
{
private final List<Chit> oldChits = new ArrayList<Chit>(8);
private final List<Chit> newChits = new ArrayList<Chit>(8);
private final Marker oldMarker;
private final Marker newMarker;
private final ClientGUI gui;
private static boolean active;
private List<CreatureType> creaturesToSplit;
private final Box oldBox;
private final Box newBox;
private final Box buttonBox;
private final JButton doneButton;
private final JButton cancelButton;
private final JButton skipButton;
private final int totalChits;
private final int scale;
private final SaveWindow saveWindow;
private SplitLegion(ClientGUI gui, Legion parent, String selectedMarkerId)
{
super(gui.getBoard().getFrame(), gui.getOwningPlayer().getName()
+ ": Split Legion " + parent, true);
Container contentPane = getContentPane();
contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
this.gui = gui;
if (selectedMarkerId == null)
{
// TODO this should probably just throw an exception or
// even use an assert statement
oldMarker = null;
newMarker = null;
oldBox = null;
newBox = null;
buttonBox = null;
doneButton = null;
cancelButton = null;
skipButton = null;
scale = 0;
totalChits = 0;
saveWindow = null;
dispose();
return;
}
setBackground(Color.lightGray);
addWindowListener(new WindowAdapter()
{
@Override
public void windowClosing(WindowEvent e)
{
cancel();
}
});
scale = 4 * Scale.get();
oldBox = new Box(BoxLayout.X_AXIS);
contentPane.add(oldBox);
newBox = new Box(BoxLayout.X_AXIS);
contentPane.add(newBox);
buttonBox = new Box(BoxLayout.X_AXIS);
contentPane.add(buttonBox);
oldMarker = new Marker(parent, scale, parent.getLongMarkerId());
oldBox.add(oldMarker);
oldBox.add(Box.createRigidArea(new Dimension(scale / 4, 0)));
oldBox.add(Box.createHorizontalGlue());
List<String> imageNames = gui.getClient().getLegionImageNames(parent);
totalChits = imageNames.size();
Iterator<String> it = imageNames.iterator();
while (it.hasNext())
{
String imageName = it.next();
final Chit chit = Chit.newCreatureChit(scale, imageName);
oldChits.add(chit);
oldBox.add(chit);
chit.addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent e)
{
int i = oldChits.indexOf(chit);
if (i != -1)
{
moveChitToOtherLine(oldChits, newChits, oldBox,
newBox, i);
}
else
{
i = newChits.indexOf(chit);
assert i != -1 : "Chit should be either in list of old or new chits.";
moveChitToOtherLine(newChits, oldChits, newBox,
oldBox, i);
}
}
});
}
// TODO XXX marker argument still missing!!!
newMarker = new Marker(null, scale, selectedMarkerId + "-"
+ parent.getPlayer().getColor().getName());
newBox.add(newMarker);
newBox.add(Box.createRigidArea(new Dimension(scale / 4, 0)));
newBox.add(Box.createHorizontalGlue());
// Add chit-sized invisible spacers.
for (int i = 0; i < totalChits; i++)
{
newBox.add(Box.createRigidArea(new Dimension(scale, scale)));
}
doneButton = new JButton("Done");
doneButton.setEnabled(false);
doneButton.setMnemonic(KeyEvent.VK_D);
doneButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (!isSplitLegal(true))
{
return;
}
returnSplitResults();
}
});
buttonBox.add(doneButton);
skipButton = new JButton("Skip");
skipButton.setMnemonic(KeyEvent.VK_S);
skipButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
markSkip();
}
});
if (gui.getGame().getTurnNumber() > 1)
{
// not much use to allowing mark as skip in first turn :)
buttonBox.add(skipButton);
}
cancelButton = new JButton("Cancel");
cancelButton.setMnemonic(KeyEvent.VK_C);
cancelButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
cancel();
}
});
buttonBox.add(cancelButton);
pack();
saveWindow = new SaveWindow(gui.getOptions(), "SplitLegion");
Point location = saveWindow.loadLocation();
if (location == null)
{
centerOnScreen();
}
else
{
setLocation(location);
}
setVisible(true);
}
/**
* Opens a dialog to select the creatures to split and returns the result.
*
* @return The list of creature types selected for the split or null if the split was cancelled.
*/
static List<CreatureType> splitLegion(ClientGUI gui, Legion parent,
String selectedMarkerId)
{
if (!active)
{
active = true;
SplitLegion dialog = new SplitLegion(gui, parent, selectedMarkerId);
active = false;
return dialog.creaturesToSplit;
}
return null;
}
/** Move a chit to the end of the other line. */
private void moveChitToOtherLine(List<Chit> fromChits, List<Chit> toChits,
Container fromBox, Container toBox, int oldPosition)
{
Chit chit = fromChits.remove(oldPosition);
fromBox.remove(chit);
fromBox.add(Box.createRigidArea(new Dimension(scale, 0)));
toBox.remove(toBox.getComponentCount() - 1);
toChits.add(chit);
// Account for the marker and the spacer.
toBox.add(chit, toChits.size() + 1);
doneButton.setEnabled(isSplitLegal(false));
pack();
repaint();
}
/** Return true if the split is legal. Each legion must have
* height >= 2. If this was an initial split, each legion
* must have height == 4 and one lord. */
private boolean isSplitLegal(boolean showMessage)
{
if (oldChits.size() < 2 || newChits.size() < 2)
{
if (showMessage)
{
gui.showMessageDialogAndWait("Legion too short.");
}
return false;
}
if (oldChits.size() + newChits.size() == 8)
{
if (oldChits.size() != newChits.size())
{
if (showMessage)
{
gui.showMessageDialogAndWait("Initial split must be 4-4.");
}
return false;
}
int numLords = 0;
Iterator<Chit> it = oldChits.iterator();
while (it.hasNext())
{
Chit chit = it.next();
String id = chit.getId();
if (id.startsWith(Constants.titan)
|| id.startsWith(gui.getGame().getVariant()
.getPrimaryAcquirable()))
{
numLords++;
}
}
if (numLords != 1)
{
if (showMessage)
{
gui.showMessageDialogAndWait("Each stack must have one lord.");
}
return false;
}
}
return true;
}
private void cancel()
{
creaturesToSplit = null;
dispose();
}
private void markSkip()
{
// empty list to signal: skip split.
creaturesToSplit = new ArrayList<CreatureType>();
dispose();
}
private void returnSplitResults()
{
creaturesToSplit = new ArrayList<CreatureType>();
Iterator<Chit> it = newChits.iterator();
while (it.hasNext())
{
Chit chit = it.next();
String creatureName = chit.getId();
if (creatureName.startsWith(Constants.titan))
{
creatureName = Constants.titan;
}
creaturesToSplit.add(gui.getGame().getVariant()
.getCreatureByName(creatureName));
}
dispose();
}
}