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 java.io.IOException;
023    import java.io.Serializable;
024    import java.util.Iterator;
025    import java.util.LinkedList;
026    
027    public class ScreenBuffer implements Iterable<Object>, Serializable, Screenable {
028    
029      /** . */
030      private final LinkedList<Object> chunks;
031    
032      /** . */
033      private Style current;
034    
035      /** . */
036      private Style next;
037    
038      /** Where we flush. */
039      private final ScreenContext out;
040    
041      public ScreenBuffer() {
042        this.chunks = new LinkedList<Object>();
043        this.current = Style.style();
044        this.next = Style.style();
045        this.out = null;
046      }
047    
048      public ScreenBuffer(ScreenContext out) {
049        this.chunks = new LinkedList<Object>();
050        this.current = Style.style();
051        this.next = Style.style();
052        this.out = out;
053      }
054    
055      public Iterator<Object> iterator() {
056        return chunks.iterator();
057      }
058    
059      public void format(Format format, Appendable appendable) throws IOException {
060        format.begin(appendable);
061        for (Object chunk : this) {
062          if (chunk instanceof Style) {
063            format.write((Style)chunk, appendable);
064          } else if (chunk instanceof CLS) {
065            format.cls(appendable);
066          } else {
067            format.write((CharSequence)chunk, appendable);
068          }
069        }
070        format.end(appendable);
071      }
072    
073      public ScreenBuffer append(Iterable<?> data) throws NullPointerException {
074        for (Object o : data) {
075          append(o);
076        }
077        return this;
078      }
079    
080      public ScreenBuffer append(Object... data) throws NullPointerException {
081        for (Object o : data) {
082          append(o);
083        }
084        return this;
085      }
086    
087      public ScreenBuffer cls() {
088        chunks.addLast(CLS.INSTANCE);
089        return this;
090      }
091    
092      public ScreenBuffer append(Style style) throws NullPointerException {
093        next = next.merge(style);
094        return this;
095      }
096    
097      @Override
098      public ScreenBuffer append(char c) throws IOException {
099        return append(Character.toString(c));
100      }
101    
102      public ScreenBuffer append(CharSequence s) {
103        if (s.length() > 0) {
104          if (!next.equals(current)) {
105            if (!Style.style().equals(next)) {
106              chunks.addLast(next);
107            }
108            current = next;
109            next = Style.style();
110          }
111          chunks.addLast(s);
112        }
113        return this;
114      }
115    
116      public ScreenBuffer append(CharSequence s, int start, int end) {
117        if (end != start) {
118          if (start != 0 || end != s.length()) {
119            s = s.subSequence(start, end);
120          }
121          append(s);
122        }
123        return this;
124      }
125    
126      public void flush() throws IOException {
127        if (out != null) {
128          for (Object chunk : chunks) {
129            if (chunk instanceof CLS) {
130              out.cls();
131            } else if (chunk instanceof CharSequence) {
132              out.append((CharSequence)chunk);
133            } else {
134              out.append((Style)chunk);
135            }
136          }
137        }
138        chunks.clear();
139        if (out != null) {
140          out.flush();
141        }
142      }
143    
144      public ScreenBuffer append(ScreenBuffer s) throws NullPointerException {
145        for (Object chunk : s.chunks) {
146          append(chunk);
147        }
148        if (s.next != null && !s.next.equals(Style.style())) {
149          append(s.next);
150        }
151        return this;
152      }
153    
154      public ScreenBuffer append(Object o) throws NullPointerException {
155        if (o == null) {
156          throw new NullPointerException("No null accepted");
157        }
158        if (o instanceof ScreenBuffer) {
159          append((ScreenBuffer)o);
160        } else if (o instanceof Style) {
161          append((Style)o);
162        } else if (o instanceof CharSequence){
163          append(((CharSequence)o));
164        } else if (o instanceof CLS) {
165          cls();
166        } else {
167          append(o.toString());
168        }
169        return this;
170      }
171    
172      public boolean contains(Object o) {
173        return toString().contains(o.toString());
174      }
175    
176      public boolean isEmpty() {
177        return chunks.isEmpty();
178      }
179    
180      public void clear() {
181        chunks.clear();
182      }
183    
184      @Override
185      public int hashCode() {
186        return toString().hashCode();
187      }
188    
189      @Override
190      public boolean equals(Object obj) {
191        if (obj == this) {
192          return true;
193        }
194        if (obj instanceof ScreenBuffer) {
195          ScreenBuffer that = (ScreenBuffer)obj;
196          return toString().equals(that.toString());
197        }
198        return false;
199      }
200    
201      @Override
202      public String toString() {
203        StringBuilder sb = new StringBuilder();
204        try {
205          format(Format.TEXT, sb);
206        }
207        catch (IOException ignore) {
208        }
209        return sb.toString();
210      }
211    }