/*license*\
XBN-Java: Copyright (C) 2014, Jeff Epstein (aliteralmind __DASH__ github __AT__ yahoo __DOT__ com)
This software is dual-licensed under the:
- Lesser General Public License (LGPL) version 3.0 or, at your option, any later version;
- Apache Software License (ASL) version 2.0.
Either license may be applied at your discretion. More information may be found at
- http://en.wikipedia.org/wiki/Multi-licensing.
The text of both licenses is available in the root directory of this project, under the names "LICENSE_lgpl-3.0.txt" and "LICENSE_asl-2.0.txt". The latest copies may be downloaded at:
- LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt
- ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt
\*license*/
package com.github.xbn.linefilter.entity.raw;
import com.github.xbn.linefilter.entity.LineEntityException;
import com.github.xbn.analyze.alter.AbstractValueAlterer;
import com.github.xbn.analyze.alter.Altered;
import com.github.xbn.analyze.alter.NeedsToBeDeleted;
import com.github.xbn.analyze.alter.ValueAlterer;
import com.github.xbn.io.NewTextAppenterFor;
import com.github.xbn.io.TextAppenter;
import com.github.xbn.keyed.SimpleNamed;
import com.github.xbn.lang.CrashIfObject;
import com.github.xbn.lang.IllegalArgumentStateException;
import com.github.xbn.linefilter.entity.EntityType;
import com.github.xbn.linefilter.entity.OnOffAbort;
import com.github.xbn.linefilter.entity.raw.RawOnOffEntityFilter;
import com.github.xbn.linefilter.entity.raw.z.RawLineEntity_Fieldable;
import com.github.xbn.number.CrashIfIntIs;
import com.github.xbn.number.LengthInRange;
import java.util.Objects;
import static com.github.xbn.lang.XbnConstants.*;
/**
<p>The base class for all entities.</p>
<A NAME="cfg"></a><h3>Builder Configuration: {@link com.github.xbn.linefilter.entity.raw.z.RawLineEntity_CfgForNeeder RawLineEntity_CfgForNeeder}</h3>
<p><ul>
<li>YYY</li>
com.github.xbn.linefilter.entity.raw.z.RawLineEntity_CfgForNeeder#reset()
com.github.xbn.linefilter.entity.raw.z.RawLineEntity_CfgForNeeder#debugLineNumbers(Appendable)
com.github.xbn.linefilter.entity.raw.z.RawLineEntity_CfgForNeeder#chainID(boolean, Object)
</ul></p>
* @since 0.1.0
* @author Copyright (C) 2014, Jeff Epstein ({@code aliteralmind __DASH__ github __AT__ yahoo __DOT__ com}), dual-licensed under the LGPL (version 3.0 or later) or the ASL (version 2.0). See source code for details. <a href="http://xbnjava.aliteralmind.com">{@code http://xbnjava.aliteralmind.com}</a>, <a href="https://github.com/aliteralmind/xbnjava">{@code https://github.com/aliteralmind/xbnjava}</a>
**/
public abstract class RawLineEntity<L> extends AbstractValueAlterer<L,L> implements RawChildEntity<L> {
private final RawParentEntity<L> parent ;
private final RawParentEntity<L> topParent ;
private final int levelsBelowRoot;
private final SimpleNamed smplNamed ;
private final TextAppenter dbgAptrLineNums;
private final EntityType type ;
private final RawOnOffEntityFilter<L> filter;
private final TextAppenter dbgAptrEveryLine;
private final LengthInRange rangeForEveryLineDebug;
private boolean isRqd ;
private int mostRecentLineNum;
private int fullyActiveCount ;
private boolean doAbortItr ;
/**
<p>Create a new and <i>temporarily unusable</i> instance from a fieldable.</p>
* @param fieldable May not be {@code null}, and all relevant fields must conform to the restrictions as documented in the setters of all sub-classes (<code><a href="{@docRoot}/com/github/xbn/linefilter/entity/SingleLineEntity.html#cfg">SingleLineEntity</a></code>, <code><a href="{@docRoot}/com/github/xbn/linefilter/entity/BlockEntity.html#cfg">BlockEntity</a></code>, <code><a href="{@docRoot}/com/github/xbn/linefilter/entity/StealthBlockEntity.html#cfg">StealthBlockEntity</a></code>).
*/
public RawLineEntity(RawLineEntity_Fieldable<L> fieldable) {
super();
declareMayDelete(false);
try {
type = fieldable.getType();
} catch(RuntimeException rx) {
throw CrashIfObject.nullOrReturnCause(fieldable, "fieldable", null, rx);
}
Objects.requireNonNull(type, "fieldable.getType()");
smplNamed = new SimpleNamed(fieldable.getName());
isRqd = fieldable.isRequired();
levelsBelowRoot = -1;
resetCountsLET();
filter = ((fieldable.getFilterIfNonNull() == null)
? NewRawOnOffEntityFilterFor.<L>alwaysForPrePost(OnOffAbort.ON, OnOffAbort.ON)
: fieldable.getFilterIfNonNull());
Objects.requireNonNull(filter, "fieldable.getFilterIfNonNull()");
parent = null;
topParent = null;
dbgAptrLineNums = NewTextAppenterFor.appendableUnusableIfNull(
fieldable.getDebugApblLineNumbers());
dbgAptrEveryLine = null;
rangeForEveryLineDebug = null;
resetLineStateRLE();
resetStateLET();
}
protected RawLineEntity(RawLineEntity<L> to_copy, int levels_belowRoot, RawParentEntity<L> parent, TextAppenter dbgAptrEveryLine_ifUseable, LengthInRange range_forEveryLineDebug) {
super(to_copy);
type = to_copy.getType();
CrashIfIntIs.lessThanZero(levels_belowRoot, "levels_belowRoot", null);
filter = to_copy.getFilter().getObjectCopy();
if(parent == null) {
if(levels_belowRoot != 0) {
throw new IllegalArgumentStateException("parent=null, levels_belowRoot=" + levels_belowRoot + ". Root entity must have a levels-below of zero.");
}
this.parent = null;
try {
@SuppressWarnings("unchecked")
RawParentEntity<L> top2 = (RawParentEntity<L>)to_copy;
topParent = top2;
} catch(ClassCastException ccx) {
throw new ClassCastException("parent is null, but to_copy (" + to_copy.getClass().getName() + ") is not a RawParentEntity<L>: " + ccx);
}
smplNamed = new SimpleNamed(to_copy.smplNamed.getName());
levelsBelowRoot = 0;
} else {
if(levels_belowRoot < 1) {
throw new IllegalArgumentStateException("parent=null, levels_belowRoot=" + levels_belowRoot + ". Non-root entity must have a levels-below greater than zero.");
}
RawParentEntity<L> top2 = parent;
try {
while(top2 != null) {
top2 = top2.getParent();
}
} catch(RuntimeException rx) {
throw CrashIfObject.nullOrReturnCause(parent, "parent", null, rx);
}
this.parent = parent;
topParent = top2;
smplNamed = new SimpleNamed(to_copy.smplNamed.getName());
isRqd = to_copy.isRequired();
levelsBelowRoot = levels_belowRoot;
}
resetStateLET();
resetCountsLET();
dbgAptrLineNums = to_copy.getDebugAptrLineNumbers();
Objects.requireNonNull(dbgAptrEveryLine_ifUseable, "dbgAptrEveryLine_ifUseable");
Objects.requireNonNull(range_forEveryLineDebug, "range_forEveryLineDebug");
dbgAptrEveryLine = dbgAptrEveryLine_ifUseable;
rangeForEveryLineDebug = range_forEveryLineDebug;
resetLineStateRLE();
}
public void resetLineState() {
resetLineStateRLE();
}
protected void resetLineStateRLE() {
mostRecentLineNum = 0;
}
/**
<p>The outputter for diagnostics on every analyzed line.</p>
* @see com.github.xbn.linefilter.FilteredIterator#FilteredIterator(Iterator, Returns, Appendable, LengthInRange, RawBlockEntity)
*/
public TextAppenter getDebugAptrEveryLine() {
return dbgAptrEveryLine;
}
public LengthInRange getEveryLineDebugRange() {
return rangeForEveryLineDebug;
}
public RawParentEntity<L> getParent() {
return parent;
}
public RawParentEntity<L> getTopParent() {
return topParent;
}
public String getName() {
return smplNamed.getName();
}
public String getKey() {
return smplNamed.getKey();
}
public EntityType getType() {
return type;
}
public boolean isRequired() {
return isRqd;
}
public int getParentCount() {
return levelsBelowRoot;
}
public TextAppenter getDebugAptrLineNumbers() {
return dbgAptrLineNums;
}
public RawOnOffEntityFilter<L> getFilter() {
return filter;
}
public int getFullyActiveCount() {
return fullyActiveCount;
}
protected void incrementFullyActiveCount() {
fullyActiveCount++;
}
public void resetState() {
super.resetState();
resetStateLET();
}
protected void resetStateLET() {
doAbortItr = false;
}
public void resetCounts() {
super.resetCounts();
resetCountsLET();
}
protected void resetCountsLET() {
fullyActiveCount = 0;
}
public int getMostRecentLineNum() {
return mostRecentLineNum;
}
public abstract boolean isActive();
public boolean isInitialized() {
return (getParentCount() != -1);
}
public boolean doAbortIterator() {
return doAbortItr;
}
protected void abortIteratorDeclareNotAltered(String abort_source, L line) {
declareAltered(Altered.NO, NeedsToBeDeleted.NO);
abortIterator(abort_source);
}
protected void abortIterator(String abort_source) {
if(isEveryLineAptrUseableAndInRange()) {
getDebugAptrEveryLine().appentln(getDebuggingPrefix() + " ABORT_ENTITY (aborted by " + abort_source + "): Setting doAbortIterator() to true");
}
doAbortItr = true;
}
/*
protected void declareAltered(L line, Altered altered, NeedsToBeDeleted deleted) {
try {
declareAltered(line.getNumber(), Altered.NO, NeedsToBeDeleted.NO);
} catch(RuntimeException rx) {
throw CrashIfObject.nullOrReturnCause(line, "line", null, rx);
}
}
public int getMostRecentLineNum() {
return lineNumAnalyzed;
}
*/
public L getAltered(L line_toAnalyze, L line_toAlter) {
throw new UnsupportedOperationException("Use getAltered(int, L, L)");
}
public L getAltered(int line_num, L line_toAnalyze, L line_toAlter) {
mostRecentLineNum = line_num;
return super.getAltered(line_toAnalyze, line_toAlter);
}
protected void declareAltered(Altered altered, NeedsToBeDeleted deleted) {
if(!isInitialized()) {
throw new IllegalStateException("isInitialized()=false");
}
if(doAbortIterator()) {
throw new IllegalStateException("Already aborted (doAbortIterator()=true). Cannot declare anything altered. this=" + this);
}
super.declareAltered(altered, deleted);
}
protected void postFilter(L potentially_alteredLine) {
if(doAbortIterator()) {
throw new IllegalStateException("Already aborted (doAbortIterator()=true). Cannot execute post-filter. this=" + this);
}
OnOffAbort state = getFilter().getPostState(this, getMostRecentLineNum(), potentially_alteredLine);
if(state.doAbortIterator()) {
abortIterator("post-filter");
return;
}
//Do not abort
if(state.isOff() && isEveryLineAptrUseableAndInRange()) {
getDebugAptrEveryLine().appentln(getDebuggingPrefix() + " getPostState(this, original_line, potentially_alteredLine) is OFF.");
}
}
protected boolean isEveryLineAptrUseableAndInRange() {
return getDebugAptrEveryLine().isUseable() && getEveryLineDebugRange().isIn(getMostRecentLineNum());
}
public StringBuilder appendParentChainName(StringBuilder to_appendTo, String separator) {
try {
to_appendTo.append(getName());
} catch(RuntimeException rx) {
throw CrashIfObject.nullOrReturnCause(to_appendTo, "to_appendTo", null, rx);
}
RawParentEntity<L> parent = getParent();
while(parent != null) {
to_appendTo.insert(0, separator).insert(0, parent.getName());
parent = parent.getParent();
}
return to_appendTo;
}
/**
* @return <code>{@link #appendToString(StringBuilder) appendToString}(new StringBuilder()).toString()</code>
*/
public String toString() {
return appendToString(new StringBuilder()).toString();
}
/**
* @param to_appendTo May not be {@code null}.
* @see #toString()
*/
public StringBuilder appendToString(StringBuilder to_appendTo) {
try {
to_appendTo.append("\"");
} catch(RuntimeException rx) {
throw CrashIfObject.nullOrReturnCause(to_appendTo, "to_appendTo", null, rx);
}
appendParentChainName(to_appendTo, "/").append("\", ").
append(getType()).append(", getMostRecentLineNum()=").append(getMostRecentLineNum());
if(doAbortIterator()) {
to_appendTo.append(", doAbortIterator()=true");
}
if(isRequired()) {
to_appendTo.append(", isRequired()=true");
}
to_appendTo.append(LINE_SEP).append(" >>> Alterer info: ");
super.appendToString(to_appendTo);//.append("\", rules: {{");
// return appendRules(to_appendTo).append("}}");
return to_appendTo;
}
protected static final <L> ValueAlterer<L,L> getAltererCopyCrashIfMayDelete(ValueAlterer<L,L> alterer, String alterer_varName) {
if(alterer.mayDelete()) {
throw new IllegalArgumentException(alterer_varName + ".mayDelete() is true.");
}
try {
return alterer.getObjectCopy();
} catch(RuntimeException rx) {
throw new RuntimeException("Attempting " + alterer_varName + ".getObjectCopy()");
}
}
/**
<p><i>Do not use</i>--Use {@code getAlteredPostResetCheck} instead.</p>
* @exception UnsupportedOperationException
*/
public final RawLineEntity<L> getObjectCopy() {
throw new UnsupportedOperationException("Use getAlteredPostResetCheck");
}
public String getDebuggingPrefix() {
return getDebuggingPrefixPrefix() + "]";
}
protected String getDebuggingPrefixPrefix() {
return "[" + getMostRecentLineNum() + ":" + getType() +
":\"" + getName() + "\"" +
(isActive() ? ":active" : "") +
(doAbortIterator() ? ":ABORT_ITERATOR" : "");
}
protected void crashIfRequiredAndNeverActive() {
if(!isRequired()) {
return;
}
if(getFullyActiveCount() == 0) {
throw new LineEntityException(-1, null, this, "Entity is required, but was not found in the input.");
}
}
}