001 /*
002 * Copyright (C) 2012 eXo Platform SAS.
003 *
004 * This is free software; you can redistribute it and/or modify it
005 * under the terms of the GNU Lesser General Public License as
006 * published by the Free Software Foundation; either version 2.1 of
007 * the License, or (at your option) any later version.
008 *
009 * This software is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public
015 * License along with this software; if not, write to the Free
016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018 */
019
020 package org.crsh.text;
021
022 import org.crsh.io.Pipe;
023
024 import java.io.IOException;
025 import java.io.Serializable;
026 import java.util.Iterator;
027 import java.util.LinkedList;
028
029 public class ChunkBuffer implements Iterable<Chunk>, Serializable, Pipe<Chunk> {
030
031 /** . */
032 private final LinkedList<Chunk> chunks;
033
034 /** . */
035 private Style current;
036
037 /** . */
038 private Style next;
039
040 /** Where we flush. */
041 private final Pipe<Chunk> out;
042
043 public ChunkBuffer() {
044 this.chunks = new LinkedList<Chunk>();
045 this.current = Style.style();
046 this.next = Style.style();
047 this.out = null;
048 }
049
050 public ChunkBuffer(Pipe<Chunk> out) {
051 this.chunks = new LinkedList<Chunk>();
052 this.current = Style.style();
053 this.next = Style.style();
054 this.out = out;
055 }
056
057 public Iterator<Chunk> iterator() {
058 return chunks.iterator();
059 }
060
061 @Deprecated
062 public void writeAnsiTo(Appendable appendable) throws IOException {
063 Iterator<Chunk> iterator = iterator();
064 while (iterator.hasNext()) {
065 Chunk chunk = iterator.next();
066 if (chunk instanceof Text) {
067 Text text = (Text)chunk;
068 if (text.buffer.length() > 0) {
069 appendable.append(text.buffer);
070 }
071 } else if (chunk instanceof Style) {
072 ((Style)chunk).writeAnsiTo(appendable);
073 }
074 }
075 }
076
077 public ChunkBuffer append(Iterable<?> data) throws NullPointerException {
078 for (Object o : data) {
079 append(o);
080 }
081 return this;
082 }
083
084 public ChunkBuffer append(Object... data) throws NullPointerException {
085 for (Object o : data) {
086 append(o);
087 }
088 return this;
089 }
090
091 public ChunkBuffer cls() {
092 chunks.addLast(CLS.INSTANCE);
093 return this;
094 }
095
096 public ChunkBuffer append(Style style) throws NullPointerException {
097 next = next.merge(style);
098 return this;
099 }
100
101 public ChunkBuffer append(char c) {
102 last().buffer.append(c);
103 return this;
104 }
105
106 public ChunkBuffer append(CharSequence s) {
107 return append(s, 0, s.length());
108 }
109
110 public ChunkBuffer append(CharSequence s, int start, int end) {
111 if (end > start) {
112 last().buffer.append(s, start, end);
113 }
114 return this;
115 }
116
117 private Text last() {
118 if (!next.equals(current)) {
119 if (!Style.style().equals(next)) {
120 chunks.addLast(next);
121 }
122 current = next;
123 next = Style.style();
124 }
125 Chunk last = chunks.peekLast();
126 if (last instanceof Text) {
127 return (Text)last;
128 } else {
129 Text text = new Text();
130 chunks.addLast(text);
131 return text;
132 }
133 }
134
135 public void provide(Chunk element) throws IOException {
136 append(element);
137 }
138
139 public void flush() throws IOException {
140 if (out != null) {
141 for (Chunk chunk : chunks) {
142 out.provide(chunk);
143 }
144 }
145 chunks.clear();
146 if (out != null) {
147 out.flush();
148 }
149 }
150
151 public ChunkBuffer append(ChunkBuffer s) throws NullPointerException {
152 for (Chunk chunk : s.chunks) {
153 write(chunk);
154 }
155 if (s.next != null && !s.next.equals(Style.style())) {
156 write(s.next);
157 }
158 return this;
159 }
160
161 public void write(Chunk chunk) throws NullPointerException {
162 if (chunk instanceof Style) {
163 append((Style)chunk);
164 } else if (chunk instanceof Text){
165 append(((Text)chunk).buffer);
166 } else {
167 cls();
168 }
169 }
170
171 public ChunkBuffer append(Object o) throws NullPointerException {
172 if (o == null) {
173 throw new NullPointerException("No null accepted");
174 }
175 if (o instanceof ChunkBuffer) {
176 append((ChunkBuffer)o);
177 } else if (o instanceof Chunk) {
178 write((Chunk)o);
179 } else {
180 CharSequence s;
181 if (o instanceof CharSequence) {
182 s = (CharSequence)o;
183 } else {
184 s = o.toString();
185 }
186 append(s);
187 }
188 return this;
189 }
190
191 public boolean contains(Object o) {
192 return toString().contains(o.toString());
193 }
194
195 public boolean isEmpty() {
196 return chunks.isEmpty();
197 }
198
199 public void clear() {
200 chunks.clear();
201 }
202
203 @Override
204 public int hashCode() {
205 return toString().hashCode();
206 }
207
208 @Override
209 public boolean equals(Object obj) {
210 if (obj == this) {
211 return true;
212 }
213 if (obj instanceof ChunkBuffer) {
214 ChunkBuffer that = (ChunkBuffer)obj;
215 return toString().equals(that.toString());
216 }
217 return false;
218 }
219
220 @Override
221 public String toString() {
222 StringBuilder sb = new StringBuilder();
223 for (Chunk chunk : chunks) {
224 if (chunk instanceof Text) {
225 sb.append(((Text)chunk).buffer);
226 }
227 }
228 return sb.toString();
229 }
230
231 public void writeTo(Pipe<Chunk> writer) throws IOException {
232 for (Chunk chunk : chunks) {
233 writer.provide(chunk);
234 }
235 }
236 }