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.util;
021    
022    import java.util.Iterator;
023    import java.util.NoSuchElementException;
024    
025    public class CharSlicer {
026    
027      /** . */
028      private final String value;
029    
030      /** . */
031      private Pair<Integer, Integer> size;
032    
033      public CharSlicer(String value) {
034        this.value = value;
035        this.size = size();
036      }
037    
038      public Pair<Integer, Integer> size() {
039        if (size == null) {
040          size = size(value, 0, 1);
041        }
042        return size;
043      }
044    
045      private static Pair<Integer, Integer> size(String s, int index, int height) {
046        if (index < s.length()) {
047          int pos = s.indexOf('\n', index);
048          if (pos == -1) {
049            return Pair.of(s.length() - index, height);
050          } else {
051            Pair<Integer, Integer> ret = size(s, pos + 1, height + 1);
052            return new Pair<Integer, Integer>(Math.max(pos - index, ret.getFirst()), ret.getSecond());
053          }
054        } else {
055          return Pair.of(0, height);
056        }
057      }
058    
059      public Pair<Integer, Integer>[] lines(final int width) {
060        return lines(linesIterator(width), 0);
061      }
062    
063      private Pair<Integer, Integer>[] lines(Iterator<Pair<Integer, Integer>> i, int count) {
064        Pair<Integer, Integer>[] lines;
065        if (i.hasNext()) {
066          Pair<Integer, Integer> n = i.next();
067          lines = lines(i, count + 1);
068          lines[count] = n;
069        } else {
070          lines = new Pair[count];
071        }
072        return lines;
073      }
074    
075      public Iterator<Pair<Integer, Integer>> linesIterator(final int width) {
076    
077        return new BaseIterator<Pair<Integer, Integer>>() {
078    
079          /** . */
080          int index = 0;
081    
082          /** . */
083          Pair<Integer, Integer> next = null;
084    
085          public boolean hasNext() {
086            if (next == null) {
087              if (index != Integer.MAX_VALUE) {
088                int pos = value.indexOf('\n', index);
089                int nextIndex;
090                if (pos == -1) {
091                  pos = Math.min(index + width, value.length());
092                  nextIndex = pos;
093                } else {
094                  if (pos <= index + width) {
095                    nextIndex = pos + 1;
096                  } else {
097                    nextIndex = pos = index + width;
098                  }
099                }
100                next = Pair.of(index, pos);
101                if (pos < value.length()) {
102                  index = nextIndex;
103                } else {
104                  // Stop value
105                  index = Integer.MAX_VALUE;
106                }
107              }
108            }
109            return next != null;
110          }
111    
112          public Pair<Integer, Integer> next() {
113            if (!hasNext()) {
114              throw new NoSuchElementException();
115            }
116            Pair<Integer, Integer> next = this.next;
117            this.next = null;
118            return next;
119          }
120        };
121      }
122    }