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 (height < 1) {
047          throw new IllegalArgumentException("A non positive height=" + height + " cannot be accepted");
048        }
049        if (index < s.length()) {
050          int pos = s.indexOf('\n', index);
051          if (pos == -1) {
052            return Pair.of(s.length() - index, height);
053          } else {
054            Pair<Integer, Integer> ret = size(s, pos + 1, height + 1);
055            return new Pair<Integer, Integer>(Math.max(pos - index, ret.getFirst()), ret.getSecond());
056          }
057        } else {
058          return Pair.of(0, height);
059        }
060      }
061    
062      public Pair<Integer, Integer>[] lines(final int width) {
063        return lines(linesIterator(width), 0);
064      }
065    
066      private Pair<Integer, Integer>[] lines(Iterator<Pair<Integer, Integer>> i, int count) {
067        Pair<Integer, Integer>[] lines;
068        if (i.hasNext()) {
069          Pair<Integer, Integer> n = i.next();
070          lines = lines(i, count + 1);
071          lines[count] = n;
072        } else {
073          lines = new Pair[count];
074        }
075        return lines;
076      }
077    
078      public Iterator<Pair<Integer, Integer>> linesIterator(final int width) {
079        if (width < 1) {
080          throw new IllegalArgumentException("A non positive width=" + width + " cannot be accepted");
081        }
082        return new BaseIterator<Pair<Integer, Integer>>() {
083    
084          /** . */
085          int index = 0;
086    
087          /** . */
088          Pair<Integer, Integer> next = null;
089    
090          public boolean hasNext() {
091            if (next == null) {
092              if (index != Integer.MAX_VALUE) {
093                int pos = value.indexOf('\n', index);
094                int nextIndex;
095                if (pos == -1) {
096                  pos = Math.min(index + width, value.length());
097                  nextIndex = pos;
098                } else {
099                  if (pos <= index + width) {
100                    nextIndex = pos + 1;
101                  } else {
102                    nextIndex = pos = index + width;
103                  }
104                }
105                next = Pair.of(index, pos);
106                if (pos < value.length()) {
107                  index = nextIndex;
108                } else {
109                  // Stop value
110                  index = Integer.MAX_VALUE;
111                }
112              }
113            }
114            return next != null;
115          }
116    
117          public Pair<Integer, Integer> next() {
118            if (!hasNext()) {
119              throw new NoSuchElementException();
120            }
121            Pair<Integer, Integer> next = this.next;
122            this.next = null;
123            return next;
124          }
125        };
126      }
127    }