Package org.mage.plugins.card

Source Code of org.mage.plugins.card.CardPluginImpl

package org.mage.plugins.card;

import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLayeredPane;
import javax.swing.JScrollPane;

import mage.cards.Card;
import mage.cards.CardDimensions;
import mage.cards.MagePermanent;
import mage.cards.action.ActionCallback;
import mage.interfaces.plugin.CardPlugin;
import mage.utils.CardUtil;
import mage.view.CardView;
import mage.view.PermanentView;
import net.xeoh.plugins.base.annotations.PluginImplementation;
import net.xeoh.plugins.base.annotations.events.Init;
import net.xeoh.plugins.base.annotations.events.PluginLoaded;
import net.xeoh.plugins.base.annotations.meta.Author;

import org.apache.log4j.Logger;
import org.mage.card.arcane.Animation;
import org.mage.card.arcane.CardPanel;
import org.mage.card.arcane.ManaSymbols;
import org.mage.plugins.card.constants.Constants;
import org.mage.plugins.card.dl.DownloadGui;
import org.mage.plugins.card.dl.DownloadJob;
import org.mage.plugins.card.dl.Downloader;
import org.mage.plugins.card.dl.sources.GathererSymbols;
import org.mage.plugins.card.images.DownloadPictures;

/**
* {@link CardPlugin} implementation.
*
* @version 0.3 07.11.2010 Mage cards.
* @version 0.2 07.11.2010 Downloading images.
* @version 0.1 01.11.2010 Mage permanents. Sorting card layout.
* @author nantuko
*/
@PluginImplementation
@Author(name = "nantuko")
public class CardPluginImpl implements CardPlugin {

  private final static Logger log = Logger.getLogger(CardPluginImpl.class);

  static private final int GUTTER_Y = 15;
  static private final int GUTTER_X = 5;
  static final float EXTRA_CARD_SPACING_X = 0.04f;
  static private final float CARD_SPACING_Y = 0.03f;
  static private final float STACK_SPACING_X = 0.07f;
  static private final float STACK_SPACING_Y = 0.13f;
  static private final int MW_GUIDE_HEIGHT = 30;

  private int landStackMax = 5;
  private int cardWidthMin = 50, cardWidthMax = Constants.CARD_SIZE_FULL.width;
  private boolean stackVertical = false;

  private int playAreaWidth, playAreaHeight;
  private int cardWidth, cardHeight;
  private int extraCardSpacingX, cardSpacingX, cardSpacingY;
  private int stackSpacingX, stackSpacingY;
  private List<Row> rows = new ArrayList<Row>();

  @Init
  public void init() {
  }

  @PluginLoaded
  public void newPlugin(CardPlugin plugin) {
    ManaSymbols.loadImages();
    log.info(plugin.toString() + " has been loaded.");
  }

  public String toString() {
    return "[Card plugin, version 0.3]";
  }

  @Override
  public MagePermanent getMagePermanent(PermanentView permanent, CardDimensions dimension, UUID gameId, ActionCallback callback) {
    CardPanel cardPanel = new CardPanel(permanent, gameId, true, callback);
    cardPanel.setShowCastingCost(true);
    cardPanel.setCardBounds(0, 0, dimension.frameWidth, dimension.frameHeight);
    cardPanel.setShowCastingCost(true);
    return cardPanel;
  }
 
  @Override
  public MagePermanent getMageCard(CardView permanent, CardDimensions dimension, UUID gameId, ActionCallback callback) {
    CardPanel cardPanel = new CardPanel(permanent, gameId, true, callback);
    cardPanel.setShowCastingCost(true);
    cardPanel.setCardBounds(0, 0, dimension.frameWidth, dimension.frameHeight);
    cardPanel.setShowCastingCost(true);
    return cardPanel;
  }

  @Override
  public void sortPermanents(Map<String, JComponent> ui, Collection<MagePermanent> permanents) {
    if (ui == null)
      throw new RuntimeException("Error: no components");
    JComponent component = ui.get("jScrollPane");
    JComponent component2 = ui.get("battlefieldPanel");
    if (component == null)
      throw new RuntimeException("Error: jScrollPane is missing");
    if (component2 == null)
      throw new RuntimeException("Error: battlefieldPanel is missing");
    if (!(component instanceof JScrollPane))
      throw new RuntimeException("Error: jScrollPane has wrong type.");
    if (!(component instanceof JScrollPane))
      throw new RuntimeException("Error: battlefieldPanel is missing");
   
    JScrollPane jScrollPane = (JScrollPane)component;
    JLayeredPane battlefieldPanel = (JLayeredPane)component2;
   
    Row allLands = new Row();

    outerLoop: //
    for (MagePermanent permanent : permanents) {
      if (!CardUtil.isLand(permanent) || CardUtil.isCreature(permanent))
        continue;

      int insertIndex = -1;

      // Find lands with the same name.
      for (int i = 0, n = allLands.size(); i < n; i++) {
        Stack stack = allLands.get(i);
        MagePermanent firstPanel = stack.get(0);
        if (firstPanel.getOriginal().getName().equals(permanent.getOriginal().getName())) {
          if (!empty(firstPanel.getLinks())) {
            // Put this land to the left of lands with the same name and attachments.
            insertIndex = i;
            break;
          }
          if (!empty(permanent.getLinks()) || stack.size() == landStackMax) {
            // If this land has attachments or the stack is full, put it to the right.
            insertIndex = i + 1;
            continue;
          }
          // Add to stack.
          stack.add(0, permanent);
          continue outerLoop;
        }
        if (insertIndex != -1)
          break;
      }

      Stack stack = new Stack();
      stack.add(permanent);
      allLands.add(insertIndex == -1 ? allLands.size() : insertIndex, stack);
    }

    Row allCreatures = new Row(permanents, RowType.creature);
    Row allOthers = new Row(permanents, RowType.other);

    cardWidth = cardWidthMax;
    Rectangle rect = jScrollPane.getVisibleRect();
    playAreaWidth = rect.width;
    playAreaHeight = rect.height - MW_GUIDE_HEIGHT;
    while (true) {
      rows.clear();
      cardHeight = Math.round(cardWidth * CardPanel.ASPECT_RATIO);
      extraCardSpacingX = (int) Math.round(cardWidth * EXTRA_CARD_SPACING_X);
      cardSpacingX = cardHeight - cardWidth + extraCardSpacingX;
      cardSpacingY = (int) Math.round(cardHeight * CARD_SPACING_Y);
      stackSpacingX = stackVertical ? 0 : (int) Math.round(cardWidth * STACK_SPACING_X);
      stackSpacingY = (int) Math.round(cardHeight * STACK_SPACING_Y);
      Row creatures = (Row) allCreatures.clone();
      Row lands = (Row) allLands.clone();
      Row others = (Row) allOthers.clone();
      // Wrap all creatures and lands.
      wrap(creatures, rows, -1);
      int afterCreaturesIndex = rows.size();
      wrap(lands, rows, afterCreaturesIndex);
      // Store the current rows and others.
      List<Row> storedRows = new ArrayList<Row>(rows.size());
      for (Row row : rows)
        storedRows.add((Row) row.clone());
      Row storedOthers = (Row) others.clone();
      // Fill in all rows with others.
      for (Row row : rows)
        fillRow(others, rows, row);

      // Stop if everything fits, otherwise revert back to the stored values.
      if (creatures.isEmpty() && lands.isEmpty() && others.isEmpty())
        break;
      rows = storedRows;
      others = storedOthers;
      // Try to put others on their own row(s) and fill in the rest.
      wrap(others, rows, afterCreaturesIndex);
      for (Row row : rows)
        fillRow(others, rows, row);
      // If that still doesn't fit, scale down.
      if (creatures.isEmpty() && lands.isEmpty() && others.isEmpty())
        break;
      //cardWidth = (int)(cardWidth / 1.2);
      cardWidth--;
    }

    // Get size of all the rows.
    int x, y = GUTTER_Y;
    int maxRowWidth = 0;
    for (Row row : rows) {
      int rowBottom = 0;
      x = GUTTER_X;
      for (int stackIndex = 0, stackCount = row.size(); stackIndex < stackCount; stackIndex++) {
        Stack stack = row.get(stackIndex);
        rowBottom = Math.max(rowBottom, y + stack.getHeight());
        x += stack.getWidth();
      }
      y = rowBottom;
      maxRowWidth = Math.max(maxRowWidth, x);
    }
    //setPreferredSize(new Dimension(maxRowWidth - cardSpacingX, y - cardSpacingY));
    //revalidate();

    // Position all card panels.
    x = 0;
    y = GUTTER_Y;
    for (Row row : rows) {
      int rowBottom = 0;
      x = GUTTER_X;
      for (int stackIndex = 0, stackCount = row.size(); stackIndex < stackCount; stackIndex++) {
        Stack stack = row.get(stackIndex);
        // Align others to the right.
        if (RowType.other.isType(stack.get(0))) {
          x = playAreaWidth - GUTTER_X + extraCardSpacingX;
          for (int i = stackIndex, n = row.size(); i < n; i++)
            x -= row.get(i).getWidth();
        }
        for (int panelIndex = 0, panelCount = stack.size(); panelIndex < panelCount; panelIndex++) {
          MagePermanent panel = stack.get(panelIndex);
          int stackPosition = panelCount - panelIndex - 1;
          ///setComponentZOrder((Component)panel, panelIndex);
          int panelX = x + (stackPosition * stackSpacingX);
          int panelY = y + (stackPosition * stackSpacingY);
          //panel.setLocation(panelX, panelY);
          battlefieldPanel.moveToBack(panel);
          panel.setCardBounds(panelX, panelY, cardWidth, cardHeight);
        }
        rowBottom = Math.max(rowBottom, y + stack.getHeight());
        x += stack.getWidth();
      }
      y = rowBottom;
    }
  }
 
  private boolean empty(List<?> list) {
    return list == null || list.size() == 0;
  }
 
  private int wrap(Row sourceRow, List<Row> rows, int insertIndex) {
    // The cards are sure to fit (with vertical scrolling) at the minimum card width.
    boolean allowHeightOverflow = cardWidth == cardWidthMin;

    Row currentRow = new Row();
    for (int i = 0, n = sourceRow.size() - 1; i <= n; i++) {
      Stack stack = sourceRow.get(i);
      // If the row is not empty and this stack doesn't fit, add the row.
      int rowWidth = currentRow.getWidth();
      if (!currentRow.isEmpty() && rowWidth + stack.getWidth() > playAreaWidth) {
        // Stop processing if the row is too wide or tall.
        if (!allowHeightOverflow && rowWidth > playAreaWidth)
          break;
        if (!allowHeightOverflow && getRowsHeight(rows) + sourceRow.getHeight() > playAreaHeight)
          break;
        rows.add(insertIndex == -1 ? rows.size() : insertIndex, currentRow);
        currentRow = new Row();
      }
      currentRow.add(stack);
    }
    // Add the last row if it is not empty and it fits.
    if (!currentRow.isEmpty()) {
      int rowWidth = currentRow.getWidth();
      if (allowHeightOverflow || rowWidth <= playAreaWidth) {
        if (allowHeightOverflow || getRowsHeight(rows) + sourceRow.getHeight() <= playAreaHeight) {
          rows.add(insertIndex == -1 ? rows.size() : insertIndex, currentRow);
        }
      }
    }
    // Remove the wrapped stacks from the source row.
    for (Row row : rows)
      for (Stack stack : row)
        sourceRow.remove(stack);
    return insertIndex;
  }

  private void fillRow(Row sourceRow, List<Row> rows, Row row) {
    int rowWidth = row.getWidth();
    while (!sourceRow.isEmpty()) {
      Stack stack = sourceRow.get(0);
      rowWidth += stack.getWidth();
      if (rowWidth > playAreaWidth)
        break;
      if (stack.getHeight() > row.getHeight()) {
        if (getRowsHeight(rows) - row.getHeight() + stack.getHeight() > playAreaHeight)
          break;
      }
      row.add(sourceRow.remove(0));
    }
  }

  private int getRowsHeight(List<Row> rows) {
    int height = 0;
    for (Row row : rows)
      height += row.getHeight();
    return height - cardSpacingY + GUTTER_Y * 2;
  }

  static private enum RowType {
    land, creature, other;

    public boolean isType(MagePermanent card) {
      switch (this) {
      case land:
        return CardUtil.isLand(card);
      case creature:
        return CardUtil.isCreature(card);
      case other:
        return !CardUtil.isLand(card) && !CardUtil.isCreature(card);
      default:
        throw new RuntimeException("Unhandled type: " + this);
      }
    }
  }

  private class Row extends ArrayList<Stack> {
    public Row() {
      super(16);
    }

    public Row(Collection<MagePermanent> permanents, RowType type) {
      this();
      addAll(permanents, type);
    }

    private void addAll(Collection<MagePermanent> permanents, RowType type) {
      for (MagePermanent panel : permanents) {
        if (!type.isType(panel))
          continue;
        Stack stack = new Stack();
        stack.add(panel);
        add(stack);
      }
    }

    public boolean addAll(Collection<? extends Stack> c) {
      boolean changed = super.addAll(c);
      c.clear();
      return changed;
    }

    private int getWidth() {
      if (isEmpty())
        return 0;
      int width = 0;
      for (Stack stack : this)
        width += stack.getWidth();
      return width + GUTTER_X * 2 - extraCardSpacingX;
    }

    private int getHeight() {
      if (isEmpty())
        return 0;
      int height = 0;
      for (Stack stack : this)
        height = Math.max(height, stack.getHeight());
      return height;
    }
  }

  private class Stack extends ArrayList<MagePermanent> {
    public Stack() {
      super(8);
    }

    public boolean add(MagePermanent panel) {
      boolean appended = super.add(panel);
      //for (CardPanel attachedPanel : panel.attachedPanels)
      //add(attachedPanel);
      return appended;
    }

    private int getWidth() {
      return cardWidth + (size() - 1) * stackSpacingX + cardSpacingX;
    }

    private int getHeight() {
      return cardHeight + (size() - 1) * stackSpacingY + cardSpacingY;
    }
  }

  @Override
  public void downloadImages(Set<Card> allCards) {
    DownloadPictures.startDownload(null, allCards);
  }
 
  @Override
  public void downloadSymbols() {
    final DownloadGui g = new DownloadGui(new Downloader());

    Iterable<DownloadJob> it = new GathererSymbols();
       
        for(DownloadJob job:it) {
            g.getDownloader().add(job);
        }
   
    JDialog d = new JDialog((Frame) null, "Download pictures", false);
    d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    d.addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosing(WindowEvent e) {
        g.getDownloader().dispose();
      }
    });
    d.setLayout(new BorderLayout());
    d.add(g);
    d.pack();
    d.setVisible(true);   
  }

  @Override
  public Image getManaSymbolImage(String symbol) {
    return ManaSymbols.getManaSymbolImage(symbol);
  }

  @Override
  public void onAddCard(MagePermanent card) {
    if (card != null) {
      Animation.showCard((CardPanel) card);
      try {
        while ((card).getAlpha() + 0.05f < 1) {
          Thread.sleep(30);
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  @Override
  public void onRemoveCard(MagePermanent card) {
    if (card != null) {
      Animation.hideCard((CardPanel) card);
      try {
        while ((card).getAlpha() - 0.05f > 0) {
          Thread.sleep(30);
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}
TOP

Related Classes of org.mage.plugins.card.CardPluginImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.