/*
Copyright (C) 2001, 2006 United States Government
as represented by the Administrator of the
National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind;

import java.util.*;

/**
 * @author Tom Gaskins
 * @version $Id: WorldWind.java 1792 2007-05-08 21:28:37Z tgaskins $
 */
//TODO: prevent circular exception loops when Resources unavailable (internationalisation)
// until that problem is solved, don't create international support for this class.
public final class WorldWind
{
    private static WorldWind instance = new WorldWind();

    private WWObjectImpl wwo = new WWObjectImpl();
    private MemoryCache memoryCache;
    private FileCache dataFileCache;
    private BasicRetrievalService retrievalService;
    private ThreadedTaskService threadedTaskService = new ThreadedTaskService();

    private WorldWind() // Singleton, prevent instantiation.
    {
        this.retrievalService = (BasicRetrievalService) createConfigurationComponent(
            AVKey.RETRIEVAL_SERVICE_CLASS_NAME);
        this.threadedTaskService = (ThreadedTaskService) createConfigurationComponent(
            AVKey.THREADED_TASK_SERVICE_CLASS_NAME);
        this.dataFileCache = (FileCache) createConfigurationComponent(AVKey.DATA_FILE_CACHE_CLASS_NAME);
        this.memoryCache = (MemoryCache) createConfigurationComponent(AVKey.MEMORY_CACHE_CLASS_NAME);
    }

    public static java.util.logging.Logger logger()
    {
        String loggerName = Configuration.getStringValue(AVKey.LOGGER_NAME);
        if (loggerName == null)
            return java.util.logging.Logger.global;

        java.util.logging.Logger logger = java.util.logging.Logger.getLogger(loggerName);
        return logger != null ? logger : java.util.logging.Logger.global;
    }

    public static MemoryCache memoryCache()
    {
        return instance.memoryCache;
    }

    public static FileCache dataFileCache()
    {
        return instance.dataFileCache;
    }

    public static RetrievalService retrievalService()
    {
        return instance.retrievalService;
    }

    public static ThreadedTaskService threadedTaskService()
    {
        return instance.threadedTaskService;
    }

    /**
     * @param className
     * @return
     * @throws WWRuntimeException       if the <code>Object</code> could not be created
     * @throws IllegalArgumentException if <code>className</code> is null or zero length
     */
    public static Object createComponent(String className) throws WWRuntimeException
    {
        if (className == null || className.length() == 0)
        {   //WorldWind.ClassNameKeyNulZero
            String message = "Class name key is null or zero length";
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new IllegalArgumentException(message);
        }

        try
        {
            Class c = Class.forName(className);
            return c.newInstance();
        }
        catch (Exception e)
        {   //WorldWind.ExceptionCreatingComponent
            String message = "Exception while creating World Wind component " + className;
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new WWRuntimeException(message, e);
        }
        catch (Throwable t)
        {   //WorldWind.ErrorCreatingComponent
            String message = "Error while creating World Wind component " + className;
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new WWRuntimeException(message, t);
        }
    }

    /**
     * @param classNameKey
     * @return
     * @throws IllegalStateException    if no name could be found which corresponds to <code>classNameKey</code>
     * @throws IllegalArgumentException if <code>classNameKey<code> is null
     * @throws WWRuntimeException       if the component could not be created
     */
    public static Object createConfigurationComponent(String classNameKey)
        throws IllegalStateException, IllegalArgumentException
    {
        if (classNameKey == null)
        {   //nullValue.ClassNameKeyNull
            String message = "Class name key is null";
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new IllegalArgumentException(message);
        }

        String name = Configuration.getStringValue(classNameKey);
        if (name == null)
        {   //WorldWind.NoClassNameInConfigurationForKey
            String message = "No class name in configuration for key " + classNameKey;
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new IllegalStateException(message);
        }

        try
        {
            return WorldWind.createComponent(name);
        }
        catch (Throwable e)
        {   //WorldWind.UnableToCreateClassForConfigurationKey
            String message = "Unable to create class for configuration key " + classNameKey;
            WorldWind.logger().log(java.util.logging.Level.FINE, message);
            throw new WWRuntimeException(message, e);
        }
    }

    public static void setValue(String key, String value)
    {
        instance.wwo.setValue(key, value);
    }

    public static Object getValue(String key)
    {
        return instance.wwo.getValue(key);
    }

    public static String getStringValue(String key)
    {
        return instance.wwo.getStringValue(key);
    }

    public static boolean hasKey(String key)
    {
        return instance.wwo.hasKey(key);
    }

    public static void removeKey(String key)
    {
        instance.wwo.removeKey(key);
    }

    /**
     * Retrieve a String resource from the "error" bundle.
     *
     * @param property The property used to identify which String to return.
     * @return the requested String.
     */
    public static String retrieveErrMsg(String property)
    {
        ResourceBundle res = ResourceBundle.getBundle("ErrorStrings", Locale.getDefault());
        return (String) res.getObject(property);
    }

    public static String retrieveMessage(String property, String bundle)
    {
        ResourceBundle res = ResourceBundle.getBundle(bundle, Locale.getDefault());
        return (String) res.getObject(property);
    }
}
