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 }