001package org.unix4j.unix.uniq;
002
003import java.util.LinkedHashMap;
004import java.util.Map;
005
006import org.unix4j.context.ExecutionContext;
007import org.unix4j.line.Line;
008import org.unix4j.processor.LineProcessor;
009
010/**
011 * Line processors implementing the actual uniq command execution for the case
012 * when the {@link UniqOption#global global} option is selected. The actual
013 * processors are member classes of this abstract base class.
014 */
015abstract class GlobalProcessor extends UniqProcessor {
016        protected final Map<Line, Long> lineToCount = new LinkedHashMap<Line, Long>();
017        public GlobalProcessor(UniqCommand command, ExecutionContext context, LineProcessor output) {
018                super(command, context, output);
019        }
020        
021        /**
022         * Line processor implementing the actual uniq command execution for the 
023         * case when only the {@link UniqOption#global global} option is selected.
024         */
025        public static class Normal extends GlobalProcessor {
026                public Normal(UniqCommand command, ExecutionContext context, LineProcessor output) {
027                        super(command, context, output);
028                }
029                @Override
030                protected boolean processLine(Line line, LineProcessor output) {
031                        lineToCount.put(line, null);//we don't really need the count
032                        return true;// we want all input
033                }
034                @Override
035                public void finish() {
036                        final LineProcessor output = getOutput();
037                        for (final Line line : lineToCount.keySet()) {
038                                output.processLine(line);
039                        }
040                        lineToCount.clear();
041                        output.finish();
042                }
043        }
044        /**
045         * Abstract base class for member classes {@link UniqueOnly}, 
046         * {@link DuplicateOnly} and {@link Count} 
047         */
048        abstract protected static class UniqueDuplicateCount extends GlobalProcessor {
049                private static final Long ONE = Long.valueOf(1);
050                private long maxCount = 0;
051                public UniqueDuplicateCount(UniqCommand command, ExecutionContext context, LineProcessor output) {
052                        super(command, context, output);
053                }
054                @Override
055                protected boolean processLine(Line line, LineProcessor output) {
056                        Long count = lineToCount.put(line, ONE);
057                        if (count != null) {
058                                count++;
059                                lineToCount.put(line, count);
060                                maxCount = Math.max(maxCount, count);
061                        } else {
062                                maxCount = Math.max(maxCount, 1);
063                        }
064                        return true;// we want all input
065                }
066                @Override
067                public void finish() {
068                        final LineProcessor output = getOutput();
069                        final int maxDigits = String.valueOf(maxCount).length();
070                        for (final Map.Entry<Line, Long> e : lineToCount.entrySet()) {
071                                writeLine(e.getKey(), e.getValue(), maxDigits, output);
072                        }
073                        lineToCount.clear();
074                        maxCount = 0;
075                        output.finish();
076                }
077                abstract protected void writeLine(Line line, long count, int maxCountDigits, LineProcessor output);
078        }
079        /**
080         * Line processor implementing the actual uniq command execution for the 
081         * case when the {@link UniqOption#global global} option is selected along
082         * with the {@link UniqOption#uniqueOnly uniqueOnly} option.
083         */
084        public static class UniqueOnly extends UniqueDuplicateCount {
085                public UniqueOnly(UniqCommand command, ExecutionContext context, LineProcessor output) {
086                        super(command, context, output);
087                }
088                @Override
089                protected void writeLine(Line line, long count, int maxCountDigits, LineProcessor output) {
090                        if (count == 1) {
091                                output.processLine(line);
092                        }
093                }
094        }
095        /**
096         * Line processor implementing the actual uniq command execution for the 
097         * case when the {@link UniqOption#global global} option is selected along
098         * with the {@link UniqOption#duplicatedOnly duplicatedOnly} option.
099         */
100        public static class DuplicateOnly extends UniqueDuplicateCount {
101                public DuplicateOnly(UniqCommand command, ExecutionContext context, LineProcessor output) {
102                        super(command, context, output);
103                }
104                @Override
105                protected void writeLine(Line line, long count, int maxCountDigits, LineProcessor output) {
106                        if (count > 1) {
107                                output.processLine(line);
108                        }
109                }
110        }
111        /**
112         * Line processor implementing the actual uniq command execution for the 
113         * case when the {@link UniqOption#global global} option is selected along
114         * with the {@link UniqOption#count count} option.
115         */
116        public static class Count extends UniqueDuplicateCount {
117                public Count(UniqCommand command, ExecutionContext context, LineProcessor output) {
118                        super(command, context, output);
119                }
120                @Override
121                protected void writeLine(Line line, long count, int maxCountDigits, LineProcessor output) {
122                        CountUtil.writeCountLine(line, count, Math.max(3, maxCountDigits), output);
123                }
124        }
125        
126}