001    // Copyright 2004, 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.hivemind.util;
016    
017    import java.util.Locale;
018    import java.util.NoSuchElementException;
019    
020    import org.apache.hivemind.HiveMind;
021    
022    /**
023     *  Used in a wide variety of resource searches.  Generates
024     *  a series of name variations from a base name, a 
025     *  {@link java.util.Locale} and an optional suffix.
026     *
027     *  @author Howard Lewis Ship
028     */
029    
030    public class LocalizedNameGenerator
031    {
032        private int _baseNameLength;
033        private String _suffix;
034        private StringBuffer _buffer;
035        private String _language;
036        private String _country;
037        private String _variant;
038        private int _state;
039        private int _prevState;
040    
041        private static final int INITIAL = 0;
042        private static final int LCV = 1;
043        private static final int LC = 2;
044        private static final int LV = 3;
045        private static final int L = 4;
046        private static final int BARE = 5;
047        private static final int EXHAUSTED = 6;
048    
049        public LocalizedNameGenerator(String baseName, Locale locale, String suffix)
050        {
051            _baseNameLength = baseName.length();
052    
053            if (locale != null)
054            {
055                _language = locale.getLanguage();
056                _country = locale.getCountry();
057                _variant = locale.getVariant();
058            }
059    
060            _state = INITIAL;
061            _prevState = INITIAL;
062    
063            _suffix = suffix;
064    
065            _buffer = new StringBuffer(baseName);
066    
067            advance();
068        }
069    
070        private void advance()
071        {
072            _prevState = _state;
073    
074            while (_state != EXHAUSTED)
075            {
076                _state++;
077    
078                switch (_state)
079                {
080                    case LCV :
081    
082                        if (HiveMind.isBlank(_variant))
083                            continue;
084    
085                        return;
086    
087                    case LC :
088    
089                        if (HiveMind.isBlank(_country))
090                            continue;
091    
092                        return;
093    
094                    case LV :
095    
096                        // If _country is null, then we've already generated this string
097                        // as state LCV and we can continue directly to state L
098    
099                        if (HiveMind.isBlank(_variant) || HiveMind.isBlank(_country))
100                            continue;
101    
102                        return;
103    
104                    case L :
105    
106                        if (HiveMind.isBlank(_language))
107                            continue;
108    
109                        return;
110    
111                    case BARE :
112                    default :
113                        return;
114                }
115            }
116        }
117    
118        /**
119         *  Returns true if there are more name variants to be
120         *  returned, false otherwise.
121         * 
122         **/
123    
124        public boolean more()
125        {
126            return _state != EXHAUSTED;
127        }
128    
129        /**
130         *  Returns the next localized variant.
131         * 
132         *  @throws NoSuchElementException if all variants have been
133         *  returned.
134         * 
135         **/
136    
137        public String next()
138        {
139            if (_state == EXHAUSTED)
140                throw new NoSuchElementException();
141    
142            String result = build();
143    
144            advance();
145    
146            return result;
147        }
148    
149        private String build()
150        {
151            _buffer.setLength(_baseNameLength);
152    
153            if (_state == LC || _state == LCV || _state == L)
154            {
155                _buffer.append('_');
156                _buffer.append(_language);
157            }
158    
159            // For LV, we want two underscores between language
160            // and variant.
161    
162            if (_state == LC || _state == LCV || _state == LV)
163            {
164                _buffer.append('_');
165    
166                if (_state != LV)
167                    _buffer.append(_country);
168            }
169    
170            if (_state == LV || _state == LCV)
171            {
172                _buffer.append('_');
173                _buffer.append(_variant);
174            }
175    
176            if (_suffix != null)
177                _buffer.append(_suffix);
178    
179            return _buffer.toString();
180        }
181    
182        public Locale getCurrentLocale()
183        {
184            switch (_prevState)
185            {
186                case LCV :
187    
188                    return new Locale(_language, _country, _variant);
189    
190                case LC :
191    
192                    return new Locale(_language, _country, "");
193    
194                case LV :
195    
196                    return new Locale(_language, "", _variant);
197    
198                case L :
199    
200                    return new Locale(_language, "", "");
201    
202                default :
203                    return null;
204            }
205        }
206    }