package com.songoda.ultimatetimber.tree; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class TreeBlockSet implements Collection { private final ITreeBlock initialLogBlock; private List> logBlocks; private final List> leafBlocks; public TreeBlockSet() { this.initialLogBlock = null; this.logBlocks = new LinkedList<>(); this.leafBlocks = new LinkedList<>(); } public TreeBlockSet(ITreeBlock initialLogBlock) { this.initialLogBlock = initialLogBlock; this.logBlocks = new LinkedList<>(); this.leafBlocks = new LinkedList<>(); if (initialLogBlock != null) { this.logBlocks.add(initialLogBlock); } } /** * Gets the TreeBlock that initiated the tree topple * * @return The TreeBlock of the initial topple point */ public ITreeBlock getInitialLogBlock() { return this.initialLogBlock; } /** * Gets all logs in this TreeBlockSet * * @return A Set of TreeBlocks */ public List> getLogBlocks() { return Collections.unmodifiableList(this.logBlocks); } /** * Gets all leaves in this TreeBlockSet * * @return A Set of TreeBlocks */ public List> getLeafBlocks() { return Collections.unmodifiableList(this.leafBlocks); } /** * Gets all blocks in this TreeBlockSet * * @return A Set of all TreeBlocks */ public Set> getAllTreeBlocks() { Set> treeBlocks = new HashSet<>(); treeBlocks.addAll(this.logBlocks); treeBlocks.addAll(this.leafBlocks); return treeBlocks; } @Override public int size() { return this.logBlocks.size() + this.leafBlocks.size(); } @Override public boolean isEmpty() { return this.logBlocks.isEmpty() && this.leafBlocks.isEmpty(); } @Override public boolean contains(Object o) { return this.logBlocks.contains(o) || this.leafBlocks.contains(o); } @Override public Iterator iterator() { return this.getAllTreeBlocks().iterator(); } @Override public Object[] toArray() { return this.getAllTreeBlocks().toArray(); } @Override @SuppressWarnings("unchecked") public boolean add(Object o) { if (!(o instanceof ITreeBlock)) { return false; } ITreeBlock treeBlock = (ITreeBlock) o; switch (treeBlock.getTreeBlockType()) { case LOG: return this.logBlocks.add(treeBlock); case LEAF: return this.leafBlocks.add(treeBlock); } return false; } @Override public boolean remove(Object o) { if (!(o instanceof ITreeBlock)) { return false; } ITreeBlock treeBlock = (ITreeBlock) o; switch (treeBlock.getTreeBlockType()) { case LOG: return this.logBlocks.remove(treeBlock); case LEAF: return this.leafBlocks.remove(treeBlock); } return false; } @Override public boolean addAll(Collection c) { boolean allAdded = true; for (Object o : c) { if (!this.add(o)) { allAdded = false; } } return allAdded; } @Override public void clear() { this.logBlocks.clear(); this.leafBlocks.clear(); } @Override public boolean retainAll(Collection c) { boolean retainedAll = true; for (Object o : c) { if (!this.contains(o)) { this.remove(o); } else { retainedAll = false; } } return retainedAll; } @Override public boolean removeAll(Collection c) { boolean removedAll = true; for (Object o : c) { if (this.contains(o)) { this.remove(o); } else { removedAll = false; } } return removedAll; } public void sortAndLimit(int max) { if (this.logBlocks.size() < max) { return; } this.logBlocks = this.logBlocks.stream().sorted(Comparator.comparingInt(b -> b.getLocation().getBlockY())) .limit(max).collect(Collectors.toList()); int highest = this.logBlocks.get(this.logBlocks.size() - 1).getLocation().getBlockY(); if (this.logBlocks.size() >= max) { for (ITreeBlock leafBlock : new LinkedList<>(this.leafBlocks)) { if (leafBlock.getLocation().getY() > highest) { this.leafBlocks.remove(leafBlock); } } } } /** * Removes all tree blocks of a given type * * @param treeBlockType The type of tree block to remove * @return If any blocks were removed */ public boolean removeAll(TreeBlockType treeBlockType) { if (treeBlockType == TreeBlockType.LOG) { boolean removedAny = !this.logBlocks.isEmpty(); this.logBlocks.clear(); return removedAny; } if (treeBlockType == TreeBlockType.LEAF) { boolean removedAny = !this.leafBlocks.isEmpty(); this.leafBlocks.clear(); return removedAny; } return false; } @Override public boolean containsAll(Collection c) { for (Object o : c) { if (!this.contains(o)) { return false; } } return true; } @Override @SuppressWarnings("unchecked") public Object[] toArray(Object[] a) { Set> treeBlocks = new HashSet<>(); for (Object o : a) { if (o instanceof ITreeBlock) { treeBlocks.add((ITreeBlock) o); } } return treeBlocks.toArray(); } }