001package org.unix4j.io;
002
003import java.util.ArrayList;
004import java.util.LinkedList;
005import java.util.List;
006
007import org.unix4j.line.Line;
008import org.unix4j.util.LineUtil;
009
010/**
011 * Output device storing all written lines in memory in a {@link List}.
012 */
013public class BufferedOutput implements Output {
014
015        private final List<Line> buffer;
016
017        /**
018         * Constructor using an {@link ArrayList} as backing buffer for the lines.
019         */
020        public BufferedOutput() {
021                this(new ArrayList<Line>());
022        }
023
024        /**
025         * Constructor using the specified list as line buffer. The buffer is NOT
026         * cloned, that is, changes to the buffer affect this {@code BufferedOutput}
027         * and vice versa.
028         * 
029         * @param buffer
030         *            the line buffer used "as is" without cloning
031         */
032        public BufferedOutput(List<Line> buffer) {
033                this.buffer = buffer;
034        }
035
036        @Override
037        public boolean processLine(Line line) {
038                buffer.add(line);
039                return true;
040        }
041
042        @Override
043        public void finish() {
044                // nothing to do
045        }
046
047        /**
048         * Returns a list-like representation of the lines contained in this buffer.
049         * Some users might also consider {@link #toMultiLineString()} instead.
050         * 
051         * @return a list-like string representation of the buffered lines
052         */
053        @Override
054        public String toString() {
055                return buffer.toString();
056        }
057
058        /**
059         * Returns a multi-line representation of the lines in this buffer. The last
060         * line is never terminated, all other lines are terminated with guarantee
061         * even if the line itself has an empty line ending string.
062         * 
063         * @return a multi-line string of the buffered lines, without line
064         *         termination for the last line
065         * @see LineUtil#toMultiLineString(List)
066         */
067        public String toMultiLineString() {
068                return LineUtil.toMultiLineString(buffer);
069        }
070
071        /**
072         * Writes the buffered output lines to the specified {@code output} device.
073         * This buffered output devices does not change, that is, all lines will
074         * still be contained in the buffer after calling this method.
075         * 
076         * @param output
077         *            the output device to write to
078         */
079        public void writeTo(Output output) {
080                boolean more = true;
081                for (int i = 0; i < buffer.size() && more; i++) {
082                        more = output.processLine(buffer.get(i));
083                }
084                output.finish();
085        }
086
087        /**
088         * Returns a {@link BufferedInput} with all lines contained in this
089         * {@code BufferedOutput}. The lists used as buffer in this
090         * {@link BufferedOutput} and the returned {@link BufferedInput} are NOT
091         * shared, meaning that subsequent modifications of this
092         * {@code BufferedOutput} are not reflected in the returned
093         * {@code BufferedInput}.
094         * 
095         * @return a {@code BufferdInput} object reflecting the current snapshot of
096         *         lines in this {@code BufferedOutput}
097         */
098        public BufferedInput asInput() {
099                return new BufferedInput(new LinkedList<Line>(buffer));
100        }
101
102        /**
103         * Returns a new list with the lines currently stored by this
104         * {@code BufferdOutput} object.
105         * 
106         * @return a new list with the lines of this buffer
107         */
108        public List<Line> asList() {
109                return new ArrayList<Line>(buffer);
110        }
111
112        /**
113         * Returns the number of lines currently stored by this
114         * {@code BufferedOutput} object.
115         * 
116         * @return the number of lines in the buffer
117         */
118        public int size() {
119                return buffer.size();
120        }
121
122        /**
123         * Clears all lines in this buffer.
124         * 
125         * @return this buffer for chained calls
126         */
127        public BufferedOutput clear() {
128                buffer.clear();
129                return this;
130        }
131}