package magic.ui.widget.duel.viewer;
import magic.ui.utility.ImageDrawingUtils;
import magic.ui.IChoiceViewer;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import magic.data.GeneralConfig;
import magic.model.MagicType;
import magic.model.MagicCard;
import magic.model.MagicCardDefinition;
import magic.model.MagicCardList;
import magic.ui.MagicImages;
import magic.ui.helpers.ImageHelper;
import magic.ui.screen.duel.game.SwingGameController;
import magic.ui.duel.viewerinfo.CardViewerInfo;
import magic.ui.theme.Theme;
import magic.ui.theme.ThemeFactory;
import magic.ui.FontsAndBorders;
import magic.ui.utility.MagicStyle;
@SuppressWarnings("serial")
public class ImageCardListViewer extends JPanel implements IChoiceViewer {
private static final GeneralConfig CONFIG = GeneralConfig.getInstance();
private static final MagicCardList EMPTY_CARD_LIST=new MagicCardList();
private static final int CARD_WIDTH=100;
private static final int CARD_HEIGHT=140;
private static final int SPACING=10;
private static final BasicStroke MOUSE_OVER_STROKE = new BasicStroke(2);
private static final Color MOUSE_OVER_COLOR = MagicStyle.getRolloverColor();
private static final Color MOUSE_OVER_TCOLOR = MagicStyle.getTranslucentColor(MOUSE_OVER_COLOR, 20);
private final SwingGameController controller;
private MagicCardList cardList;
private List<Point> cardPoints;
private Set<?> validChoices;
private boolean showInfo;
private int currentCardIndex = 0;
private int cardStep = 0;
public ImageCardListViewer(final SwingGameController controller) {
setOpaque(false);
this.controller=controller;
cardList=EMPTY_CARD_LIST;
cardPoints = new ArrayList<>();
validChoices=Collections.emptySet();
setMouseListener();
setMouseMotionListener();
setMouseWheelListener();
controller.registerChoiceViewer(this);
}
private void setMouseWheelListener() {
addMouseWheelListener(new MouseWheelListener() {
@Override
public void mouseWheelMoved(MouseWheelEvent event) {
final int cardIndex = getCardIndexAt(event.getX(), event.getY());
if (event.getWheelRotation() < 0) { // rotate mousewheel forward
if (cardIndex >= 0) {
showCardPopup(cardIndex);
}
} else if (event.getWheelRotation() > 0) { // rotate mousewheel back
if (cardIndex >= 0) {
controller.hideInfo();
}
}
}
});
}
private void setMouseMotionListener() {
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(final MouseEvent event) {
final int cardIndex = getCardIndexAt(event.getX(), event.getY());
final boolean isCardChanged = (currentCardIndex != cardIndex);
if (cardIndex >= 0) {
if (isCardChanged) {
if (!CONFIG.isMouseWheelPopup() || controller.isPopupVisible()) {
showCardPopup(cardIndex);
} else {
// handles case where mousewheel popup is enabled and the mouseExited
// event does not fire because cards overlap.
controller.hideInfo();
}
}
} else if (isCardChanged) {
controller.hideInfo();
}
if (isCardChanged) {
// highlight new card mouse cursor is over.
currentCardIndex = cardIndex;
repaint();
}
}
});
}
private void setMouseListener() {
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(final MouseEvent event) {
if (CONFIG.isTouchscreen()) {
final int cardIndex = getCardIndexAt(event.getX(), event.getY());
final boolean isDoubleClick = event.getClickCount() == 2;
if (cardIndex >= 0 && isDoubleClick) {
controller.processClick(cardList.get(cardIndex));
controller.hideInfo();
}
}
}
@Override
public void mouseReleased(MouseEvent event) {
if (!CONFIG.isTouchscreen()) {
if (ImageCardListViewer.this.contains(event.getPoint())) {
if (SwingUtilities.isRightMouseButton(event)) {
controller.actionKeyPressed();
} else if (SwingUtilities.isLeftMouseButton(event)) {
final int cardIndex = getCardIndexAt(event.getX(), event.getY());
if (cardIndex >= 0) {
controller.processClick(cardList.get(cardIndex));
}
}
}
}
}
@Override
public void mouseExited(final MouseEvent event) {
controller.hideInfo();
// unselect card and remove highlight.
currentCardIndex = -1;
repaint();
}
@Override
public void mouseEntered(MouseEvent e) {
// highlight card mouse cursor is over.
repaint();
}
});
}
private void showCardPopup(int index) {
final MagicCard card=cardList.get(index);
final Point pointOnScreen=getLocationOnScreen();
final Point point=cardPoints.get(index);
final Rectangle rect=
new Rectangle(pointOnScreen.x+point.x,pointOnScreen.y+point.y,CARD_WIDTH,CARD_HEIGHT);
controller.viewCardPopup(card, rect, true);
}
private int getCardIndexAt(final int x,final int y) {
for (int index=cardPoints.size()-1;index>=0;index--) {
final Point point=cardPoints.get(index);
if (x>=point.x&&y>=point.y&&x<point.x+CARD_WIDTH&&y<point.y+CARD_HEIGHT) {
return index;
}
}
return -1;
}
public void setCardList(final MagicCardList aCardList,final boolean aShowInfo) {
final List<Point> tCardPoints=new ArrayList<Point>();
final int cardCount = aCardList.size();
final int preferredWidth = CARD_WIDTH * cardCount + (cardCount - 1) * SPACING;
int availableWidth = getWidth();
int step;
if (preferredWidth <availableWidth ||cardCount ==1) {
int x=0;
step = CARD_WIDTH + SPACING;
for (int index=0;index<cardCount ;index++) {
tCardPoints.add(new Point(x,1));
x+=step;
}
} else {
step = (availableWidth - CARD_WIDTH) / (cardCount - 1);
int x = 0;
for (int index=0;index<cardCount ;index++) {
tCardPoints.add(new Point(x, 1));
x += step;
}
}
this.cardStep = step > CARD_WIDTH ? CARD_WIDTH : step;
this.cardList=aCardList;
this.cardPoints=tCardPoints;
this.showInfo=aShowInfo;
}
@Override
public void paintComponent(final Graphics g) {
if (cardList.isEmpty()) {
return;
}
g.setFont(FontsAndBorders.FONT1);
final FontMetrics metrics=g.getFontMetrics();
final Graphics2D g2d=(Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
final Stroke defaultStroke = g2d.getStroke();
final Point mousePoint = MouseInfo.getPointerInfo().getLocation();
SwingUtilities.convertPointFromScreen(mousePoint, this);
Rectangle mouseOverRect = new Rectangle();
for (int index=0; index < cardList.size(); index++) {
final MagicCard card=cardList.get(index);
final MagicCardDefinition cardDefinition=card.getCardDefinition();
final Point point=cardPoints.get(index);
final int x1=point.x;
final int y1=point.y;
final int x2=point.x+CARD_WIDTH;
final int y2=point.y+CARD_HEIGHT;
final BufferedImage image = ImageHelper.scale(
MagicImages.getCardImage(cardDefinition),
CARD_WIDTH,
CARD_HEIGHT
);
g2d.drawImage(image, x1, y1, this);
ImageDrawingUtils.drawCardId(g, card.getId(), x1, 0);
//draw the overlay icons
if (showInfo) {
if (cardDefinition.isLand()) {
ImageDrawingUtils.drawManaInfo(
g,
this,
cardDefinition.getManaActivations(),
card.hasType(MagicType.Snow),
x1+1,
y2-17
);
} else {
ImageDrawingUtils.drawCostInfo(g,this,card.getGameCost(),x1,x2-1,y1+2);
}
if (cardDefinition.isCreature()) {
ImageDrawingUtils.drawAbilityInfo(g,this,cardDefinition.genAbilityFlags(),x1+2,y2-18);
final String pt = card.genPowerToughness().toString();
final int ptWidth=metrics.stringWidth(pt);
ImageDrawingUtils.drawCreatureInfo(g,metrics,pt,ptWidth,"","",x2-ptWidth-4,y2-18,false);
}
}
//show that card is a valid choice
if (validChoices.contains(card)) {
if (CONFIG.isHighlightOverlay() ||
(CONFIG.isHighlightTheme() &&
ThemeFactory.getInstance().getCurrentTheme().getOptionUseOverlay())) {
final Color choiceColor = ThemeFactory.getInstance().getCurrentTheme().getChoiceColor();
//draw a transparent overlay of choiceColor
g2d.setPaint(choiceColor);
g2d.fillRect(x1-1,y1-1,CARD_WIDTH+2,CARD_HEIGHT+2);
}
else if (!CONFIG.isHighlightNone()){
final Color choiceColor = ThemeFactory.getInstance().getCurrentTheme().getColor(Theme.COLOR_CHOICE_BORDER);
//draw a one pixel border of choiceColor
g2d.setPaint(new Color(choiceColor.getRGB()));
final Stroke stroke = g2d.getStroke();
g2d.setStroke(new BasicStroke(2));
g2d.drawRect(x1,y1,CARD_WIDTH-1,CARD_HEIGHT);
g2d.setStroke(stroke);
}
}
final int highlightWidth = (index == cardList.size()-1) ? CARD_WIDTH : cardStep;
final Rectangle rect = new Rectangle(x1, y1, highlightWidth, y2 - y1);
if (rect.contains(mousePoint)) {
mouseOverRect = rect;
}
}
paintMouseOverHighlight2(g2d, mouseOverRect, defaultStroke);
}
/**
* draw filled rectangle using translucent color over visible portion of card.
*/
private void paintMouseOverHighlight2(final Graphics2D g2d, final Rectangle rect, final Stroke defaultStroke) {
g2d.setPaint(MOUSE_OVER_TCOLOR);
g2d.fillRect(rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2);
}
@Override
public void showValidChoices(final Set<?> aValidChoices) {
this.validChoices=aValidChoices;
repaint();
}
public Point getCardPosition(final CardViewerInfo cardInfo) {
Point cardPosition = null;
for (int index=0; index < cardList.size(); index++) {
final MagicCard card = cardList.get(index);
if (card.getId() == cardInfo.getId()) {
cardPosition = cardPoints.get(index);
break;
}
}
if (cardPosition != null) {
cardPosition = new Point(
cardPosition.x + getParent().getParent().getLocation().x + 45,
cardPosition.y + getParent().getLocation().y);
}
return cardPosition;
}
public Dimension getCardSize() {
return new Dimension(CARD_WIDTH, CARD_HEIGHT);
}
}