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 020package org.crsh.text; 021 022import org.crsh.io.Consumer; 023 024import java.io.IOException; 025import java.io.Serializable; 026import java.util.Iterator; 027import java.util.LinkedList; 028 029public class ChunkBuffer implements Iterable<Chunk>, Serializable, Consumer<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 Consumer<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(Consumer<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 public void format(Format format, Appendable appendable) throws IOException { 062 for (Chunk chunk : this) { 063 format.append(chunk, appendable); 064 } 065 } 066 067 public ChunkBuffer append(Iterable<?> data) throws NullPointerException { 068 for (Object o : data) { 069 append(o); 070 } 071 return this; 072 } 073 074 public ChunkBuffer append(Object... data) throws NullPointerException { 075 for (Object o : data) { 076 append(o); 077 } 078 return this; 079 } 080 081 public ChunkBuffer cls() { 082 chunks.addLast(CLS.INSTANCE); 083 return this; 084 } 085 086 public ChunkBuffer append(Style style) throws NullPointerException { 087 next = next.merge(style); 088 return this; 089 } 090 091 public ChunkBuffer append(Text text) { 092 CharSequence s = text.getText(); 093 if (s.length() > 0) { 094 if (!next.equals(current)) { 095 if (!Style.style().equals(next)) { 096 chunks.addLast(next); 097 } 098 current = next; 099 next = Style.style(); 100 } 101 chunks.addLast(text); 102 } 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 if (start != 0 || end != s.length()) { 113 s = s.subSequence(start, end); 114 } 115 append(Text.create(s)); 116 } 117 return this; 118 } 119 120 public Class<Chunk> getConsumedType() { 121 return Chunk.class; 122 } 123 124 public void provide(Chunk element) throws IOException { 125 append(element); 126 } 127 128 public void flush() throws IOException { 129 if (out != null) { 130 for (Chunk chunk : chunks) { 131 out.provide(chunk); 132 } 133 } 134 chunks.clear(); 135 if (out != null) { 136 out.flush(); 137 } 138 } 139 140 public ChunkBuffer append(ChunkBuffer s) throws NullPointerException { 141 for (Chunk chunk : s.chunks) { 142 write(chunk); 143 } 144 if (s.next != null && !s.next.equals(Style.style())) { 145 write(s.next); 146 } 147 return this; 148 } 149 150 public void write(Chunk chunk) throws NullPointerException { 151 if (chunk instanceof Style) { 152 append((Style)chunk); 153 } else if (chunk instanceof Text){ 154 append(((Text)chunk)); 155 } else { 156 cls(); 157 } 158 } 159 160 public ChunkBuffer append(Object o) throws NullPointerException { 161 if (o == null) { 162 throw new NullPointerException("No null accepted"); 163 } 164 if (o instanceof ChunkBuffer) { 165 append((ChunkBuffer)o); 166 } else if (o instanceof Chunk) { 167 write((Chunk)o); 168 } else { 169 CharSequence s; 170 if (o instanceof CharSequence) { 171 s = (CharSequence)o; 172 } else { 173 s = o.toString(); 174 } 175 append(s); 176 } 177 return this; 178 } 179 180 public boolean contains(Object o) { 181 return toString().contains(o.toString()); 182 } 183 184 public boolean isEmpty() { 185 return chunks.isEmpty(); 186 } 187 188 public void clear() { 189 chunks.clear(); 190 } 191 192 @Override 193 public int hashCode() { 194 return toString().hashCode(); 195 } 196 197 @Override 198 public boolean equals(Object obj) { 199 if (obj == this) { 200 return true; 201 } 202 if (obj instanceof ChunkBuffer) { 203 ChunkBuffer that = (ChunkBuffer)obj; 204 return toString().equals(that.toString()); 205 } 206 return false; 207 } 208 209 @Override 210 public String toString() { 211 StringBuilder sb = new StringBuilder(); 212 try { 213 format(Format.TEXT, sb); 214 } 215 catch (IOException ignore) { 216 } 217 return sb.toString(); 218 } 219}