package org.leumasjaffe.charsheet.view.level; import javax.swing.JPanel; import org.jdesktop.swingx.VerticalLayout; import org.leumasjaffe.charsheet.model.magic.DDSpell; import org.leumasjaffe.charsheet.model.observable.BoolGate; import org.leumasjaffe.charsheet.model.observable.IntValue; import org.leumasjaffe.charsheet.view.magic.SelectSpellsPanel; import org.leumasjaffe.charsheet.view.magic.SelectSpellsPanel.Info; import org.leumasjaffe.observer.ObservableListener; import org.leumasjaffe.observer.ObserverDispatch; import lombok.AccessLevel; import lombok.Getter; import lombok.experimental.FieldDefaults; import lombok.experimental.NonFinal; import java.awt.GridBagLayout; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.TreeMap; import javax.swing.JScrollPane; import java.awt.GridBagConstraints; @SuppressWarnings("serial") @FieldDefaults(level=AccessLevel.PUBLIC, makeFinal=true) class LevelUpSpellPanel extends JPanel { public static interface SpellPicker { public List> getSpellCounts(SelectSpellsPanel.Info info); public Collection getAvailableSpells(SelectSpellsPanel.Info info, int i); } public static enum SpellPickType implements SpellPicker { LEARN { @Override public List> getSpellCounts(SelectSpellsPanel.Info info) { return info.dclass.getProto().getSpells().get().getKnown(); } @Override public Collection getAvailableSpells(Info info, int i) { Collection spells = new ArrayList<>(info.dclass.getProto().getSpellList(i)); spells.removeAll(info.dclass.getSpellBook().get().spellsKnownAtLevel(i)); return spells; } }, PREPARE { @Override public List> getSpellCounts(SelectSpellsPanel.Info info) { // TODO: Bonus spells for high ability scores return info.dclass.getProto().getSpells().get().getPerDay(); } @Override public Collection getAvailableSpells(Info info, int i) { return info.dclass.getSpellBook().get().spellsKnownAtLevel(i); } }; } int[] ready = {0}; @NonFinal int spellLevelsGrown = 0; int oldHighestSpellLevel, newHighestSpellLevel, toLevel; SpellPicker pick; SelectSpellsPanel.Info info; @Getter List panels; ObservableListener allReady; public LevelUpSpellPanel(SpellPicker pick, SelectSpellsPanel.Info info, BoolGate.Handle readyCount) { this.pick = pick; this.info = info; this.toLevel = info.dclass.getLevel().value(); newHighestSpellLevel = info.dclass.getHighestSpellLevel(toLevel); oldHighestSpellLevel = info.dclass.getHighestSpellLevel(toLevel-1); GridBagLayout gridBagLayout = new GridBagLayout(); gridBagLayout.columnWidths = new int[]{0, 0}; gridBagLayout.rowHeights = new int[]{0, 0}; gridBagLayout.columnWeights = new double[]{1.0, Double.MIN_VALUE}; gridBagLayout.rowWeights = new double[]{1.0, Double.MIN_VALUE}; setLayout(gridBagLayout); JScrollPane scrollPane = new JScrollPane(); GridBagConstraints gbc_scrollPane = new GridBagConstraints(); gbc_scrollPane.fill = GridBagConstraints.BOTH; gbc_scrollPane.gridx = 0; gbc_scrollPane.gridy = 0; add(scrollPane, gbc_scrollPane); JPanel panel = new JPanel(new VerticalLayout(5)); scrollPane.setViewportView(panel); panels = new ArrayList<>(); final IntValue val = getSharedAllowedSlots(info); final Map spells = getNewSpells(val); final int sharedSlots = val.value(); BoolGate gate = new BoolGate(newHighestSpellLevel); for (int i = 0; i < newHighestSpellLevel; ++i) { if (spells.get(i) < 0) { gate.set(i, true); panels.add(null); continue; } ++spellLevelsGrown; SelectSpellsPanel lvl = new SelectSpellsPanel(info, gate.handle(i), i, new LinkedHashSet<>(), Math.max(spells.get(i), sharedSlots), pick.getAvailableSpells(info, i), pick != SpellPickType.LEARN, val); panels.add(lvl); panel.add(lvl); } allReady = new ObservableListener<>(this, (c, v) -> { readyCount.set(this, v.all()); }); allReady.setObserved(gate); } private Map getNewSpells(IntValue sharedSpellCountLimit) { final Map map = new TreeMap<>(); final List> spellList = pick.getSpellCounts(info); final List spellsAtPreviousLevel = toLevel == 1 ? Collections.emptyList() : spellList.get(toLevel-2); final List spellsAtCurrentLevel = spellList.get(toLevel-1); for (int i = 0; i < newHighestSpellLevel; ++i) { map.put(i, diff(spellsAtCurrentLevel, spellsAtPreviousLevel, i, isNewSpellCircle(i))); } if (!map.isEmpty()) sharedSpellCountLimit.value(-1); return map; } private IntValue getSharedAllowedSlots(Info info) { return info.dclass.getSpellBook().get().getSharedAllowedSlots(); } private boolean isNewSpellCircle(int i) { return i == (newHighestSpellLevel - 1) && oldHighestSpellLevel != newHighestSpellLevel; } private int diff(List current, List previous, int level, boolean newSpellLevel) { if (current.size() <= level) return 0; else if (newSpellLevel || previous.size() <= level) return current.get(level); else return current.get(level) - previous.get(level); } @Override public void removeNotify() { ObserverDispatch.unsubscribeAll(allReady); } }