001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.util.string;
018
019import java.io.Serializable;
020import java.util.ArrayList;
021import java.util.List;
022
023/**
024 * An abstract base class for string list implementations. Besides having an implementation for
025 * IStringSequence (iterator(), get(int index) and size()), an AbstractStringList can be converted
026 * to a String array or a List of Strings.
027 * <p>
028 * The total length of all Strings in the list can be determined by calling totalLength().
029 * <p>
030 * Strings or a subset of Strings in the list can be formatted using three join() methods:
031 * <p>
032 * <ul>
033 * <li>join(String) Joins strings together using a given separator
034 * <li>join() Joins Strings using comma as a separator
035 * <li>join(int first, int last, String) Joins a sublist of strings using a given separator
036 * </ul>
037 * 
038 * @author Jonathan Locke
039 */
040public abstract class AbstractStringList implements IStringSequence, Serializable
041{
042        /**
043         * 
044         */
045        private static final long serialVersionUID = 1L;
046
047        /**
048         * @return String iterator
049         * @see org.apache.wicket.util.string.IStringSequence#iterator()
050         */
051        @Override
052        public abstract IStringIterator iterator();
053
054        /**
055         * @return Number of strings in this string list
056         * @see org.apache.wicket.util.string.IStringSequence#size()
057         */
058        @Override
059        public abstract int size();
060
061        /**
062         * @param index
063         *            The index into this string list
064         * @return The string at the given index
065         * @see org.apache.wicket.util.string.IStringSequence#get(int)
066         */
067        @Override
068        public abstract String get(int index);
069
070        /**
071         * Returns this String sequence as an array of Strings. Subclasses may provide a more efficient
072         * implementation than the one provided here.
073         * 
074         * @return An array containing exactly this sequence of Strings
075         */
076        public String[] toArray()
077        {
078                // Get number of Strings
079                final int size = size();
080
081                // Allocate array
082                final String[] strings = new String[size];
083
084                // Copy string references
085                for (int i = 0; i < size; i++)
086                {
087                        strings[i] = get(i);
088                }
089
090                return strings;
091        }
092
093        /**
094         * Returns this String sequence as an array of Strings. Subclasses may provide a more efficient
095         * implementation than the one provided here.
096         * 
097         * @return An array containing exactly this sequence of Strings
098         */
099        public final List<String> toList()
100        {
101                // Get number of Strings
102                final int size = size();
103
104                // Allocate list of exactly the right size
105                final List<String> strings = new ArrayList<>(size);
106
107                // Add strings to list
108                for (int i = 0; i < size; i++)
109                {
110                        strings.add(get(i));
111                }
112
113                return strings;
114        }
115
116        /**
117         * @return The total length of all Strings in this sequence.
118         */
119        public int totalLength()
120        {
121                // Get number of Strings
122                final int size = size();
123
124                // Add strings to list
125                int totalLength = 0;
126
127                for (int i = 0; i < size; i++)
128                {
129                        totalLength += get(i).length();
130                }
131
132                return totalLength;
133        }
134
135        /**
136         * Joins this sequence of strings using a comma separator. For example, if this sequence
137         * contains [1 2 3], the result of calling this method will be "1, 2, 3".
138         * 
139         * @return The joined String
140         */
141        public final String join()
142        {
143                return join(", ");
144        }
145
146        /**
147         * Joins this sequence of strings using a separator
148         * 
149         * @param separator
150         *            The separator to use
151         * @return The joined String
152         */
153        public final String join(final String separator)
154        {
155                return join(0, size(), separator);
156        }
157
158        /**
159         * Joins this sequence of strings from first index to last using a separator
160         * 
161         * @param first
162         *            The first index to use, inclusive
163         * @param last
164         *            The last index to use, exclusive
165         * @param separator
166         *            The separator to use
167         * @return The joined String
168         */
169        public final String join(final int first, final int last, final String separator)
170        {
171                // Allocate buffer of exactly the right length
172                final int length = totalLength() + (separator.length() * (Math.max(0, last - first - 1)));
173                final AppendingStringBuffer buf = new AppendingStringBuffer(length);
174
175                // Loop through indexes requested
176                for (int i = first; i < last; i++)
177                {
178                        // Add next string
179                        buf.append(get(i));
180
181                        // Add separator?
182                        if (i != (last - 1))
183                        {
184                                buf.append(separator);
185                        }
186                }
187
188                return buf.toString();
189        }
190
191        /**
192         * Converts this object to a string representation
193         * 
194         * @return String version of this object
195         */
196        @Override
197        public String toString()
198        {
199                return "[" + join() + "]";
200        }
201}