package org.jboss.windup.rules.files.condition.regex;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.github.rwitzel.streamflyer.core.AfterModification;
import com.github.rwitzel.streamflyer.regex.MatchProcessor;
import com.github.rwitzel.streamflyer.regex.MatchProcessorResult;
import com.github.rwitzel.streamflyer.regex.OnStreamMatcher;
import com.github.rwitzel.streamflyer.regex.RegexModifier;
import com.github.rwitzel.streamflyer.regex.addons.util.DoNothingProcessor;
import com.github.rwitzel.streamflyer.util.ModificationFactory;
import com.github.rwitzel.streamflyer.util.statistics.LineColumnAwareModificationFactory;
/**
* Extends {@link RegexModifier} to support tracking the line number and column, and to fire {@link StreamRegexMatchedEvent} events when content is
* matched by the regular expression.
*
* @author <a href="mailto:jesse.sightler@gmail.com">Jesse Sightler</a>
*
*/
public class StreamRegexMatcher extends RegexModifier
{
private final StreamRegexMatcherProcessor streamRegexMatcherProcessor;
public static StreamRegexMatcher create(String regex, StreamRegexMatchListener listener)
{
StreamRegexMatcherProcessor streamRegexMatcherProcessor = new StreamRegexMatcherProcessor(listener);
return new StreamRegexMatcher(regex, 0, streamRegexMatcherProcessor);
}
private StreamRegexMatcher(String regex, int flags, StreamRegexMatcherProcessor streamRegexMatcherProcessor)
{
super(regex, flags, streamRegexMatcherProcessor, 2048, 2048);
this.streamRegexMatcherProcessor = streamRegexMatcherProcessor;
}
@Override
public AfterModification modify(StringBuilder characterBuffer, int firstModifiableCharacterInBuffer,
boolean endOfStreamHit)
{
this.streamRegexMatcherProcessor.setFirstCharIndex(firstModifiableCharacterInBuffer);
return super.modify(characterBuffer, firstModifiableCharacterInBuffer, endOfStreamHit);
}
@Override
protected void init(OnStreamMatcher matcher, MatchProcessor matchProcessor, int minimumLengthOfLookBehind,
int newNumberOfChars)
{
super.init(matcher, matchProcessor, minimumLengthOfLookBehind, newNumberOfChars);
ModificationFactory delegate = new ModificationFactory(minimumLengthOfLookBehind, newNumberOfChars);
this.factory = new LineColumnAwareModificationFactory(delegate);
this.matchProcessor = matchProcessor;
this.matcher = matcher;
this.newNumberOfChars = newNumberOfChars;
((StreamRegexMatcherProcessor) matchProcessor).setLineColumnAwareModificationFactory((LineColumnAwareModificationFactory) this.factory);
}
private static class StreamRegexMatcherProcessor extends DoNothingProcessor implements MatchProcessor
{
private int firstCharIndex;
private final StreamRegexMatchListener listener;
private LineColumnAwareModificationFactory lineColumnAwareModificationFactory;
public StreamRegexMatcherProcessor(StreamRegexMatchListener listener)
{
this.listener = listener;
}
public void setLineColumnAwareModificationFactory(LineColumnAwareModificationFactory lineColumnAwareModificationFactory)
{
this.lineColumnAwareModificationFactory = lineColumnAwareModificationFactory;
}
public void setFirstCharIndex(int firstCharIndex)
{
this.firstCharIndex = firstCharIndex;
}
@Override
public MatchProcessorResult process(StringBuilder characterBuffer, int firstModifiableCharacterInBuffer, MatchResult matchResult)
{
long unmatchedStartLine = lineColumnAwareModificationFactory.getCurrentLine();
long unmatchedStartColumn = lineColumnAwareModificationFactory.getCurrentColumn();
int unmatchedStart = firstCharIndex;
int unmatchedEnd = matchResult.start();
String unmatched = characterBuffer.substring(unmatchedStart, unmatchedEnd);
Matcher matcher = Pattern.compile("\r\n|\r|\n").matcher(unmatched);
int numLines = 0;
int endOfLastLineBreak = 0;
while (matcher.find())
{
numLines++;
endOfLastLineBreak = matcher.end();
}
long lineNumber = unmatchedStartLine + numLines;
long columnNumber;
if (numLines == 0)
{
columnNumber = unmatchedStartColumn + unmatched.length();
}
else
{
columnNumber = unmatched.length() - endOfLastLineBreak; // length of last line in 'unmatched'
}
String matchText = matchResult.group();
StreamRegexMatchedEvent event = new StreamRegexMatchedEvent(matchText, lineNumber, columnNumber);
listener.regexMatched(event);
return super.process(characterBuffer, firstModifiableCharacterInBuffer, matchResult);
}
}
}