org.unix4j.unix.wc.Counters Maven / Gradle / Ivy
package org.unix4j.unix.wc;
import java.util.EnumMap;
import org.unix4j.line.Line;
import org.unix4j.line.SimpleLine;
import org.unix4j.processor.LineProcessor;
import org.unix4j.util.Counter;
import org.unix4j.util.StringUtil;
/**
* Counters for lines, words and characters with {@link Counter} objects in a
* map by {@link CounterType}. It depends on the argument options which counters
* are actually maintained. The {@link #update(Line)} method updates the
* relevant counters based on a line.
*/
class Counters {
public final static int MIN_COUNT_PADDING = 2;
private final EnumMap counters = new EnumMap(CounterType.class);
private boolean lastLineWasEmpty;
/**
* Constructor initialising all relevant counters depending on the options
* set in {@code args}.
*
* @param args
* the arguments with the options indicating which counts are
* desired
*/
public Counters(WcArguments args) {
for (final CounterType type : CounterType.values()) {
if (type.isOptionSet(args)) {
counters.put(type, new Counter());
}
}
if (counters.isEmpty()) {
// no option is set, count everything
for (final CounterType type : CounterType.values()) {
counters.put(type, new Counter());
}
}
}
/**
* Updates all the relevant counters based on the specified {@code line}.
*
* @param line
* the line to incorporate into the counts
*/
public void update(Line line) {
for (final CounterType type : counters.keySet()) {
final Counter counter = counters.get(type);
if (counter != null) {
counter.increment(type.count(line));
}
}
lastLineWasEmpty = line.getContentLength() == 0;
}
/**
* Updates the totals counter based on some other counter. Adds the counts
* of the specified {@code counters} to the total counts of {@code this}
* counter.
*
* @param counters
* the counters with per-file counts
*/
public void updateTotal(Counters counters) {
for (final CounterType type : this.counters.keySet()) {
final Counter total = this.counters.get(type);
final Counter update = counters.counters.get(type);
if (total != null && update != null) {
total.increment(update.getCount());
}
}
}
/**
* Resets all counts to zero.
*/
public void reset() {
for (final Counter counter : counters.values()) {
counter.reset();
}
}
private int getWidestCount() {
int max = 0;
for (final Counter counter : counters.values()) {
max = Math.max(max, counter.getWidth());
}
return max;
}
public int getFixedWidthOfColumnsInOutput() {
if(counters.size() == 1){
return counters.values().iterator().next().getWidth();
} else {
return getWidestCount() + MIN_COUNT_PADDING;
}
}
/**
* Writes the counts line to the specified {@code output}.
*
* @param output
* the output destination
*/
public void writeCountsLine(LineProcessor output) {
writeCountsLineWithFileInfo(output, null);
}
/**
* Writes the counts line to the specified {@code output} appending the
* specified file information.
*
* @param output
* the output destination
* @param fileInfo
* the file information, usually a file name or path
*/
public void writeCountsLineWithFileInfo(LineProcessor output, String fileInfo) {
writeCountsLineWithFileInfo(output, fileInfo, getFixedWidthOfColumnsInOutput());
}
/**
* Writes the counts line to the specified {@code output} appending the
* specified file information.
*
* @param output
* the output destination
* @param fileInfo
* the file information, usually a file name or path
* @param fixedWidthOfColumnsInOutput
* the fixed width of the outputted counts. Will usually be the width
* of the widest count, plus two characters
*/
public void writeCountsLineWithFileInfo(LineProcessor output, String fileInfo, int fixedWidthOfColumnsInOutput) {
dontCountSingleEmptyLine();
final CharSequence countString;
final StringBuilder sb = new StringBuilder();
for (final Counter counter : counters.values()) {
final String formattedCount = StringUtil.fixSizeString(fixedWidthOfColumnsInOutput, false, ' ', counter.getCount());
sb.append(formattedCount);
}
countString = sb;
if (fileInfo == null) {
output.processLine(new SimpleLine(countString));
} else {
output.processLine(new SimpleLine(countString + " " + fileInfo));
}
}
private void dontCountSingleEmptyLine() {
if (lastLineWasEmpty) {
final Counter lineCounter = counters.get(CounterType.Lines);
if (lineCounter != null && lineCounter.getCount() == 1) {
lineCounter.reset();
}
}
}
}