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.getOriginalPermanent().getAttachments())) {
// Put this land to the left of lands with the same name and attachments.
insertIndex = i;
break;
}
List<CounterView> counters = firstPanel.getOriginalPermanent().getCounters();
if (counters != null && counters.size() > 0) {
// don't put to first panel if it has counters
insertIndex = i;
break;
}
if (!empty(permanent.getOriginalPermanent().getAttachments()) || stack.size() == landStackMax) {
// If this land has attachments or the stack is full, put it to the right.
insertIndex = i + 1;
continue;
}
counters = permanent.getOriginalPermanent().getCounters();
if (counters != null && counters.size() > 0) {
// if a land has counter, 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();
if (permanent.getOriginalPermanent().getAttachments() != null) {
stack.setMaxAttachedCount(permanent.getOriginalPermanent().getAttachments().size());
}
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);
Row allAttached = new Row(permanents, RowType.attached);
boolean othersOnTheRight = true;
if (options != null && options.containsKey("nonLandPermanentsInOnePile")) {
if (options.get("nonLandPermanentsInOnePile").equals("true")) {
othersOnTheRight = false;
allCreatures.addAll(allOthers);
allOthers.clear();
}
}
cardWidth = cardWidthMax;
Rectangle rect = battlefieldPanel.getVisibleRect();
playAreaWidth = rect.width;
playAreaHeight = rect.height;
while (true) {
rows.clear();
cardHeight = Math.round(cardWidth * CardPanel.ASPECT_RATIO);
extraCardSpacingX = Math.round(cardWidth * EXTRA_CARD_SPACING_X);
cardSpacingX = cardHeight - cardWidth + extraCardSpacingX;
cardSpacingY = Math.round(cardHeight * CARD_SPACING_Y);
stackSpacingX = stackVertical ? 0 : Math.round(cardWidth * STACK_SPACING_X);
stackSpacingY = Math.round(cardHeight * STACK_SPACING_Y);
attachmentSpacingY = Math.round(cardHeight * ATTACHMENT_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);
int afterLandsIndex = rows.size();
wrap(others, rows, afterLandsIndex);
// Store the current rows and others.
List<Row> storedRows = new ArrayList<>(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;
}
//FIXME: -1 is too slow. why not binary search?
cardWidth -= 3;
}
// 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);
}
// Position all card panels.
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 (othersOnTheRight && 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;
if (jPanel != null) {
jPanel.setComponentZOrder(panel, panelIndex);
}
int panelX = x + (stackPosition * stackSpacingX);
int panelY = y + (stackPosition * stackSpacingY);
try {
// may cause:
// java.lang.IllegalArgumentException: illegal component position 26 should be less then 26
battlefieldPanel.moveToFront(panel);
} catch (Exception e) {
e.printStackTrace();
}
panel.setCardBounds(panelX, panelY, cardWidth, cardHeight);
}
rowBottom = Math.max(rowBottom, y + stack.getHeight());
x += stack.getWidth();
}
y = rowBottom;
}
// we need this only for defining card size
// attached permanents will be handled separately
for (Stack stack : allAttached) {
for (MagePermanent panel : stack) {
panel.setCardBounds(0, 0, cardWidth, cardHeight);
}
}
return y;
}