001package org.unix4j.io;
002
003import org.unix4j.line.Line;
004import org.unix4j.util.StringUtil;
005
006import java.util.Collection;
007import java.util.Iterator;
008import java.util.LinkedList;
009import java.util.stream.Stream;
010
011/**
012 * Input device reading the input from a string. If the string contains
013 * line-ending code (UNIX or DOS), it is split into multiple lines.
014 */
015public class StringInput implements Input {
016
017        private final Input input;
018
019        /**
020         * Constructor with lines. Each line is tested for new line characters and
021         * possibly split into multiple lines.
022         * 
023         * @param lines
024         *            the lines for this input
025         */
026        public StringInput(String... lines) {
027                this(new BufferedInput(toList(lines)));
028        }
029
030        /**
031         * Constructor with lines. Each line is tested for new line characters and
032         * possibly split into multiple lines.
033         *
034         * @param lines
035         *            the lines for this input
036         */
037        public StringInput(Iterable<? extends String> lines) {
038                this(lines instanceof Collection ?
039                                new BufferedInput(toList(lines)) :
040                                new IteratorInput(toIterator(lines))
041                );
042        }
043
044        /**
045         * Constructor with lines. Each line is tested for new line characters and
046         * possibly split into multiple lines.
047         *
048         * @param lines
049         *            the lines for this input
050         */
051        public StringInput(Stream<? extends String> lines) {
052                this(lines.iterator());
053        }
054
055        /**
056         * Constructor with lines. Each line is tested for new line characters and
057         * possibly split into multiple lines.
058         *
059         * @param lines
060         *            the lines for this input
061         */
062        public StringInput(Iterator<? extends String> lines) {
063                this(new IteratorInput(toIterator(lines)));
064        }
065
066        private StringInput(Input input) {
067                this.input = input;
068        }
069
070        @Override
071        public boolean hasMoreLines() {
072                return input.hasMoreLines();
073        }
074
075        @Override
076        public Line readLine() {
077                return input.readLine();
078        }
079
080        @Override
081        public Iterator<Line> iterator() {
082                return input.iterator();
083        }
084
085        @Override
086        public void close() {
087                input.close();
088        }
089
090        @Override
091        public String toString() {
092                return input.toString();
093        }
094
095        public String toMultilineString() {
096                if (input instanceof BufferedInput) {
097                        return ((BufferedInput)input).toMultiLineString();
098                }
099                return toString();
100        }
101
102        private static LinkedList<Line> toList(String[] lines) {
103                final LinkedList<Line> list = new LinkedList<Line>();
104                for (int i = 0; i < lines.length; i++) {
105                        list.addAll(StringUtil.splitLines(lines[i]));
106                }
107                return list;
108        }
109
110        private static LinkedList<Line> toList(Iterable<? extends String> lines) {
111                final LinkedList<Line> list = new LinkedList<Line>();
112                for (String line : lines) {
113                        list.addAll(StringUtil.splitLines(line));
114                }
115                return list;
116        }
117
118        private static Iterator<Line> toIterator(final Iterable<? extends String> lines) {
119                return toIterator(lines.iterator());
120        }
121
122        private static Iterator<Line> toIterator(final Iterator<? extends String> lines) {
123                return new Iterator<Line>() {
124                        final LinkedList<Line> next = new LinkedList<>();
125                        @Override
126                        public boolean hasNext() {
127                                return false;
128                        }
129
130                        @Override
131                        public Line next() {
132                                if (next.isEmpty()) {
133                                        if (lines.hasNext()) {
134                                                next.addAll(StringUtil.splitLines(lines.next()));
135                                        }
136                                }
137                                return next.isEmpty() ? null : next.removeFirst();
138                        }
139
140                        @Override
141                        public void remove() {
142                                throw new UnsupportedOperationException("remove is not supported");
143                        }
144                };
145        }
146}