package net.sf.jasperreports.engine.util;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

public class JRResourcesUtil {
  private static FileResolver globalFileResolver;
  
  private static ThreadLocalStack localFileResolverStack = new ThreadLocalStack();
  
  private static URLStreamHandlerFactory globalURLHandlerFactory;
  
  private static ThreadLocalStack localURLHandlerFactoryStack = new ThreadLocalStack();
  
  private static ClassLoader globalClassLoader;
  
  private static ThreadLocalStack localClassLoaderStack = new ThreadLocalStack();
  
  public static URL createURL(String spec, URLStreamHandlerFactory urlHandlerFactory) {
    URL uRL;
    URLStreamHandler handler = getURLHandler(spec, urlHandlerFactory);
    try {
      if (handler == null) {
        uRL = new URL(spec);
      } else {
        uRL = new URL(null, spec, handler);
      } 
    } catch (MalformedURLException e) {
      uRL = null;
    } 
    return uRL;
  }
  
  public static URLStreamHandler getURLHandler(String spec, URLStreamHandlerFactory urlHandlerFactory) {
    urlHandlerFactory = getURLHandlerFactory(urlHandlerFactory);
    URLStreamHandler handler = null;
    if (urlHandlerFactory != null) {
      String protocol = getURLProtocol(spec);
      if (protocol != null)
        handler = urlHandlerFactory.createURLStreamHandler(protocol); 
    } 
    return handler;
  }
  
  private static String getURLProtocol(String spec) {
    String protocol = null;
    spec = spec.trim();
    int colon = spec.indexOf(':');
    if (colon > 0) {
      String proto = spec.substring(0, colon);
      if (protocolValid(proto))
        protocol = proto; 
    } 
    return protocol;
  }
  
  private static boolean protocolValid(String protocol) {
    int length = protocol.length();
    if (length < 1)
      return false; 
    if (!Character.isLetter(protocol.charAt(0)))
      return false; 
    for (int i = 1; i < length; i++) {
      char c = protocol.charAt(i);
      if (!Character.isLetterOrDigit(c) && c != '+' && c != '-' && c != '.')
        return false; 
    } 
    return true;
  }
  
  public static FileResolver getFileResolver(FileResolver fileResolver) {
    if (fileResolver == null) {
      fileResolver = getThreadFileResolver();
      if (fileResolver == null)
        fileResolver = globalFileResolver; 
    } 
    return fileResolver;
  }
  
  public static FileResolver getGlobalFileResolver() {
    return globalFileResolver;
  }
  
  public static FileResolver getThreadFileResolver() {
    return (FileResolver)localFileResolverStack.top();
  }
  
  public static void setThreadFileResolver(FileResolver fileResolver) {
    localFileResolverStack.push(fileResolver);
  }
  
  public static void resetThreadFileResolver() {
    localFileResolverStack.pop();
  }
  
  public static void setGlobalFileResolver(FileResolver fileResolver) {
    globalFileResolver = fileResolver;
  }
  
  public static File resolveFile(String location, FileResolver fileResolver) {
    fileResolver = getFileResolver(fileResolver);
    if (fileResolver != null)
      return fileResolver.resolveFile(location); 
    File file = new File(location);
    if (file.exists() && file.isFile())
      return file; 
    return null;
  }
  
  public static URLStreamHandlerFactory getURLHandlerFactory(URLStreamHandlerFactory urlHandlerFactory) {
    if (urlHandlerFactory == null) {
      urlHandlerFactory = getThreadURLStreamHandlerFactory();
      if (urlHandlerFactory == null)
        urlHandlerFactory = globalURLHandlerFactory; 
    } 
    return urlHandlerFactory;
  }
  
  public static URLStreamHandlerFactory getGlobalURLStreamHandlerFactory() {
    return globalURLHandlerFactory;
  }
  
  public static URLStreamHandlerFactory getThreadURLStreamHandlerFactory() {
    return (URLStreamHandlerFactory)localURLHandlerFactoryStack.top();
  }
  
  public static void setThreadURLHandlerFactory(URLStreamHandlerFactory urlHandlerFactory) {
    localURLHandlerFactoryStack.push(urlHandlerFactory);
  }
  
  public static void resetThreadURLHandlerFactory() {
    localURLHandlerFactoryStack.pop();
  }
  
  public static void setGlobalURLHandlerFactory(URLStreamHandlerFactory urlHandlerFactory) {
    globalURLHandlerFactory = urlHandlerFactory;
  }
  
  public static ClassLoader getClassLoader(ClassLoader classLoader) {
    if (classLoader == null) {
      classLoader = getThreadClassLoader();
      if (classLoader == null)
        classLoader = globalClassLoader; 
    } 
    return classLoader;
  }
  
  public static ClassLoader getGlobalClassLoader() {
    return globalClassLoader;
  }
  
  public static ClassLoader getThreadClassLoader() {
    return (ClassLoader)localClassLoaderStack.top();
  }
  
  public static void setThreadClassLoader(ClassLoader classLoader) {
    localClassLoaderStack.push(classLoader);
  }
  
  public static void resetClassLoader() {
    localClassLoaderStack.pop();
  }
  
  public static void setGlobalClassLoader(ClassLoader classLoader) {
    globalClassLoader = classLoader;
  }
  
  public static URL findClassLoaderResource(String location, ClassLoader classLoader, Class clazz) {
    classLoader = getClassLoader(classLoader);
    URL url = null;
    if (classLoader != null)
      url = classLoader.getResource(location); 
    if (url == null) {
      classLoader = Thread.currentThread().getContextClassLoader();
      if (classLoader != null)
        url = classLoader.getResource(location); 
      if (url == null) {
        classLoader = clazz.getClassLoader();
        if (classLoader == null) {
          url = clazz.getResource("/" + location);
        } else {
          url = classLoader.getResource(location);
        } 
      } 
    } 
    return url;
  }
  
  public static ResourceBundle loadResourceBundle(String baseName, Locale locale) {
    return loadResourceBundle(baseName, locale, null);
  }
  
  public static ResourceBundle loadResourceBundle(String baseName, Locale locale, ClassLoader classLoader) {
    ResourceBundle resourceBundle = null;
    classLoader = getClassLoader(classLoader);
    if (classLoader != null)
      try {
        resourceBundle = ResourceBundle.getBundle(baseName, locale, classLoader);
      } catch (MissingResourceException e) {} 
    if (resourceBundle == null) {
      classLoader = Thread.currentThread().getContextClassLoader();
      if (classLoader != null)
        try {
          resourceBundle = ResourceBundle.getBundle(baseName, locale, classLoader);
        } catch (MissingResourceException e) {} 
    } 
    if (resourceBundle == null) {
      classLoader = JRClassLoader.class.getClassLoader();
      if (classLoader == null) {
        resourceBundle = ResourceBundle.getBundle(baseName, locale);
      } else {
        resourceBundle = ResourceBundle.getBundle(baseName, locale, classLoader);
      } 
    } 
    return resourceBundle;
  }
}
