package teamcomm.gui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.text.DecimalFormat;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.GroupLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
import teamcomm.data.RobotState;
import teamcomm.data.event.RobotStateEvent;
import teamcomm.data.event.RobotStateEventListener;
/**
* Class for the panel showing basic information about robots.
*
* @author Felix Thielke
*/
public class RobotPanel extends JPanel implements RobotStateEventListener {
private static final long serialVersionUID = 6656251707032959704L;
/**
* Width of a robot panel.
*/
public static final int PANEL_WIDTH = 175;
/**
* Height of a robot panel.
*/
public static final int PANEL_HEIGHT = 105;
private static final double MPS_LEGAL_THRESHOLD = 5.25;
private final RobotState robot;
private final RobotDetailFrame detailFrame;
private final JPanel foregroundPanel = new JPanel();
private final JLabel connectionStatus = new JLabel();
private final JLabel teamLogo = new JLabel((Icon) null, SwingConstants.CENTER);
private static final Color defaultColor = new JLabel("test").getForeground();
private static final String ICONS_PATH = "config/icons/";
private static final String ICON_ONLINE = "wlan_status_green.png";
private static final String ICON_OFFLINE = "wlan_status_red.png";
private static final String ICON_HIGH_LATENCY = "wlan_status_yellow.png";
private static ImageIcon iconOnline;
private static ImageIcon iconOffline;
private static ImageIcon iconHighLatency;
/**
* Constructor.
*
* @param robot robot to create the panel for
*/
public RobotPanel(final RobotState robot) {
super();
loadIcons();
this.robot = robot;
final RobotPanel robotPanel = this;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(getForeground()), robot.getAddress(), TitledBorder.CENTER, TitledBorder.TOP));
setLayout(new OverlayLayout(robotPanel));
setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
setMaximumSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
foregroundPanel.setLayout(new BoxLayout(foregroundPanel, BoxLayout.Y_AXIS));
foregroundPanel.setOpaque(false);
for (int i = 0; i < 4; i++) {
foregroundPanel.add(new JLabel(" ", JLabel.LEFT));
}
final JPanel foregroundContainer = new JPanel();
foregroundContainer.setOpaque(false);
final GroupLayout foregroundContainerLayout = new GroupLayout(foregroundContainer);
foregroundContainer.setLayout(foregroundContainerLayout);
foregroundContainerLayout.setHorizontalGroup(
foregroundContainerLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(foregroundPanel, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, PANEL_WIDTH, Short.MAX_VALUE)
);
foregroundContainerLayout.setVerticalGroup(
foregroundContainerLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(foregroundPanel, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, PANEL_HEIGHT, Short.MAX_VALUE)
);
add(foregroundContainer);
connectionStatus.setIcon(iconOnline);
final JPanel backgroundContainer = new JPanel();
backgroundContainer.setOpaque(false);
final GroupLayout backgroundContainerLayout = new GroupLayout(backgroundContainer);
backgroundContainer.setLayout(backgroundContainerLayout);
backgroundContainerLayout.setHorizontalGroup(
backgroundContainerLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(GroupLayout.Alignment.TRAILING, backgroundContainerLayout.createSequentialGroup()
.addGap(0, 220, Short.MAX_VALUE)
.addComponent(connectionStatus))
);
backgroundContainerLayout.setVerticalGroup(
backgroundContainerLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(backgroundContainerLayout.createSequentialGroup()
.addComponent(connectionStatus)
.addGap(0, 181, Short.MAX_VALUE))
);
add(backgroundContainer);
final JPanel backbackgroundContainer = new JPanel();
backbackgroundContainer.setOpaque(false);
final GroupLayout backbackgroundContainerLayout = new GroupLayout(backbackgroundContainer);
backbackgroundContainer.setLayout(backbackgroundContainerLayout);
backbackgroundContainerLayout.setHorizontalGroup(
backbackgroundContainerLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(teamLogo, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, PANEL_WIDTH, Short.MAX_VALUE)
);
backbackgroundContainerLayout.setVerticalGroup(
backbackgroundContainerLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(teamLogo, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, PANEL_HEIGHT, Short.MAX_VALUE)
);
add(backbackgroundContainer);
foregroundContainer.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(final ComponentEvent e) {
if (teamLogo.getIcon() != null) {
teamLogo.setIcon(TeamLogoLoader.getInstance().getScaledSemiTransparentTeamLogoIcon(robot.getTeamNumber(), Math.min((PANEL_WIDTH * 3) >> 2, foregroundPanel.getWidth()), Math.min((PANEL_HEIGHT * 3) >> 2, foregroundPanel.getHeight())));
}
}
});
update();
robot.addListener(robotPanel);
}
});
detailFrame = new RobotDetailFrame(robot, robotPanel);
}
@Override
public void robotStateChanged(final RobotStateEvent e) {
if (isVisible()) {
update();
}
}
@Override
public void connectionStatusChanged(final RobotStateEvent e) {
if (isVisible()) {
switch (robot.getConnectionStatus()) {
case HIGH_LATENCY:
connectionStatus.setIcon(iconHighLatency);
break;
case OFFLINE:
connectionStatus.setIcon(iconOffline);
break;
case ONLINE:
connectionStatus.setIcon(iconOnline);
}
}
}
/**
* Updates the panel with information of the given robot.
*/
private void update() {
final DecimalFormat df = new DecimalFormat("#.#####");
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (robot.getPlayerNumber() == null || (robot.getLastMessage() != null && !robot.getLastMessage().playerNumValid)) {
((JLabel) foregroundPanel.getComponent(0)).setForeground(Color.red);
((JLabel) foregroundPanel.getComponent(0)).setText("Player no: " + (robot.getLastMessage() != null ? robot.getLastMessage().playerNum : "invalid"));
} else {
((JLabel) foregroundPanel.getComponent(0)).setForeground(defaultColor);
((JLabel) foregroundPanel.getComponent(0)).setText("Player no: " + robot.getPlayerNumber());
}
((JLabel) foregroundPanel.getComponent(1)).setText("Messages: " + robot.getMessageCount());
final double mps = robot.getMessagesPerSecond();
if (mps >= MPS_LEGAL_THRESHOLD) {
((JLabel) foregroundPanel.getComponent(2)).setForeground(Color.red);
} else {
((JLabel) foregroundPanel.getComponent(2)).setForeground(defaultColor);
}
((JLabel) foregroundPanel.getComponent(2)).setText("Per second: " + df.format(mps));
if (robot.getLastMessage() == null || !robot.getLastMessage().valid) {
((JLabel) foregroundPanel.getComponent(3)).setForeground(Color.red);
} else {
((JLabel) foregroundPanel.getComponent(3)).setForeground(defaultColor);
}
((JLabel) foregroundPanel.getComponent(3)).setText("Illegal: " + robot.getIllegalMessageCount() + " (" + Math.round(robot.getIllegalMessageRatio() * 100.0) + "%)");
}
});
}
/**
* Toggle if the team logo shall be displayed in the background of the
* panel.
*
* @param toggle whether the team logo shall be displayeds
*/
public void setTeamLogoVisible(final boolean toggle) {
if (toggle) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
teamLogo.setIcon(TeamLogoLoader.getInstance().getScaledSemiTransparentTeamLogoIcon(robot.getTeamNumber(), Math.min((PANEL_WIDTH * 3) >> 2, Math.max(PANEL_WIDTH >> 2, foregroundPanel.getWidth())), Math.min((PANEL_HEIGHT * 3) >> 2, Math.max(PANEL_HEIGHT >> 2, foregroundPanel.getHeight()))));
}
});
} else {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
teamLogo.setIcon(null);
}
});
}
}
/**
* Releases resources of this panel.
*/
public void dispose() {
robot.removeListener(this);
detailFrame.destroy();
}
/**
* Returns the IP address of the robot associated with this panel.
*
* @return IP address
*/
public String getRobotAddress() {
return robot.getAddress();
}
private static void loadIcons() {
if (iconOnline == null) {
iconOnline = new ImageIcon(ICONS_PATH + ICON_ONLINE);
}
if (iconHighLatency == null) {
iconHighLatency = new ImageIcon(ICONS_PATH + ICON_HIGH_LATENCY);
}
if (iconOffline == null) {
iconOffline = new ImageIcon(ICONS_PATH + ICON_OFFLINE);
}
}
}