001package org.unix4j.unix.sort;
002
003import java.util.Comparator;
004import java.util.List;
005
006import org.unix4j.context.ExecutionContext;
007import org.unix4j.io.Input;
008import org.unix4j.line.Line;
009import org.unix4j.processor.LineProcessor;
010
011class MergeProcessor extends AbstractSortProcessor {
012
013        private final List<? extends Input> inputs;
014        
015        public MergeProcessor(SortCommand command, ExecutionContext context, LineProcessor output, List<? extends Input> inputs) {
016                super(command, context, output);
017                this.inputs = inputs;
018        }
019
020        @Override
021        public boolean processLine(Line line) {
022                //if lines come from standard input, there is nothing to merge
023                return getOutput().processLine(line);
024        }
025
026        @Override
027        public void finish() {
028                final int len = inputs.size();
029                final Line[] lines = new Line[len];
030                for (int i = 0; i < len; i++) {
031                        final Input input = inputs.get(i); 
032                        lines[i] = input.hasMoreLines() ? input.readLine() : null;
033                }
034                final LineProcessor output = getOutput();
035                final Comparator<? super Line> comparator = getComparator();
036                while (true) {
037                        Line line = null;
038                        int inputIndexOfLine = -1;
039                        for (int i = 0; i < len; i++) {
040                                final Line cur = lines[i];
041                                if (cur != null) {
042                                        if (inputIndexOfLine < 0 || 0 < comparator.compare(line, cur)) {
043                                                line = cur;
044                                                inputIndexOfLine = i;
045                                        }
046                                }
047                        }
048                        if (line != null) {
049                                //write the winner line
050                                if (!output.processLine(line)) {
051                                        output.finish();
052                                        return;
053                                }
054                                //move to next line for winner input
055                                final Input input = inputs.get(inputIndexOfLine); 
056                                lines[inputIndexOfLine] = input.hasMoreLines() ? input.readLine() : null;
057                        } else {
058                                //no more lines
059                                output.finish();
060                                return;
061                        }
062                }
063        }
064
065}