package gov.nysenate.openleg.processor.law;
import gov.nysenate.openleg.model.law.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Stack;
/**
* Constructs document hierarchies using document id prefixes.
*/
public class IdBasedLawBuilder extends AbstractLawBuilder implements LawBuilder
{
private static final Logger logger = LoggerFactory.getLogger(IdBasedLawBuilder.class);
/** Stack of the current parent nodes, used to determine hierarchy. */
protected Stack<LawTreeNode> parentNodes = new Stack<>();
/** --- Constructors --- */
public IdBasedLawBuilder(LawVersionId lawVersionId) {
super(lawVersionId);
}
public IdBasedLawBuilder(LawVersionId lawVersionId, LawTree previousTree) {
super(lawVersionId, previousTree);
}
/**
* We determine the position of a node based on whether any of the nodes in the parent stack has a location id
* that prefixes the current document's location id. The specific location id (the matched prefix from the parent
* document removed) is returned.
*
* For example given the locationId 'A2P1SP3', we will pop the parent stack until we find it's parent 'A2P1'
* or reach the root node. The new portion 'SP3' would be the returned value which serves as the docTypeId.
*
* @param block LawBlock
* @return String
*/
@Override
protected String determineHierarchy(LawBlock block) {
String docTypeId = block.getLocationId();
while (!currParent().isRootNode()) {
if (StringUtils.startsWith(block.getLocationId(), currParent().getLocationId())) {
String trimLocId = StringUtils.removeStart(block.getLocationId(), currParent().getLocationId());
if (locationPattern.matcher(trimLocId).matches()) {
docTypeId = trimLocId;
break;
}
}
parentNodes.pop();
}
return docTypeId;
}
@Override
protected void addChildNode(LawTreeNode node) {
if (currParent() != null) {
currParent().addChild(node);
}
// Section nodes should never become parents because they are the most granular (at the moment).
if (!node.getDocType().equals(LawDocumentType.SECTION)) {
parentNodes.push(node);
}
}
@Override
protected boolean isNodeListEmpty() {
return parentNodes.empty();
}
@Override
protected void clearParents() {
parentNodes.clear();
}
/**
* Peek at the parent node stack which holds the current parent.
*/
protected LawTreeNode currParent() {
if (!parentNodes.empty()) {
return parentNodes.peek();
}
else {
return null;
}
}
}