/*______________________________________________________________________________
 * 
 * Copyright 2002 Paul Cantrell
 * http://innig.net/util/
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * (1) Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 * (2) Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution. 
 *
 * (3) The name of the author may not be used to endorse or promote
 *     products derived from this software without specific prior
 *     written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *_______________________________________________________________________________
 */

package net.innig.util;

import net.innig.collect.*;
import java.io.IOException;
import java.net.URL;
import java.util.*;

import java.io.PrintStream;
import net.innig.io.NullOutputStream;

public abstract class Conf
    {
    public static Properties getMergedProperties(String confName)
        { return getMergedProperties(null, confName); }
    
    public static Properties getMergedProperties(String confName, ClassLoader classLoader)
        { return getMergedProperties(null, confName, classLoader); }
    
    public static Properties getMergedProperties(Class owner, String confName)
        { return getMergedProperties(owner, confName, Thread.currentThread().getContextClassLoader()); }
    
    public static Properties getMergedProperties(Class owner, String confName, ClassLoader classLoader)
        {
        synchronized(mergedPropCache)
            {
            String resource = (owner == null)
                ? confToResourceName(confName)
                : confToResourceName(owner, confName);
            Properties props = (Properties) mergedPropCache.get(resource);
            if(props == null)
                {
                //! hack to get around bogus messages generated by Ant's classloader
                PrintStream realOut = System.out;
                PrintStream realErr = System.err;
                try {
                    System.setOut(new PrintStream(new NullOutputStream()));
                    System.setErr(new PrintStream(new NullOutputStream()));
                // end hack

                    props = new Properties();
                    Enumeration e = classLoader.getResources(resource);
                    if(e == null || !e.hasMoreElements())
                        throw new MissingConfigurationException(confName, resource);

                    List urls = InnigCollections.toList(e);
                    
                    Collections.reverse(urls);
                    for(Iterator i = urls.iterator(); i.hasNext(); )
                        props.load(((URL) i.next()).openStream());
                    mergedPropCache.put(resource, props);
                    }
                catch(IOException ioe)
                    { throw new CorruptConfigurationException(confName, ioe); }
                //! hack cleanup
                finally
                    {
                    System.setOut(realOut);
                    System.setErr(realErr);
                    }
                // end hack cleanup
                }

            return props;
            }
        }
    
    public static String confToResourceName(Class owner, String confName)
        {
        String ownerName = owner.getName();
        return confToResourceName(
            ownerName.substring(ownerName.lastIndexOf('.') + 1)
            + '.' + confName);
        }
    
    public static String confToResourceName(String confName)
        {
        StringBuffer resName = new StringBuffer();
        for(int pos = 0;;)
            {
            int next = confName.indexOf('.', pos);
            if(next != -1)
                {
                resName.append(confName.substring(pos, next));
                resName.append('/');
                pos = next + 1;
                }
            else
                {
                resName.append(confName.substring(pos));
                break;
                }
            }
        resName.append(".properties");
        return resName.toString();
        }
    
    private Conf() { }
    
    private static Map mergedPropCache = new HashMap();
    }

