001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/csct/units/PrefixSet.java $
002    /*
003     * Map and oceanographical data visualisation
004     * Copyright (C) 1998 University Corporation for Atmospheric Research (Unidata)
005     *               1998 Bill Hibbard & al. (VisAD)
006     *               1999 P�ches et Oc�ans Canada
007     *               2000 Institut de Recherche pour le D�veloppement
008     *
009     *
010     *    This library is free software; you can redistribute it and/or
011     *    modify it under the terms of the GNU Library General Public
012     *    License as published by the Free Software Foundation; either
013     *    version 2 of the License, or (at your option) any later version.
014     *
015     *    This library is distributed in the hope that it will be useful,
016     *    but WITHOUT ANY WARRANTY; without even the implied warranty of
017     *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
018     *    Library General Public License for more details (http://www.gnu.org/).
019     *
020     *
021     * Contacts:
022     *     FRANCE: Surveillance de l'Environnement Assist�e par Satellite
023     *             Institut de Recherche pour le D�veloppement / US-Espace
024     *             mailto:seasnet@teledetection.fr
025     *
026     *     CANADA: Observatoire du Saint-Laurent
027     *             Institut Maurice-Lamontagne
028     *             mailto:osl@osl.gc.ca
029     *
030     *
031     *    This package is inspired from the units package of VisAD.
032     *    Unidata and Visad's work is fully acknowledged here.
033     *
034     *                   THIS IS A TEMPORARY CLASS
035     *
036     *    This is a placeholder for future <code>Unit</code> class.
037     *    This skeleton will be removed when the real classes from
038     *    JSR-108: Units specification will be publicly available.
039     */
040    package org.deegree.model.csct.units;
041    
042    // Entr�s/sorties
043    import java.io.Serializable;
044    import java.util.Arrays;
045    
046    import org.deegree.model.csct.resources.WeakHashSet;
047    
048    /**
049     * Ensemble de pr�fix. Cette classe maintient une liste d'objets
050     * {@link Prefix} en ordre croissant et sans doublons, c'est-�-dire qu'elle garanti
051     * qu'il n'y aura pas deux pr�fix repr�sentant la m�me quantit� {@link Prefix#amount}.
052     *
053     * @version 1.0
054     * @author Martin Desruisseaux
055     */
056    /*public*/final class PrefixSet implements Serializable {
057        /**
058         * Banque des objets qui ont �t� pr�c�demment cr��s et
059         * enregistr�s par un appel � la m�thode {@link #intern}.
060         */
061        private static final WeakHashSet pool = Prefix.pool;
062    
063        /**
064         * Ensemble de pr�fix. Les pr�fix de cet ensemble doivent
065         * obligatoirement �tre un ordre croissant et sans doublons.
066         */
067        private final Prefix[] prefix;
068    
069        /**
070         * Construit un ensemble de pr�fix. Le tableau <code>p</code>
071         * sera copi�, puis class�. Les �ventuels doublons seront �limin�s.
072         * Le tableau <code>p</code> original ne sera pas affect� par ces
073         * traitements.
074         */
075        private PrefixSet( final Prefix[] p ) {
076            final Prefix[] px = new Prefix[p.length];
077            System.arraycopy( p, 0, px, 0, px.length );
078            Arrays.sort( px );
079            int length = px.length;
080            for ( int i = length; --i >= 1; ) {
081                if ( px[i].amount == px[i - 1].amount ) {
082                    px[i] = null;
083                    length--;
084                }
085            }
086            int i = 0;
087            prefix = new Prefix[length];
088            for ( int j = 0; j < px.length; j++ )
089                if ( px[j] != null )
090                    prefix[i++] = px[j];
091            //----- BEGIN JDK 1.4 DEPENDENCIES ----
092            //        assert i==length;
093            //----- END OF JDK 1.4 DEPENDENCIES ----
094        }
095    
096        /**
097         * Construit un ensemble de pr�fix. Le tableau <code>p</code>
098         * sera copi�, puis class�. Les �ventuels doublons seront �limin�s.
099         * Le tableau <code>p</code> original ne sera pas affect� par ces
100         * traitements.
101         */
102        public static PrefixSet getPrefixSet( final Prefix[] p ) {
103            return new PrefixSet( p ).intern();
104        }
105    
106        /**
107         * Retourne le pr�fix repr�sent� par le symbole sp�fifi�.
108         * Si aucun pr�fix ne correspond � ce symbole, retourne
109         * <code>null</code>.
110         *
111         * @param  symbol Symbole du pr�fix recherch�.
112         * @return Pr�fix d�sign� par le symbole <code>symbol</code>.
113         */
114        public Prefix getPrefix( final String symbol ) {
115            for ( int i = 0; i < prefix.length; i++ ) {
116                final Prefix p = prefix[i];
117                if ( symbol.equals( p.symbol ) )
118                    return p;
119            }
120            return null;
121        }
122    
123        /**
124         * Retourne le pr�fix repr�sentant une quantit� �gale ou inf�rieure � la quantit� sp�cifi�e.
125         * Si <code>amount</code> est inf�rieur � la plus petite quantit� pouvant �tre repr�sent�
126         * par un pr�fix, alors cette m�thode retourne <code>null</code>.
127         */
128        public Prefix getPrefix( double amount ) {
129            amount += 1E-8 * Math.abs( amount ); // Pour �viter d'�ventuelles erreurs d'arrondissements.
130            int index = Arrays.binarySearch( prefix, new Prefix( amount ) );
131            if ( index < 0 ) {
132                index = ~index;
133                if ( index == 0 )
134                    return null;
135                if ( index > prefix.length )
136                    index = prefix.length;
137                index--;
138            }
139            return prefix[index];
140        }
141    
142        /**
143         * Retourne une cha�ne de caract�res qui �num�re tous les pr�fix contenu dans
144         * cet ensemble. La cha�ne sera de la forme "milli(m),centi(c),d�ci(d),kilo(k)"
145         * par exemple.
146         */
147        public String toString() {
148            final StringBuffer buffer = new StringBuffer();
149            for ( int i = 0; i < prefix.length; i++ ) {
150                final Prefix p = prefix[i];
151                final String name = p.getLocalizedName();
152                final String symb = p.symbol;
153                if ( name.length() != 0 || symb.length() != 0 ) {
154                    if ( buffer.length() != 0 ) {
155                        buffer.append( ',' );
156                    }
157                    buffer.append( name );
158                    if ( symb.length() != 0 ) {
159                        buffer.append( '(' );
160                        buffer.append( symb );
161                        buffer.append( ')' );
162                    }
163                }
164            }
165            return buffer.toString();
166        }
167    
168        /**
169         * V�rifie si cet ensemble est identique � l'objet <code>other</code>
170         * sp�cifi�. Deux ensembles sont consid�r�s identiques s'ils contienent
171         * les m�mes pr�fix.
172         */
173        public boolean equals( final Object other ) {
174            if ( other == this )
175                return true; // slight optimisation
176            if ( other instanceof PrefixSet ) {
177                final Prefix[] array = ( (PrefixSet) other ).prefix;
178                if ( prefix.length == array.length ) {
179                    for ( int i = 0; i < array.length; i++ )
180                        if ( !prefix[i].equals( array[i] ) )
181                            return false;
182                    return true;
183                }
184            }
185            return false;
186        }
187    
188        /**
189         * Retourne un code repr�sentant cet ensemble de pr�fix.
190         */
191        public int hashCode() {
192            int code = prefix.length << 1;
193            for ( int i = 0; i < prefix.length; i += 5 )
194                code += prefix[i].hashCode();
195            return code;
196        }
197    
198        /**
199         * Retourne un exemplaire unique de cet ensemble de pr�fix. Une banque de pr�fix, initialement
200         * vide, est maintenue de fa�on interne par la classe <code>PrefixSet</code>. Lorsque la m�thode
201         * <code>intern</code> est appel�e, elle recherchera des pr�fix �gaux � <code>this</code> au
202         * sens de la m�thode {@link #equals}. Si de tels pr�fix sont trouv�s, ils seront retourn�s.
203         * Sinon, les pr�fix <code>this</code> seront ajout�s � la banque de donn�es en utilisant une
204         * {@link java.lang.ref.WeakReference r�f�rence faible} et cette m�thode retournera <code>this</code>.
205         * <br><br>
206         * De cette m�thode il s'ensuit que pour deux ensembles de pr�fix <var>u</var> et <var>v</var>,
207         * la condition <code>u.intern()==v.intern()</code> sera vrai si et seulement si
208         * <code>u.equals(v)</code> est vrai.
209         */
210        private final PrefixSet intern() {
211            return (PrefixSet) pool.intern( this );
212        }
213    
214        /**
215         * Apr�s la lecture d'une unit�, v�rifie si ce pr�fix
216         * appara�t d�j� dans la banque des pr�fix .
217         * Si oui, l'exemplaire de la banque sera retourn� plut�t
218         * que de garder inutilement le pr�fix courant comme copie.
219         */
220        private Object readResolve() {
221            return intern();
222        }
223    }