/*
 * ResourceBundleHelper.java
 *
 * Created on 15 September 2003, 12:46
 */

package org.bodington.util;

import java.util.*;

/**
 *  Helper class to get over inadequacies of ResourceBundle Scheme.
 *  To work properly the default, top level resource bundle must be
 *  empty and the "en" locale must be complete.
 *
 * @author  jrm
 */
public class ResourceBundleHelper
{
    private static Hashtable instances = new Hashtable();
    
    private class AcceptableLocale
    {
        Locale locale;
        double q;
    }

    private class AcceptableLocaleComparator implements Comparator
    {
        public int compare(Object o1, Object o2)
        {
            if ( o1 == null )
                if ( o2 == null )
                    return 0;
                else
                    return 1;
            if ( o2 == null )
                return -1;
            
            if ( !(o1 instanceof AcceptableLocale) || !(o2 instanceof AcceptableLocale) )
                return 0;
            AcceptableLocale a1, a2;
            a1 = (AcceptableLocale)o1;
            a2 = (AcceptableLocale)o2;
            
            if ( a1.q < a2.q )
                return 1;
            if ( a1.q > a2.q )
                return -1;
            return 0;
        }
        
        public boolean equals( Object o )
        {
            return  o instanceof AcceptableLocaleComparator;
        }
    }

    String basename;
    private AcceptableLocale[] locales_in_order;
    
    
    /** Creates a new instance of ResourceBundleHelper */
    private ResourceBundleHelper( String basename, String accepts )
    {
        this.basename = basename;
        StringTokenizer tok = new StringTokenizer( accepts, "," );
        locales_in_order = new AcceptableLocale[ tok.countTokens() + 1 ];
        StringTokenizer spec, lspec;
        String qspec;
        int count, i;
        
        for ( i=0; tok.hasMoreTokens(); i++ )
        {
            locales_in_order[i] = new AcceptableLocale();
            
            spec = new StringTokenizer( tok.nextToken(), " ;" );
            lspec = new StringTokenizer( spec.nextToken(), "-" );
            count = lspec.countTokens();
            
            if ( count < 1 || count > 3 )
                throw new IllegalArgumentException( "Language spec must have one to three parts." );

            if ( count == 1 )
                locales_in_order[i].locale = new Locale( lspec.nextToken() );
            if ( count == 2 )
                locales_in_order[i].locale = new Locale( lspec.nextToken(), lspec.nextToken() );
            if ( count == 3 )
                locales_in_order[i].locale = new Locale( lspec.nextToken(), lspec.nextToken(), lspec.nextToken() );
            
            locales_in_order[i].q = 1.0;
            if ( spec.hasMoreTokens() )
            {
                qspec = spec.nextToken();
                if ( qspec.startsWith( "q=" ) )
                {
                    locales_in_order[i].q = Double.parseDouble( qspec.substring( 2 ) );
                }
            }
        }
        
        
        locales_in_order[i] = new AcceptableLocale();
        locales_in_order[i].locale = new Locale( "en" );
        locales_in_order[i].q = 0.0000000001;
        
        Arrays.sort( locales_in_order, new ResourceBundleHelper.AcceptableLocaleComparator() );
    }
    
    public static ResourceBundleHelper getResourceBundleHelper( String basename, String accepts )
    {
        synchronized ( instances )
        {
            if ( accepts == null )
                return getResourceBundleHelper( basename, "" );

            ResourceBundleHelper helper = (ResourceBundleHelper)instances.get( basename + ":" + accepts );
            if ( helper != null )
                return helper;

            try
            {
                helper = new ResourceBundleHelper( basename, accepts );
            }
            catch ( Exception e )
            {
                return null;
            }

            instances.put( basename + ":" + accepts, helper );
            
            return helper;
        }
    }
    

    public String getString( String key )
    {
        ResourceBundle bundle;
        String value;
        for ( int i=0; i<locales_in_order.length; i++ )
        {
            if ( locales_in_order[i] == null )
                continue;
            
            if ( locales_in_order[i].locale == null )
                continue;
            
            bundle = ResourceBundle.getBundle( basename, locales_in_order[i].locale );
            if ( bundle == null )
                continue;
            
            if ( !locales_in_order[i].locale.equals( bundle.getLocale() ) )
                continue;
            
            value = bundle.getString( key );
            if ( value == null )
                continue;
            
            return value;
        }
        
        return null;
    }
    
    public Locale getTopLocale()
    {
        return locales_in_order[0].locale;
    }
}
