package it.cavallium.warppi.gui.expression.blocks; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntCollections; import org.apache.commons.lang3.NotImplementedException; import java.util.Collections; import java.util.Objects; public final class BlockPosition { private final BlockOrContainer pos; public BlockPosition(BlockOrContainer pos) { this.pos = pos; } public BlockPosition(Block block) { this.pos = block; } public BlockPosition(BlockContainer container) { this.pos = container; } public boolean isBlock() { return pos instanceof Block; } public boolean isContainer() { return pos instanceof BlockContainer; } public Block getBlock() { return (Block) pos; } public BlockContainer getContainer() { return (BlockContainer) pos; } public BlockOrContainer get() { return pos; } @Override public boolean equals(Object obj) { if (obj == this) return true; if (obj == null || obj.getClass() != this.getClass()) return false; var that = (BlockPosition) obj; return Objects.equals(this.pos, that.pos); } @Override public int hashCode() { return Objects.hash(pos); } @Override public String toString() { return "BlockPosition[" + "pos=" + pos + ']'; } public BlockPosition getNext() { if (pos instanceof BlockContainer) { var container = (BlockContainer) pos; var content = container.getContent(); if (content.isEmpty()) { BlockContainer nextContainer; if (container.hasParent()) { var containers = container.getParentBlock().getInnerContainers(); var it = containers.listIterator(containers.indexOf(container) + 1); nextContainer = it.hasNext() ? it.next() : null; } else { nextContainer = null; } if (nextContainer != null) { return new BlockPosition(nextContainer); } else { var parentBlock = container.getParentBlock(); return parentBlock != null ? new BlockPosition(parentBlock) : null; } } else { var targetBlock = content.get(0); var innerContainers = targetBlock.getInnerContainers(); if (innerContainers != null && !innerContainers.isEmpty()) { return new BlockPosition(innerContainers.get(0)); } else { return new BlockPosition(targetBlock); } } } else if (pos instanceof Block) { var block = (Block) pos; var ref = block.getReference(); var nextBlock = ref.getNextBlock(); if (nextBlock == null) { var container = block.getParentContainer(); BlockContainer nextContainer; if (container.hasParent()) { var containers = container.getParentBlock().getInnerContainers(); var it = containers.listIterator(containers.indexOf(container) + 1); nextContainer = it.hasNext() ? it.next() : null; } else { nextContainer = null; } if (nextContainer != null) { return new BlockPosition(nextContainer); } else { var parentBlock = container.getParentBlock(); return parentBlock != null ? new BlockPosition(parentBlock) : null; } } else { var targetBlock = nextBlock.get(); var innerContainers = targetBlock.getInnerContainers(); if (innerContainers != null && !innerContainers.isEmpty()) { return new BlockPosition(innerContainers.get(0)); } else { return new BlockPosition(targetBlock); } } } else { throw new UnsupportedOperationException(); } } public BlockPosition getPrevious() { if (pos instanceof BlockContainer) { var container = (BlockContainer) pos; if (container.hasParent()) { var parentBlock = container.getParentBlock(); var innerContainers = parentBlock.getInnerContainers(); if (innerContainers != null) { var it = innerContainers.listIterator(innerContainers.indexOf(container)); if (it.hasPrevious()) { var prevContainer = it.previous(); return prevContainer.getLastPosition(); } else { var parentContainer = parentBlock.getParentContainer(); var blocks = parentContainer.getContentUnsafe(); var bIt = blocks.listIterator(blocks.indexOf(parentBlock)); if (bIt.hasPrevious()) { return new BlockPosition(bIt.previous()); } else { return new BlockPosition(parentContainer); } } } else { throw new UnsupportedOperationException(); } } else { return null; } } else if (pos instanceof Block) { var block = (Block) pos; var innerContainers = block.getInnerContainers(); if (innerContainers != null) { var lastContainer = innerContainers.get(innerContainers.size() - 1); return lastContainer.getLastPosition(); } var ref = block.getReference(); var prevBlock = ref.getPreviousBlock(); if (prevBlock == null) { var container = block.getParentContainer(); return new BlockPosition(container); } else { var targetBlock = prevBlock.get(); return new BlockPosition(targetBlock); } } else { throw new UnsupportedOperationException(); } } public IntArrayList getURL() { var url = new IntArrayList(); var parent = pos; while (parent != null) { var index = parent.getIndex(); if (index == -1) break; url.add(index); parent = parent.getParent(); } Collections.reverse(url); return url; } }