/*
 * @(#)Resource.java - resource and i18n
 *
 * Copyright (c) 2004-2005 by pstorch, All rights reserved.
 * 
 * This file is part of ProjectX, a free Java based demux utility.
 * By the authors, ProjectX is intended for educational purposes only, 
 * as a non-commercial test project.
 * 
 *
 * This program is free software; you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

package net.sourceforge.dvb.projectx.common;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import java.awt.Image;
import java.awt.Toolkit;

import net.sourceforge.dvb.projectx.common.Keys;


/**
 * Project-X resource and localization handling.
 * 
 * @author Peter Storch
 */
public class Resource extends Object {
	
	/** the prefix of all pjx resource files */
	private static final String PJX_RESOURCE_PREFIX = "pjxresources";

	/** current working directory */
	public static final String workdir = System.getProperty("user.dir");
	
	/** os dependent file separator */
	public static final String filesep = System.getProperty("file.separator");

	/** the users locale */
	private static Locale locale = null;

	/** the default resource bundle */
	private static ResourceBundle defaultResource = null;

	/** the resource bundle for the current users locale or language setting */
	private static ResourceBundle resource = null;

	/**
	 * Loads a resource bundle for the given locale.
	 * 
	 * @param locale
	 * @return ResourceBundle
	 */
	private static ResourceBundle loadResourceBundle(Locale locale) throws MissingResourceException
	{
		ResourceBundle newBundle = null;
		String resourceName = PJX_RESOURCE_PREFIX + "_" + locale.getLanguage() + ".properties";
		
		// first we try to find one in the current working directory
		try 
		{
			File file = new File(workdir + filesep + resourceName);
			if (file.exists() && file.canRead())
			{
				newBundle = new PropertyResourceBundle(new FileInputStream(file));
				return newBundle;
			}
		} 
		catch (Exception e) 
		{
			// shit happens, go on and try to find one in our jar file
		}
		
		try 
		{
			URL url = Resource.class.getClassLoader().getResource(resourceName);
			newBundle = new PropertyResourceBundle(url.openStream());
		} 
		catch (Exception e) 
		{
			throw new MissingResourceException("couldn't find " + resourceName, Resource.class.getName(), resourceName);
		}
		
		return newBundle;
	}
	
	static{
		// the default resource must be available
		defaultResource = loadResourceBundle(Locale.ENGLISH);
		try 
		{
			// now try to load the resource bundle form the users locale
			resource = loadResourceBundle(Locale.getDefault());
		} catch (MissingResourceException e) {
			// our fallback is english
			resource = defaultResource;
		}
	}
		
	/**
	 * Constructor of Resource.
	 */
	private Resource()
	{
		// singleton
	}
	
	/**
	 * Loads Language from ini file.
	 * 
	 * @param filename Name of the inifile.
	 */
	public static void loadLang(String lang)
	{
		locale = new Locale(lang, "");

		try {
			resource = loadResourceBundle(locale);
		} catch (MissingResourceException e) {
			// our fallback is english
			resource = defaultResource;
		}

		// initialize languages dependent keys
		new Keys();
	}
		
	/**
	 *
	 */
	public static String getChosenLanguage()
	{
		if (locale == null)
			return null;

		return locale.getLanguage();
	}

	/**
	 *
	 */
	public static void setChosenLanguage(String str)
	{
		if (str == null)
			locale = null;

		else
			locale = new Locale(str, "", "");
	}

		
	/**
	 * Gets a String from the Resource file. If the key is not found, the key
	 * itself is returned as text.
	 * 
	 * @param key
	 * @return String
	 */
	public static String getString(String key)
	{
		String text = null;

		try 
		{
			text = resource.getString(key);
		} 
		catch (MissingResourceException e) 
		{
			try 
			{
				// fallback to defaultResource
				text = defaultResource.getString(key);
			} 
			catch (MissingResourceException e2) 
			{
				System.out.println("ResourceKey '" + key + "' not found in pjxresources");
			}
		}
		
		// use key as text as fallback
		if (text == null)
		{
			text = "?" + key + "?";
		}
		
		return text;
	}

	/**
	 * Returns a resource String as a String Array of lines.
	 * 
	 * @return String[]
	 */
	public static String[] getStringByLines(String key)
	{
		List lines = new ArrayList();
		StringTokenizer st = new StringTokenizer(getString(key), "\n");
		while (st.hasMoreTokens())
		{
			lines.add(st.nextToken());
		}
		
		return (String[])lines.toArray(new String[0]);
	}

	/**
	 * Gets a String from the resource and inserts optional arguments.
	 * 
	 * @param key
	 * @param args
	 * @return
	 */
	public static String getString(String key, Object args[])
	{
		return MessageFormat.format(getString(key), args);
	}
	
	/**
	 * Gets a String from the resource and inserts an optional argument.
	 * 
	 * @param key
	 * @param args
	 * @return
	 */
	public static String getString(String key, Object arg)
	{
		return MessageFormat.format(getString(key), new Object[]{arg});
	}

	/**
	 * Gets a String from the resource and inserts two optional arguments.
	 * 
	 * @param key
	 * @param arg1
	 * @param arg2
	 * @return
	 */
	public static String getString(String key, Object arg1, Object arg2)
	{
		return MessageFormat.format(getString(key), new Object[]{arg1, arg2});
	}

	/**
	 * Gets a String from the resource and inserts three optional arguments.
	 * 
	 * @param key
	 * @param arg1
	 * @param arg2
	 * @param arg3
	 * @return
	 */
	public static String getString(String key, Object arg1, Object arg2, Object arg3)
	{
		return MessageFormat.format(getString(key), new Object[]{arg1, arg2, arg3});
	}

	/**
	 * Gets a String from the resource and inserts four optional arguments.
	 * 
	 * @param key
	 * @param arg1
	 * @param arg2
	 * @param arg3
	 * @param arg4
	 * @return
	 */
	public static String getString(String key, Object arg1, Object arg2, Object arg3, Object arg4)
	{
		return MessageFormat.format(getString(key), new Object[]{arg1, arg2, arg3, arg4});
	}

	/**
	 * Gets a String from the resource and inserts five optional arguments.
	 * 
	 * @param key
	 * @param arg1
	 * @param arg2
	 * @param arg3
	 * @param arg4
	 * @param arg5
	 * @return
	 */
	public static String getString(String key, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5)
	{
		return MessageFormat.format(getString(key), new Object[]{arg1, arg2, arg3, arg4, arg5});
	}

	
	/**
	 * Returns the available Locales for pjxresources.
	 * 
	 * @return Locale[]
	 */
	public static Locale[] getAvailableLocales() {
		Set locales = new HashSet();
		String defLang = Locale.getDefault().getLanguage();

		try {
			// we know we have an english resource, so first find this one to find the location
			URL url = ClassLoader.getSystemResource(PJX_RESOURCE_PREFIX + "_en.properties");
			if (url != null) {
				URLConnection urlc = null;
				urlc = url.openConnection();
				
				// If the resources are located in a JAR file, we need this
				// version to get the available locales.
				if (urlc != null && urlc instanceof JarURLConnection) {
					JarURLConnection jurlc = (JarURLConnection) urlc;
					addAvailableLocalesFromJar(locales, jurlc);
				}
				// .. else if the resources are in the file system, we use the
				// default version to get the available locales.
				else {
					File enFile = new File(url.getFile());
					File dir = enFile.getParentFile();
					addAvailableLocalesFromFileSystem(locales, dir);
				}
			} else {
				System.err.println("Couldn't find \"" + PJX_RESOURCE_PREFIX
						+ "\"*.properties");
			}
			
			// also look into the current working directory for additional resource files
			File workDirFile = new File(workdir);
			addAvailableLocalesFromFileSystem(locales, workDirFile);
		} catch (Exception e) {
			System.out.println(e);
		}
		
		return (Locale[])locales.toArray(new Locale[0]);
	}
	
	/**
	 * Adds available Locales from the file system.
	 * 
	 * @param locales
	 * @param dir
	 */
	private static void addAvailableLocalesFromFileSystem(Set locales, File dir) {
		File[] files = dir.listFiles();
		if (files != null) {
			for (int i = 0; i < files.length; i++) {
				File file = files[i];
				if (file.isFile() && file.getName().startsWith(PJX_RESOURCE_PREFIX))
				{
					try {
						String code = file.getName();
						int pos = code.indexOf('_');
						if (pos != -1) {
							code = code.substring(pos + 1);
						}
						pos = code.indexOf('.');
						if (pos != -1)
						{
							code = code.substring(0, pos);
						}
						Locale locale = new Locale(code, "");
						locales.add(locale);
					} catch (Exception e) {
						System.out.println(e);
					}
				}
			}
		}
	}

	/**
	 * Adds available Locales from a Jar file location
	 * 
	 * @param locales
	 * @param jurlc
	 */
	private static void addAvailableLocalesFromJar(Set locales, JarURLConnection jurlc) {
		JarFile jarf = null;
		try {
			jarf = jurlc.getJarFile();
		} catch (Exception e) {
			System.out.println(e);
		}
		if (jarf != null) {
			for (Enumeration en = jarf.entries(); en.hasMoreElements();) {
				JarEntry jare = (JarEntry) en.nextElement();
				String name = jare.getName();
				if (name.startsWith(PJX_RESOURCE_PREFIX)) {
					String code = name.substring(0,
							name.length() - ".properties".length());
					int pos = code.indexOf('_');
					if (pos != -1) {
						code = code.substring(pos + 1);
					}
					pos = code.indexOf('.');
					if (pos != -1)
					{
						code = code.substring(0, pos);
					}
					Locale locale = new Locale(code, "");
					locales.add(locale);
				}
			}
		}
	}

	/**
	 * Returns a resource (e.g. from the jar file) as an URL.
	 * 
	 * @param resource the name of the resource
	 * @return URL
	 */
	public static URL getResourceURL(String resource)
	{
		try
		{
			String filename = workdir + filesep + resource;
			File file = new File(filename);
			if (file.exists() && file.canRead())
			{
				return file.toURL();
			}
		}
		catch(Exception e)
		{
			// ignore it, it was just a try to get this resource from the filesystem
		}
		
		// for the classloader we need to replace all backslashes to forward slashes.
		// this is only necessary on windows systems and doesn't harm others
		resource = resource.replace('\\', '/');
		
		// ok, not founde in the filesystem, now try the classloader
		return Resource.class.getClassLoader().getResource(resource);
	}

	/**
	 * Returns a resource (e.g. from the jar file) as an URL.
	 * 
	 * @param resourceName the name of the resource
	 * @return URL
	 */
	public static URL getLocalizedResourceURL(String path, String resourceName)
	{
		Locale usedLocale = null;
		if (locale != null)
		{
			usedLocale = locale;
		}
		else
		{
			usedLocale = Locale.getDefault();
		}

		String localizedResource = path + filesep + usedLocale.getLanguage() + filesep + resourceName;
		
		URL url = getResourceURL(localizedResource);
		if (url != null)
		{
			return url;
		}

		// there is no localized version of this file, try the default version
		return getResourceURL(path + filesep + resourceName);
	}

	/**
	 * 
	 */
	public static Image loadImage(String imageName)
	{
		try {
			return Toolkit.getDefaultToolkit().createImage(getResourceURL(imageName));

		} catch (Exception e) {
			return null;
		}
	}
	
}
