package magic.ui.screen.duel.game;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import magic.data.GeneralConfig;
import magic.model.MagicCardList;
import magic.model.MagicPlayerZone;
import magic.ui.ScreenController;
import magic.ui.duel.resolution.DefaultResolutionProfile;
import magic.ui.duel.resolution.ResolutionProfileResult;
import magic.ui.duel.resolution.ResolutionProfiles;
import magic.ui.duel.viewerinfo.CardViewerInfo;
import magic.ui.duel.viewerinfo.GameViewerInfo;
import magic.ui.duel.viewerinfo.PlayerViewerInfo;
import magic.ui.widget.ZoneBackgroundLabel;
import magic.ui.widget.duel.animation.GameLayoutInfo;
import magic.ui.widget.duel.sidebar.DuelSideBarPanel;
import magic.ui.widget.duel.viewer.ImageBattlefieldViewer;
import magic.ui.widget.duel.viewer.ImageCardListViewer;
import net.miginfocom.swing.MigLayout;
@SuppressWarnings("serial")
public final class DuelPanel extends JPanel {
private static final GeneralConfig CONFIG = GeneralConfig.getInstance();
private ZoneBackgroundLabel backgroundLabel;
private SwingGameController controller;
private DuelSideBarPanel sidebarPanel;
private BattlefieldPanel battlefieldPanel;
private ResolutionProfileResult result;
public DuelPanel() {
setOpaque(false);
setFocusable(true);
}
public void setController(final SwingGameController aController) {
this.controller = aController;
battlefieldPanel = new BattlefieldPanel(controller);
sidebarPanel = new DuelSideBarPanel(controller);
updateView();
createMouseListener();
// TODO: should not have to run this, but required while sidebarPanel is created after battlefieldPanel.
controller.notifyPlayerZoneChanged(controller.getViewerInfo().getPlayerInfo(false), MagicPlayerZone.HAND);
controller.setUserActionPanel(sidebarPanel.getGameStatusPanel().getUserActionPanel());
}
private void createMouseListener() {
//hide info when mouse moves onto background
addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
controller.hideInfo();
}
});
}
public boolean canClickAction() {
return sidebarPanel.getGameStatusPanel().getUserActionPanel().isActionEnabled();
}
public boolean canClickUndo() {
return sidebarPanel.getGameStatusPanel().getUserActionPanel().isUndoEnabled();
}
public SwingGameController getController() {
return controller;
}
public void focusViewers(final int handGraveyard) {
battlefieldPanel.focusViewers(handGraveyard);
}
public void showCards(final MagicCardList cards) {
battlefieldPanel.showCards(cards);
}
public void update(final GameViewerInfo gameInfo) {
assert SwingUtilities.isEventDispatchThread();
sidebarPanel.doUpdate(gameInfo);
battlefieldPanel.doUpdate();
}
void updateView() {
resizeComponents();
revalidate();
repaint();
}
public void close() {
ScreenController.getFrame().closeDuelScreen();
}
@Override
public void setSize(Dimension d) {
super.setSize(d);
resizeComponents();
}
public void resizeComponents() {
final Dimension size = getSize();
result = ResolutionProfiles.calculate(size);
backgroundLabel.setZones(result);
battlefieldPanel.resizeComponents(result);
setGamePanelLayout();
// defer until all pending events on the EDT have been processed.
// this ensures that cards layout is adjusted correctly if the screen is resized.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
update(controller.getViewerInfo());
}
});
}
/**
* The game screen layout is split into two columns using MigLayout.
* The LHS is a fixed-width column that uses MigLayout to position UI components.
* The RHS column represents the battlefield and uses absolute positioning.
*/
private void setGamePanelLayout() {
removeAll();
setLayout(new MigLayout("insets 0, gap 0, flowx"));
add(sidebarPanel, "w " + DefaultResolutionProfile.getPanelWidthLHS() +"!, h 100%");
add(battlefieldPanel, "w 100%, h 100%");
sidebarPanel.doSetLayout();
}
private void doThreadSleep(final long msecs) {
try {
Thread.sleep(msecs);
} catch (InterruptedException e) {
System.err.println(e);
}
}
// TODO: move up into GameController?
public void doNewTurnNotification(GameViewerInfo gameInfo) {
assert !SwingUtilities.isEventDispatchThread();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
sidebarPanel.getGameStatusPanel().showNewTurnNotification(gameInfo);
}
});
// TODO: do while gameStatusPanel.isBusy() { sleep(100); }
doThreadSleep(CONFIG.getNewTurnAlertDuration());
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
sidebarPanel.getGameStatusPanel().hideNewTurnNotification();
}
});
}
public void refreshSidebarLayout() {
sidebarPanel.refreshLayout();
}
public void doFlashPlayerHandZoneButton(PlayerViewerInfo aPlayer) {
sidebarPanel.doFlashPlayerHandZoneButton(aPlayer);
}
void doFlashLibraryZoneButton(PlayerViewerInfo aPlayer) {
sidebarPanel.doFlashLibraryZoneButton(aPlayer);
}
public void highlightCard(CardViewerInfo cardInfo, boolean b) {
switch (cardInfo.getLocation()) {
case Battlefield:
battlefieldPanel.highlightCard(cardInfo, b);
break;
case Graveyard:
sidebarPanel.doHighlightPlayerZone(cardInfo, MagicPlayerZone.GRAVEYARD, b);
break;
case Exile:
sidebarPanel.doHighlightPlayerZone(cardInfo, MagicPlayerZone.EXILE, b);
break;
case OwnersHand:
sidebarPanel.doHighlightPlayerZone(cardInfo, MagicPlayerZone.HAND, b);
break;
case OwnersLibrary:
sidebarPanel.doHighlightPlayerZone(cardInfo, MagicPlayerZone.LIBRARY, b);
break;
}
}
public Rectangle getBattlefieldPanelBounds() {
return battlefieldPanel.getBounds();
}
private Point getLocationOnDuelPanel(final JComponent component) {
final DuelPanel duelPanel = (DuelPanel)component.getParent().getParent();
return SwingUtilities.convertPoint(component.getParent(), component.getLocation(), duelPanel);
}
public GameLayoutInfo getLayoutInfo(final GameViewerInfo gameInfo, final CardViewerInfo cardInfo) {
assert SwingUtilities.isEventDispatchThread();
final GameLayoutInfo info = new GameLayoutInfo(this.getSize());
info.setTurnPanelLayout(sidebarPanel.getTurnPanelLayout(this));
for (PlayerViewerInfo playerInfo : gameInfo.getPlayers()) {
final int playerIndex = playerInfo.player.getIndex();
info.setLibraryButtonLayout(playerIndex, sidebarPanel.getLibraryButtonLayout(playerInfo, this));
info.setHandButtonLayout(playerIndex, sidebarPanel.getHandButtonLayout(playerInfo, this));
final ImageBattlefieldViewer battlefieldViewer = playerIndex == 0
? battlefieldPanel.imagePlayerPermanentViewer
: battlefieldPanel.imageOpponentPermanentViewer;
info.setPermanentsZoneLayout(
playerIndex,
new Rectangle(
getLocationOnDuelPanel(battlefieldViewer),
battlefieldViewer.getSize()
)
);
}
info.setStackLayout(sidebarPanel.getStackViewerRectangle(this));
setCardLayoutInfo(cardInfo, info);
return info;
}
private void setCardLayoutInfo(CardViewerInfo cardInfo, GameLayoutInfo info) {
if (cardInfo.isNotEmpty()) {
final ImageCardListViewer handViewer = controller.getPlayerZoneViewer().getImageCardsListViewer();
if (handViewer.getCardPosition(cardInfo) != null) {
info.setCardInHandLayout(
new Rectangle(
handViewer.getCardPosition(cardInfo),
handViewer.getCardSize())
);
}
}
}
void setBackgroundLabel(ZoneBackgroundLabel backgroundLabel) {
this.backgroundLabel = backgroundLabel;
}
}