/*
* MegaMekLab - Copyright (C) 2008
*
* Original author - jtighe (torren@users.sourceforge.net)
*
* 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 megameklab.com.ui.Aero.views;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import megamek.common.Aero;
import megamek.common.EquipmentType;
import megamek.common.verifier.TestAero;
import megameklab.com.ui.EntitySource;
import megameklab.com.util.IView;
import megameklab.com.util.RefreshListener;
public class ArmorView extends IView implements ChangeListener, ActionListener {
/**
*
*/
private static final long serialVersionUID = 799195356642563937L;
private JPanel mainPanel = new JPanel();
private JPanel nosePanel = new JPanel();
private JPanel lWingPanel = new JPanel();
private JPanel rWingPanel = new JPanel();
private JPanel aftPanel = new JPanel();
public SpinnerNumberModel noseArmorModel = new SpinnerNumberModel();
public SpinnerNumberModel lwArmorModel = new SpinnerNumberModel();
public SpinnerNumberModel rwArmorModel = new SpinnerNumberModel();
public SpinnerNumberModel aftArmorModel = new SpinnerNumberModel();
private JSpinner noseArmorField = new JSpinner(noseArmorModel);
private JSpinner lwArmorField = new JSpinner(lwArmorModel);
private JSpinner rwArmorField = new JSpinner(rwArmorModel);
private JSpinner aftArmorField = new JSpinner(aftArmorModel);
private List<JSpinner> armorFieldList = new ArrayList<JSpinner>();
private JLabel noseArmorMaxLabel = new JLabel("", SwingConstants.CENTER);
private JLabel lwArmorMaxLabel = new JLabel("", SwingConstants.CENTER);
private JLabel rwArmorMaxLabel = new JLabel("", SwingConstants.CENTER);
private JLabel aftArmorMaxLabel = new JLabel("", SwingConstants.CENTER);
private List<JLabel> armorMaxLabelList = new ArrayList<JLabel>();
private JLabel lblAllocatedArmor = new JLabel("Allocated Armor Points:");
private JTextField valueAllocatedArmor = new JTextField();
private JLabel lblUnallocatedArmor = new JLabel("Unallocated Armor Points:");
private JTextField valueUnallocatedArmor = new JTextField();
private JLabel lblCurrentArmor = new JLabel("Total Armor Points:");
private JTextField valueCurrentArmor = new JTextField();
private JLabel lblMaxArmor = new JLabel("Maximum Possible Armor Points:");
private JTextField valueMaxArmor = new JTextField();
private JLabel lblWastedArmor = new JLabel("Wasted Armor Points:");
private JTextField valueWastedArmor = new JTextField();
private int armorPoints;
private int wastedArmorPoints;
private JButton allocateArmorButton = new JButton("Auto-Allocate Armor");
private RefreshListener refresh;
public ArmorView(EntitySource eSource) {
super(eSource);
setLayout(new GridLayout(1, 1));
mainPanel.setLayout(new GridBagLayout());
GridBagConstraints gbc;
nosePanel.setLayout(new BoxLayout(nosePanel, BoxLayout.Y_AXIS));
rWingPanel.setLayout(new BoxLayout(rWingPanel, BoxLayout.Y_AXIS));
lWingPanel.setLayout(new BoxLayout(lWingPanel, BoxLayout.Y_AXIS));
aftPanel.setLayout(new BoxLayout(aftPanel, BoxLayout.Y_AXIS));
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 0;
mainPanel.add(nosePanel, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridheight = 2;
mainPanel.add(lWingPanel, gbc);
gbc.gridx = 1;
mainPanel.add(Box.createHorizontalStrut(nosePanel.getWidth()), gbc);
gbc.gridx = 2;
mainPanel.add(rWingPanel, gbc);
gbc.gridx = 1;
gbc.gridy = 3;
gbc.gridheight = 1;
mainPanel.add(aftPanel, gbc);
noseArmorField.setName(Integer.toString(Aero.LOC_NOSE));
rwArmorField.setName(Integer.toString(Aero.LOC_RWING));
lwArmorField.setName(Integer.toString(Aero.LOC_LWING));
aftArmorField.setName(Integer.toString(Aero.LOC_AFT));
armorFieldList.add(noseArmorField);
armorFieldList.add(rwArmorField);
armorFieldList.add(lwArmorField);
armorFieldList.add(aftArmorField);
Dimension size = new Dimension(40, 25);
for (JSpinner spinner : armorFieldList) {
spinner.setToolTipText("Armor");
// you don't set the size of the jspinner, but rather its internal
// textfield
((JSpinner.DefaultEditor) spinner.getEditor()).setSize(size);
((JSpinner.DefaultEditor) spinner.getEditor()).setMaximumSize(size);
((JSpinner.DefaultEditor) spinner.getEditor())
.setPreferredSize(size);
((JSpinner.DefaultEditor) spinner.getEditor()).setMinimumSize(size);
}
armorMaxLabelList.add(noseArmorMaxLabel);
armorMaxLabelList.add(lwArmorMaxLabel);
armorMaxLabelList.add(rwArmorMaxLabel);
armorMaxLabelList.add(aftArmorMaxLabel);
Dimension labelSize = new Dimension(80, 20);
for (JLabel label : armorMaxLabelList) {
label.setSize(labelSize);
label.setMaximumSize(labelSize);
label.setPreferredSize(labelSize);
label.setMinimumSize(labelSize);
}
addAllListeners();
JPanel topPanel;
synchronized (getAero()) {
for (int location = 0; location < getAero().locations(); location++) {
switch (location) {
case Aero.LOC_NOSE:
topPanel = new JPanel(new GridLayout(2, 0));
topPanel.add(noseArmorField);
topPanel.add(noseArmorMaxLabel);
nosePanel.add(topPanel);
nosePanel.setBorder(BorderFactory.createTitledBorder(
null, getAero().getLocationAbbr(location),
TitledBorder.TOP,
TitledBorder.DEFAULT_POSITION));
break;
case Aero.LOC_LWING:
topPanel = new JPanel(new GridLayout(2, 0));
topPanel.add(lwArmorField);
topPanel.add(lwArmorMaxLabel);
lWingPanel.add(topPanel);
lWingPanel.setBorder(BorderFactory.createTitledBorder(
null, getAero().getLocationAbbr(location),
TitledBorder.TOP,
TitledBorder.DEFAULT_POSITION));
break;
case Aero.LOC_RWING:
topPanel = new JPanel(new GridLayout(2, 0));
topPanel.add(rwArmorField);
topPanel.add(rwArmorMaxLabel);
rWingPanel.add(topPanel);
rWingPanel.setBorder(BorderFactory.createTitledBorder(
null, getAero().getLocationAbbr(location),
TitledBorder.TOP,
TitledBorder.DEFAULT_POSITION));
break;
case Aero.LOC_AFT:
topPanel = new JPanel(new GridLayout(2, 0));
topPanel.add(aftArmorField);
topPanel.add(aftArmorMaxLabel);
aftPanel.add(topPanel);
aftPanel.setBorder(BorderFactory.createTitledBorder(
null, getAero().getLocationAbbr(location),
TitledBorder.TOP,
TitledBorder.DEFAULT_POSITION));
break;
}
}
}
JPanel totalArmorPanel = new JPanel();
Vector<JTextField> valueFields = new Vector<JTextField>();
valueFields.add(valueUnallocatedArmor);
valueFields.add(valueAllocatedArmor);
valueFields.add(valueCurrentArmor);
valueFields.add(valueMaxArmor);
valueFields.add(valueWastedArmor);
Dimension valueSize = new Dimension(45, 20);
for (JTextField field : valueFields) {
field.setEditable(false);
field.setSize(valueSize);
field.setPreferredSize(valueSize);
field.setMinimumSize(valueSize);
field.setMaximumSize(valueSize);
field.setHorizontalAlignment(SwingConstants.RIGHT);
}
totalArmorPanel.setLayout(new GridBagLayout());
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.anchor = GridBagConstraints.WEST;
totalArmorPanel.add(lblUnallocatedArmor, gbc);
gbc.gridx = 1;
totalArmorPanel.add(valueUnallocatedArmor, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
totalArmorPanel.add(lblAllocatedArmor, gbc);
gbc.gridx = 1;
totalArmorPanel.add(valueAllocatedArmor, gbc);
gbc.gridx = 0;
gbc.gridy = 2;
totalArmorPanel.add(lblCurrentArmor, gbc);
gbc.gridx = 1;
totalArmorPanel.add(valueCurrentArmor, gbc);
gbc.gridx = 0;
gbc.gridy = 3;
totalArmorPanel.add(lblMaxArmor, gbc);
gbc.gridx = 1;
totalArmorPanel.add(valueMaxArmor, gbc);
gbc.gridx = 0;
gbc.gridy = 4;
totalArmorPanel.add(lblWastedArmor, gbc);
gbc.gridx = 1;
totalArmorPanel.add(valueWastedArmor, gbc);
gbc.gridx = 0;
gbc.gridy = 5;
gbc.gridwidth = 2;
gbc.anchor = GridBagConstraints.CENTER;
totalArmorPanel.add(allocateArmorButton, gbc);
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 4;
gbc.gridwidth = 5;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
mainPanel.add(totalArmorPanel, gbc);
this.add(mainPanel);
resetArmorPoints();
}
private void addAllListeners() {
allocateArmorButton.addActionListener(this);
for (JSpinner spinner : armorFieldList) {
spinner.addChangeListener(this);
}
}
private void removeAllListeners() {
allocateArmorButton.removeActionListener(this);
for (JSpinner spinner : armorFieldList) {
spinner.removeChangeListener(this);
}
}
public void refresh() {
removeAllListeners();
for (int location = 0; location < getAero().locations(); location++) {
int maxArmor = TestAero.maxArmorPoints(getAero(), getAero().getWeight());
switch (location) {
case Aero.LOC_NOSE:
noseArmorModel.setValue(
Math.min(maxArmor, getAero().getArmor(location)));
if (isFullyAllocated()) {
noseArmorModel.setMaximum(
(Integer) noseArmorModel.getValue());
} else {
noseArmorModel.setMaximum(maxArmor);
}
noseArmorModel.setStepSize(1);
noseArmorModel.setMinimum(0);
noseArmorMaxLabel.setText("max: " + maxArmor);
break;
case Aero.LOC_LWING:
lwArmorModel.setValue(
Math.min(maxArmor, getAero().getArmor(location)));
if (isFullyAllocated()) {
lwArmorModel.setMaximum(
(Integer) lwArmorModel.getValue());
} else {
lwArmorModel.setMaximum(maxArmor);
}
lwArmorModel.setStepSize(1);
lwArmorModel.setMinimum(0);
lwArmorMaxLabel.setText("max: " + maxArmor);
break;
case Aero.LOC_RWING:
rwArmorModel.setValue(
Math.min(maxArmor, getAero().getArmor(location)));
if (isFullyAllocated()) {
rwArmorModel.setMaximum(
(Integer) rwArmorModel.getValue());
} else {
rwArmorModel.setMaximum(maxArmor);
}
rwArmorModel.setStepSize(1);
rwArmorModel.setMinimum(0);
rwArmorMaxLabel.setText("max: " + maxArmor);
break;
case Aero.LOC_AFT:
aftArmorModel.setValue(
Math.min(maxArmor, getAero().getArmor(location)));
if (isFullyAllocated()) {
aftArmorModel.setMaximum(
(Integer) aftArmorModel.getValue());
} else {
aftArmorModel.setMaximum(maxArmor);
}
aftArmorModel.setStepSize(1);
aftArmorModel.setMinimum(0);
aftArmorMaxLabel.setText("max: " + maxArmor);
break;
}
}
valueAllocatedArmor.setText(Integer.toString(getAero().getTotalOArmor()));
valueUnallocatedArmor.setText(Integer.toString(armorPoints
- getAero().getTotalOArmor()));
if (armorPoints != getAero().getTotalOArmor()) {
valueUnallocatedArmor.setForeground(Color.RED);
lblUnallocatedArmor.setForeground(Color.RED);
} else {
valueUnallocatedArmor.setForeground(Color.BLACK);
lblUnallocatedArmor.setForeground(Color.BLACK);
}
valueCurrentArmor.setText(Integer.toString(armorPoints));
valueMaxArmor.setText("" + TestAero.maxArmorPoints(
getAero(), getAero().getWeight()));
valueWastedArmor.setText(Integer.toString(wastedArmorPoints));
addAllListeners();
}
public void addRefreshedListener(RefreshListener l) {
refresh = l;
}
public void allocateArmor() {
double pointsToAllocate = armorPoints;
double totalArmor = TestAero.maxArmorPoints(
getAero(), getAero().getWeight());
if (pointsToAllocate > totalArmor) {
pointsToAllocate = totalArmor;
}
double percent = pointsToAllocate / totalArmor;
// put 5 times the percentage of total possible armor into the head
for (int location = 0; location < getAero().locations(); location++) {
double IS = (getAero().getInternal(location) * 2);
double allocate = Math.min(IS * percent, pointsToAllocate);
getAero().initializeArmor((int) allocate, location);
pointsToAllocate -= (int) allocate;
}
allocateLeftoverPoints(pointsToAllocate);
if (refresh != null) {
refresh.refreshStatus();
}
}
/**
* allocate any leftover points one-by-one
*
* @param points
* the amount of points left over
*/
private void allocateLeftoverPoints(double points) {
int [] locs =
{Aero.LOC_NOSE, Aero.LOC_AFT, Aero.LOC_LWING, Aero.LOC_RWING};
int locIdx = 0;
while (points > 0){
int armor = getAero().getArmor(locs[locIdx]) + 1;
getAero().initializeArmor(armor, locs[locIdx]);
points--;
locIdx = (locIdx + 1) % locs.length;
}
}
public void stateChanged(ChangeEvent e) {
removeAllListeners();
JSpinner field = (JSpinner) e.getSource();
int location = Integer.parseInt(field.getName());
int value = (Integer) field.getModel().getValue();
getAero().initializeArmor(value, location);
if (getAero().hasPatchworkArmor()) {
setArmorPoints(getMech().getTotalArmor());
}
if (refresh != null) {
addAllListeners();
refresh.refreshStructure();
removeAllListeners();
refresh.refreshStatus();
}
addAllListeners();
}
public void setArmorPoints(int points) {
int maxArmor = TestAero.maxArmorPoints(getAero(), getAero().getWeight());
wastedArmorPoints = Math.max(points - maxArmor, 0);
armorPoints = Math.min(maxArmor, points);
}
private boolean isFullyAllocated() {
if (!getAero().hasPatchworkArmor()) {
return armorPoints == getAero().getTotalOArmor();
}
return false;
}
@Override
public void actionPerformed(ActionEvent e) {
removeAllListeners();
if (e.getSource().equals(allocateArmorButton)) {
allocateArmor();
}
addAllListeners();
refresh.refreshAll();
}
public void resetArmorPoints() {
double armorPerTon = 16.0 * EquipmentType.getArmorPointMultiplier(
getAero().getArmorType(0), getAero().getArmorTechLevel(0));
setArmorPoints((int) Math
.floor(getAero().getLabArmorTonnage() * armorPerTon));
}
}