001    package org.apache.myfaces.tobago.layout;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one or more
005     * contributor license agreements.  See the NOTICE file distributed with
006     * this work for additional information regarding copyright ownership.
007     * The ASF licenses this file to You under the Apache License, Version 2.0
008     * (the "License"); you may not use this file except in compliance with
009     * the License.  You may obtain a copy of the License at
010     *
011     *      http://www.apache.org/licenses/LICENSE-2.0
012     *
013     * Unless required by applicable law or agreed to in writing, software
014     * distributed under the License is distributed on an "AS IS" BASIS,
015     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016     * See the License for the specific language governing permissions and
017     * limitations under the License.
018     */
019    
020    import org.apache.commons.lang.math.NumberUtils;
021    import org.slf4j.Logger;
022    import org.slf4j.LoggerFactory;
023    
024    import java.util.ArrayList;
025    import java.util.Iterator;
026    import java.util.List;
027    import java.util.StringTokenizer;
028    
029    public final class LayoutTokens implements Iterable<LayoutToken> {
030    
031      private static final Logger LOG = LoggerFactory.getLogger(LayoutTokens.class);
032    
033      private List<LayoutToken> tokens = new ArrayList<LayoutToken>();
034    
035      public LayoutTokens() {
036      }
037    
038      public int getSize() {
039        return tokens.size();
040      }
041    
042      public void set(int index, LayoutToken token) {
043        tokens.set(index, token);
044      }
045    
046      public boolean isEmpty() {
047        return getSize() == 0;
048      }
049    
050      public LayoutToken get(int index) {
051        return tokens.get(index);
052      }
053    
054      public void shrinkSizeTo(int size) {
055        for (int i = getSize() - 1; i >= size; i--) {
056          tokens.remove(i);
057        }
058      }
059    
060      public void ensureSize(int size, LayoutToken token) {
061        for (int index = getSize(); index < size; index++) {
062          addToken(token);
063        }
064      }
065    
066      public void addToken(LayoutToken token) {
067        tokens.add(token);
068      }
069    
070      public List<LayoutToken> getTokens() {
071        return tokens;
072      }
073    
074      public Iterator<LayoutToken> iterator() {
075        return tokens.iterator();
076      }
077    
078      public static LayoutTokens parse(String[] tokens) {
079        LayoutTokens layoutTokens = new LayoutTokens();
080        for (String token : tokens) {
081          parseToken(token, layoutTokens);
082        }
083        return layoutTokens;
084      }
085    
086      public static LayoutTokens parse(String tokens) {
087        return parse(tokens, null);
088      }
089    
090      public static LayoutTokens parse(String tokens, LayoutToken defaultToken) {
091        LayoutTokens layoutTokens = new LayoutTokens();
092        if (tokens == null) {
093          layoutTokens.addToken(defaultToken);
094          return layoutTokens;
095        }
096        StringTokenizer tokenizer = new StringTokenizer(tokens, ";");
097    
098        while (tokenizer.hasMoreTokens()) {
099          String token = tokenizer.nextToken().trim();
100          parseToken(token, layoutTokens);
101        }
102        return layoutTokens;
103      }
104    
105      private static void parseToken(String token, LayoutTokens layoutTokens) {
106        LayoutToken layoutToken = parseToken(token);
107        if (layoutToken != null) {
108          layoutTokens.addToken(layoutToken);
109        }
110      }
111    
112      public static LayoutToken parseToken(String token) {
113        try {
114          if ("*".equals(token)) {
115            return RelativeLayoutToken.DEFAULT_INSTANCE;
116          } else if (token == null) {
117            LOG.error("Empty layout token! Using 'auto' instead.");
118            return AutoLayoutToken.INSTANCE;
119          } else if ("fixed".equals(token) || "auto".equals(token)) {
120            return AutoLayoutToken.INSTANCE;
121          } else if ("minimum".equals(token)) {
122            return new MinimumLayoutToken();
123          } else if (isPixelToken(token)) {
124            return new PixelLayoutToken(Integer.parseInt(removeSuffix(token, PixelLayoutToken.SUFFIX)));
125          } else if (isPercentToken(token)) {
126            return new PercentLayoutToken(Integer.parseInt(removeSuffix(token, PercentLayoutToken.SUFFIX)));
127          } else if (isRelativeToken(token)) {
128            return new RelativeLayoutToken(Integer.parseInt(removeSuffix(token, RelativeLayoutToken.SUFFIX)));
129          } else {
130            LOG.error("Unknown layout token '" + token + "'! Using 'auto' instead.");
131            return AutoLayoutToken.INSTANCE;
132          }
133        } catch (NumberFormatException e) {
134          LOG.error("Error parsing layout token '" + token + "'! Using 'auto' instead.");
135          return AutoLayoutToken.INSTANCE;
136        }
137      }
138    
139      static boolean isPixelToken(String token) {
140        return isNumberAndSuffix(token, PixelLayoutToken.SUFFIX);
141      }
142    
143      static boolean isPercentToken(String token) {
144        return isNumberAndSuffix(token, PercentLayoutToken.SUFFIX);
145      }
146    
147      static boolean isRelativeToken(String token) {
148        return isNumberAndSuffix(token, RelativeLayoutToken.SUFFIX);
149      }
150    
151      static boolean isNumberAndSuffix(String token, String suffix) {
152        return token.endsWith(suffix)
153            && NumberUtils.isDigits(removeSuffix(token, suffix));
154      }
155    
156      private static String removeSuffix(String token, String suffix) {
157        return token.substring(0, token.length() - suffix.length());
158      }
159    
160      public String toString() {
161        StringBuilder str = new StringBuilder();
162        for (LayoutToken token : tokens) {
163          str.append(token);
164          str.append(";");
165        }
166        return str.toString();
167      }
168    
169    }