/*
 * LayeredProperties.java  $Revision: 1.9 $  $Date: 2007/10/03 04:59:32 $
 *
 * Copyright (C) 2007 Meldcraft Corporation
 *
 * This file is part of Scaffold.
 * 
 * Scaffold is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Scaffold is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with Scaffold.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.meldcraft.util;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;

/**
 * @version $Revision: 1.9 $ $Date: 2007/10/03 04:59:32 $
 * @author Rob Richards
 */
public class LayeredProperties
{
// Static variables
    public static final String BASE_KEY = "baseResourceLayers";

//  Member variables
//  Constructors and initialization
//  Public methods
    public static Map getProperties(Object reference) throws IOException
    {
        return getProperties(reference, Locale.getDefault());
    }

    public static Map getProperties(Object reference, Locale locale) throws IOException
    {
        Class clazz = reference.getClass();
        if (reference instanceof Class)
        {
            clazz = (Class)reference;
        }
        String name = clazz.getName().replace('.', '/');
        return getProperties(reference, new String[] {name}, locale);
    }

    public static Map getProperties(Object reference, String[] resourceNames) throws IOException
    {
        return getProperties(reference, resourceNames, Locale.getDefault());
    }

    public static Map getProperties(Object reference, String[] resourceNames, Locale locale) throws IOException
    {
        LayeredProperties lp = new LayeredProperties();
        return lp.loadProperties(reference, resourceNames, locale);
    }

    public static URL[] getResources(Object reference) throws IOException
    {
        return getResources(reference, Locale.getDefault());
    }

    public static URL[] getResources(Object reference, Locale locale) throws IOException
    {
        String name = reference.getClass().getName().replace('.', '/');
        return getResources(reference, new String[] {name}, locale);
    }

    public static URL[] getResources(Object reference, String[] resourceNames) throws IOException
    {
        return getResources(reference, resourceNames, Locale.getDefault());
    }

    public static URL[] getResources(Object reference, String[] resourceNames, Locale locale) throws IOException
    {
        LayeredProperties lp = new LayeredProperties();
        return lp.findResources(reference, resourceNames, locale);
    }

//  Protected methods
    protected Map loadProperties(Object reference, String[] resourceNames, Locale locale) throws IOException
    {
        Map ret = null;

        URL[] urls = findResources(reference, resourceNames, locale);
        if (urls != null)
        {
            ret = new HashMap();
            PropertiesHelper.insertStringArray(ret, Integer.MAX_VALUE, BASE_KEY, resourceNames);

            for (int i=urls.length-1 ; i >= 0 ; i--)
            {
                Map imap = new HashMap();
                Properties props = new Properties();
                props.load(urls[i].openStream());

                Object impobj = props.get(BASE_KEY);
                if (impobj instanceof String)
                {
                    String[] imports = PropertiesHelper.getStringArray((String)impobj);
                    if (imports != null)
                    {
                        for (int j=0 ; j < imports.length ; j++)
                        {
                            imports[j] = imports[j].replace('.', '/');
                        }
                        Map map = loadProperties(reference, imports, locale);
                        imap.putAll(map);
                        String[] bases = PropertiesHelper.getStringArray(map, BASE_KEY);
                        if (bases != null)
                        {
                            PropertiesHelper.insertStringArray(ret, Integer.MAX_VALUE, BASE_KEY, bases);
                        }
                    }
                }

                props.remove(BASE_KEY);
                imap.remove(BASE_KEY);
                Object[] keys = props.keySet().toArray();
                for (int j=0 ; j < keys.length ; j++)
                {
                    String key = (String)keys[j];
                    add(imap, key, props.getProperty(key));
                }
                ret.putAll(imap);
            }
        }

        return ret;
    }

    protected URL[] findResources(Object reference, String[] resourceNames, Locale locale) throws IOException
    {
        URL[] ret = null;

        ArrayList list = new ArrayList();
        for (int ri=resourceNames.length-1 ; ri >= 0 ; ri--)
        {
            String resourceName = resourceNames[ri];

            String[] names = getResourceVariants(resourceName, Locale.getDefault());
            if ((names != null) && (names.length > 0))
            {
                Class clazz = reference.getClass();
                if (reference instanceof Class)
                {
                    clazz = (Class)reference;
                }

                ClassLoader loader = clazz.getClassLoader();
                if (loader == null)
                {
                    loader = ClassLoader.getSystemClassLoader();
                }

                for (int i=0 ; i < names.length ; i++)
                {
                    URL[] urls = (URL[])java.util.Collections.list(loader.getResources(names[i] + ".properties")).toArray(new URL[0]);
                    if (urls != null)
                    {
                        for (int j=0 ; j < urls.length ; j++)
                        {
                            list.add(urls[j]);
                        }
                    }
                }
            }
        }

        if (list.size() > 0)
        {
            ret = (URL[])list.toArray(new URL[list.size()]);
        }

        return ret;
    }

    protected String[] getResourceVariants(String resourceName, Locale locale)
    {
        ArrayList result = new ArrayList(5);

        String language = locale.getLanguage();
        int languageLength = language.length();
        String country = locale.getCountry();
        int countryLength = country.length();
        String variant = locale.getVariant();
        int variantLength = variant.length();

        result.add(resourceName);

        if (languageLength + countryLength + variantLength > 0)
        {
            StringBuffer temp = new StringBuffer(resourceName);

            temp.append('_');
            temp.append(language);
            if (languageLength > 0) {
                result.add(temp.toString());
            }

            if (countryLength + variantLength > 0)
            {
                temp.append('_');
                temp.append(country);
                if (countryLength > 0) {
                    result.add(temp.toString());
                }

                if (variantLength > 0)
                {
                    temp.append('_');
                    temp.append(variant);
                    result.add(temp.toString());
                }
            }
        }

        return (String[])result.toArray(new String[result.size()]);
    }

    protected void add(Map map, String key, String value)
    {
        PropertiesHelper.add(map, key, value);
    }

//  Private methods
//  Inner classes
}



