package scales.utils.collection.path
import scala.collection.immutable.Stack
import scala.collection.IndexedSeqLike
import scala.collection.generic.CanBuildFrom
import scales.utils.{LeftLike, RightLike, EitherLike, ItemOrTree, collection, subtree}
import collection.Tree
case class Top[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]]]() extends LeftLike[Top[Item, Section, CC], Path[Item, Section, CC]]
trait Position[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]]] {
private[utils] val root: Path[Item, Section, CC]
private[utils] val position: Stack[Int]
}
private[utils] case class PositionImpl[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]]](val position: Stack[Int], val root: Path[Item, Section, CC]) extends Position[Item, Section, CC]
case class Node[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]]](index: Int, focus: ItemOrTree[Item, Section, CC])
case class Path[Item <: LeftLike[Item, Tree[Item, Section, CC]], Section, CC[X] <: IndexedSeqLike[X, CC[X]]](top: EitherLike[Top[Item,Section,CC], Path[Item, Section, CC]], node: Node[Item, Section, CC])
(implicit cbf : CanBuildFrom[CC[_], ItemOrTree[Item, Section, CC], CC[ItemOrTree[Item, Section, CC]]]) extends Iterable[Path[Item, Section, CC]] with RightLike[Top[Item, Section, CC], Path[Item, Section, CC]] { self =>
def parentTree : Tree[Item, Section, CC] = top.getRight.node.focus.getRight
def parentCount = if (top.isLeft) 0 else parentTree.children.length
def hasPreviousSibling = (node.index > 0 && node.index <= parentCount)
def hasNextSibling = (node.index > -1 && node.index < (parentCount - 1))
def isItem = node.focus.isLeft
def hasChildren =
if (isItem) false
else children.length != 0
def focus[R]( i : Item => R, t : Tree[Item,Section,CC] => R) : R =
node.focus.fold(i, t)
def children : CC[ItemOrTree[Item,Section,CC]] = node.focus.right.get.children
def previousSibling = Path(top, Node(node.index - 1, parentTree.children.apply(node.index - 1)))
def nextSibling = Path(top, Node(node.index + 1, parentTree.children(node.index + 1)))
def tree() = node.focus.getRight
def item() = node.focus.getLeft
private[this] class ItemIterator() extends Iterator[Path[Item,Section, CC]] {
def hasNext = false
def next() = error("Cannot iterate over an item")
}
private[this] class TreeIterator() extends Iterator[Path[Item,Section, CC]] {
val c = children.iterator
var index = -1
def hasNext = c.hasNext
def next() : Path[Item, Section, CC] = {
index += 1
Path(self, Node(index, c.next()))
}
}
def iterator() =
if (isItem)
new ItemIterator()
else
new TreeIterator()
def firstChild(): Option[Path[Item, Section, CC]] =
if (!hasChildren) None
else Some(Path(this, Node(0, children.head)))
def lastChild(): Option[Path[Item, Section, CC]] =
if (isItem) None
else {
val c = children
if (c.length == 0) None
else {
val newPos = c.length - 1
Some(Path(this,
Node(newPos, c(newPos))))
}
}
def zipUp(): Path[Item, Section, CC] =
if (top.isLeft) this
else {
val path = top.right.get
val pt = parentTree
if (pt.children(node.index) eq node.focus) path
else {
val parentFocus =
subtree(pt.section, pt.children.updated(node.index, node.focus))
Path(path.top, Node(path.node.index,
parentFocus))
}
}
def modify(newFocus: (ItemOrTree[Item, Section, CC]) => ItemOrTree[Item, Section, CC]) =
Path(top, Node(node.index,
newFocus(node.focus)))
def removeAndUp(): Option[Path[Item, Section, CC]] =
if (top.isLeft) None
else {
val path = top.right.get
val tree = path.node.focus.right.get
val parentFocus = {
val c = parentTree.children
if (c.size == 1) {
subtree(tree.section, c.asInstanceOf[scala.collection.Traversable[ItemOrTree[Item, Section, CC]]].companion.empty.asInstanceOf[CC[ItemOrTree[Item, Section, CC]]])
} else {
val parts = parentTree.children.splitAt(node.index)
subtree(tree.section, parts._1 ++ parts._2.tail)
}
}
Some(
Path(path.top, Node(path.node.index,
parentFocus)))
}
def position(): Position[Item, Section, CC] = {
@scala.annotation.tailrec
def makePosition(path: Path[Item, Section, CC], stack: Stack[Int]): (Stack[Int], Path[Item, Section, CC]) = {
val newStack = stack.push(path.node.index)
if (path.top.isLeft)
(newStack, path)
else
makePosition(path.top.right.get, newStack)
}
val res = makePosition(this, Stack[Int]())
new PositionImpl[Item,Section,CC](res._1, res._2)
}
override def toString(): String = {
val builder = new java.lang.StringBuilder()
builder.append("Path(");
if (top.isLeft)
builder.append("Top");
else
builder.append(top.right.get.tree.section);
builder.append(",");
builder.append(node.index);
builder.append(",");
if (isItem)
builder.append(item);
else
builder.append(tree.section);
builder.append(")");
builder.toString
}
}
<iframe src="https://scalesxml.github.io/scales-xml_2.10/0.5.0/api.sxr/scales/utils/collection/path/Paths.scala.html" width="1280" height="720" frameborder="0"> </iframe>