/*
* -----------------------------------------------------------------------
* Copyright © 2013-2016 Meno Hochschild, <http://www.menodata.de/>
* -----------------------------------------------------------------------
* This file (SkipProcessor.java) is part of project Time4J.
*
* Time4J is free software: You can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* Time4J is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Time4J. If not, see <http://www.gnu.org/licenses/>.
* -----------------------------------------------------------------------
*/
package net.time4j.format.expert;
import net.time4j.engine.AttributeQuery;
import net.time4j.engine.ChronoDisplay;
import net.time4j.engine.ChronoElement;
import java.io.IOException;
import java.util.Set;
import java.util.function.IntPredicate;
/**
* <p>Verarbeitet nicht interpretierbare Zeichen. </p>
*
* @author Meno Hochschild
* @since 3.18/4.14
*/
final class SkipProcessor
implements FormatProcessor<Void> {
//~ Instanzvariablen --------------------------------------------------
private final int count;
private final IntPredicate condition;
//~ Konstruktoren -----------------------------------------------------
SkipProcessor(int keepRemainingChars) {
super();
if (keepRemainingChars < 0) {
throw new IllegalArgumentException("Must not be negative: " + keepRemainingChars);
}
this.condition = null;
this.count = keepRemainingChars;
}
SkipProcessor(
IntPredicate unparseable,
int maxIterations
) {
super();
if (unparseable == null) {
throw new NullPointerException("Missing condition for unparseable chars.");
} else if (maxIterations < 1) {
throw new IllegalArgumentException("Must be positive: " + maxIterations);
}
this.condition = unparseable;
this.count = maxIterations;
}
//~ Methoden ----------------------------------------------------------
@Override
public void print(
ChronoDisplay formattable,
Appendable buffer,
AttributeQuery attributes,
Set<ElementPosition> positions,
boolean quickPath
) throws IOException {
// no-op
}
@Override
public void parse(
CharSequence text,
ParseLog status,
AttributeQuery attributes,
ParsedEntity<?> parsedResult,
boolean quickPath
) {
int start = status.getPosition();
int len = text.length();
int offset;
if (this.condition == null) {
offset = len - this.count; // minus keepRemainingChars
} else {
offset = start;
for (int i = 0; i < this.count && (i + start < len); i++) {
if (this.condition.test(text.charAt(i + start))) {
offset++;
} else {
break;
}
}
}
offset = Math.min(Math.max(offset, 0), len);
if (offset > start) {
status.setPosition(offset);
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj instanceof SkipProcessor) {
SkipProcessor that = (SkipProcessor) obj;
return (
(this.count == that.count)
&& ((this.condition == null) ? (that.condition == null) : this.condition.equals(that.condition))
);
} else {
return false;
}
}
@Override
public int hashCode() {
return ((this.condition == null) ? this.count : (~this.count ^ this.condition.hashCode()));
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(64);
sb.append(this.getClass().getName());
if (this.condition == null) {
sb.append("[keepRemainingChars=");
sb.append(this.count);
} else {
sb.append("[condition=");
sb.append(this.condition);
sb.append(", maxIterations=");
sb.append(this.count);
}
sb.append(']');
return sb.toString();
}
// optional
@Override
public ChronoElement<Void> getElement() {
return null;
}
@Override
public FormatProcessor<Void> withElement(ChronoElement<Void> element) {
return this;
}
@Override
public boolean isNumerical() {
return false;
}
@Override
public FormatProcessor<Void> quickPath(
ChronoFormatter<?> formatter,
AttributeQuery attributes,
int reserved
) {
return this;
}
}