/*
 Javier Kohen's Java Framework Classes.
 Copyright (C) 2000-2001  Javier Kohen <jkohen at tough.com>
 
 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 ar.com.jkohen.util;
 
 import java.applet.Applet;
 import java.applet.AudioClip;
 import java.awt.*;
 import java.net.*;
 import java.util.*;
 import java.io.*;
 
 import ar.com.jkohen.irc.MircMessage;
 
 public class Resources extends Observable implements Runnable
 {
 	private static Object obj;
 	private static Class cls;
 	private static ClassLoader clsld;
 	private static MediaTracker tracker;
 	private static Thread loader;
 	private static String path;
 	private static Vector files;
 
 	public static Properties lang_resource;
 	public static Properties img_resource;
 	public static String help_resource;
 
 
 	// Events sounds.

 
 	public static final int SND_ON = 0;
 	public static final int SND_OFFAWAY = 1;
 	public static final int SND_OFF = 2;
 
 	public final static int EVENT_JOIN = 0;
 	public final static int EVENT_PART = 1;
 	public final static int EVENT_OP = 2;
 	public final static int EVENT_DEOP = 3;
 	public final static int EVENT_KICK = 4;
 	public final static int EVENT_BAN = 5;
 	public final static int EVENT_QUIT = 6;
 	public final static int EVENT_PRVMSG = 7;
 	public final static int EVENT_MSG = 8;
 
 	public final static int EVENTS = 9;
 
 	public static Hashtable SOUNDS = new Hashtable();
 
 	// Images buttons.

 
 	public static Image LARGE_NORMAL;
 	public static Image LARGE_PRESSED;
 	public static Image LARGE_DISABLED;
 	public static Image LARGE_ALERT;
 	public static Image LARGE_WAIT;
 
 	public static Image SMALL_NORMAL;
 	public static Image SMALL_PRESSED;
 	public static Image SMALL_DISABLED;
 
 	public Resources(Object target, String pref_lang)
 	{
 		this.obj = target;
 
 		try
 		{
 			/* Mixing Signed and Unsigned Code
 			** http://docs.oracle.com/javase/6/docs/technotes/guides/jweb/mixed_code.html
 			**
 			** ClassLoader clsld = Thread.currentThread().getContextClassLoader();
 			*/
 			Thread th = Thread.currentThread();
 			java.lang.reflect.Method getloader = Thread.class.getMethod("getContextClassLoader", new Class[] {});
 			Object obj = getloader.invoke(th, new Object[] {});
 			clsld = (ClassLoader)obj;
 		}
 		catch (Exception ex)
 		{
 			cls = (target instanceof Class) ? (Class)target : target.getClass();
 		}
 
 		this.tracker = new MediaTracker((Component)target);
 
 
 		/*
 		** By default, this will load the English language files
 		** Then, this will try to load JVM's default locale ones.
 		** So, you should always include *_en.properties files.
 		*/
 
 		try
 		{
 			Locale en_locale = new Locale("en", "");
 			Properties en_lang_resource = null;
 			Properties en_img_resource = null;
 			String en_help_resource = null;
 			try
 			{
 				en_lang_resource = readProperties("eirc", en_locale, null);
 				en_img_resource = readProperties("images", en_locale, null);
 				en_help_resource = readText("help", en_locale, null);
 			}
 			catch (MissingResourceException ex) { System.err.println("Cannot load " + ex.getKey()); }
 
 			Locale locale = null;
 			if (pref_lang != null && pref_lang.length() >= 2)
 				locale = new Locale(pref_lang, "");
 			else
 				locale = Locale.getDefault();
 
 			lang_resource = readProperties("eirc", locale, en_lang_resource);
 			img_resource = readProperties("images", locale, en_img_resource);
 			help_resource = readText("help", locale, en_help_resource);
 		}
 		catch (MissingResourceException ex) { System.err.println("Cannot load " + ex.getKey()); }
 
 		cacheImages();
 	}
 
 	public static URL getResource(String resource_name)
 	{
 		URL u = (clsld != null ? clsld.getResource(resource_name) : cls.getResource(resource_name));
 		return (u);
 	}
 
 	public static InputStream getResourceAsStream(String resource_name)
 	{
 		InputStream is = (clsld != null ? clsld.getResourceAsStream(resource_name) : cls.getResourceAsStream(resource_name));
 		return (is);
 	}
 
 	private static void cacheImages()
 	{
 		LARGE_NORMAL = getImage("button.large.normal");
 		LARGE_PRESSED = getImage("button.large.pressed");
 		LARGE_DISABLED = getImage("button.large.disabled");
 		LARGE_ALERT = getImage("button.large.alert");
 		LARGE_WAIT = getImage("button.large.wait");
 
 		SMALL_NORMAL = getImage("button.small.normal");
 		SMALL_PRESSED = getImage("button.small.pressed");
 		SMALL_DISABLED = getImage("button.small.disabled");
 
 	}
 
 	public void cacheSounds(Vector files, String path)
 	{
 		this.files = files;
 		this.path = path;
 	   	loader = new Thread(this, "sound_loader");
 	   	loader.start();
 	}
 
 	public void run()
 	{
 		int i = 1;
 		Enumeration e = files.elements();
 		while (e.hasMoreElements() && loader == Thread.currentThread())
 		{
    			String key = (String)e.nextElement();
 			AudioClip au = createSound(path + "/" + key);
 			if (au != null)
 			{
 	   			SOUNDS.put(key, au);
 
 				setChanged();
 				notifyObservers(key);
 			}
 		}
 	}
 
 	public static Image getImage(String key)
 	{
 		String name = getLabel(key);
 		if (name != null && !name.equals(""))
 		{
 			try
 			{
 				Image img = createImage(name);
 				tracker.addImage(img, 0);
 				tracker.waitForID(0, 1000);
 				return(img);
 			} catch (InterruptedException e) {}
 		}
 		return(null);
 	}
 
 	public static String getLabel(String key)
 	{
 		String value = img_resource.getProperty(key);
 		if (value == null)
 			System.err.println("Missing key : " + key);
 
 		return(value);
 	}
 
 	public static String getString(String key)
 	{
 		String value = lang_resource.getProperty(key);
 		if (value == null)
 			System.err.println("Missing key : " + key);
 
 		return(value);
 	}
 
 	public static String getHelp()
 	{
 		return(help_resource);
 	}
 
 	private Properties readProperties(String name, Locale loc, Properties defaults) throws MissingResourceException
 	{
 		Properties pr = null;
 		if (defaults != null)
 			pr = new Properties(defaults);
 		else
 			pr = new Properties();
 		String resource_name = name + "_" + loc.getLanguage() + ".properties";
 
 		try
 		{
 			InputStream in = getResourceAsStream(resource_name);
 			if (in != null)
 			{
 				pr.load(in);
 				in.close();
 			}
 
 			if (pr == null)
 			{
 				throw new MissingResourceException("Cannot load properties file" , "Resource", resource_name);
 			}
 			else
 			{
 				for (Enumeration e = pr.propertyNames(); e.hasMoreElements(); )
 				{
 					String key = (String)e.nextElement();
 					String value = pr.getProperty(key);
 
 					if (value != null && value.length() > 0)
 						pr.put(key, MircMessage.attrDecode(value));
 				}
 			}
 		}
 		catch (IOException e)
 		{
 			throw new MissingResourceException("Cannot load properties file" , "Resource", resource_name);
 		}
 
 		return(pr);
 	}
 	
 	private String readText(String name, Locale loc, String defaults) throws MissingResourceException
 	{
 		String txt = null;
 		if (defaults != null)
 			txt = defaults;
 		String resource_name = name + "_" + loc.getLanguage() + ".txt";
 
 		try
 		{
 			InputStream in = getResourceAsStream(resource_name);
 			if (in != null)
 			{
 				txt = new String();
 				BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF8"));
 				String s;
 
 				while((s = br.readLine()) != null)
 				{
 					if (s.equals(""))
 						s = "\r";
 					
 						txt += s + "\n";
 				}
 				br.close();
 				
 				txt = MircMessage.attrDecode(txt);
 			}
 		}
 		catch (IOException e)
 		{
 			throw new MissingResourceException("Cannot load text file" , "Resource", resource_name);
 		}
 
 		return(txt);
 	}
 
 	/**
 	 * BUGS:
 	 *  * Netscape Navigator (tested with 4.7x) won't load files from outside a JAR.
 	 *  * Life would be easier if Netscape Navigator supported Class.getResource().
 	 *	* Their not supporting it is actually documented on Netscape's Developers website.
 	 */
 /*
 	public static byte [] getResource(String name, Object target) throws IOException
 	{
 		// Resolve object to a Class, if needed.
 	   	Class cl = (target instanceof Class) ? (Class)target : target.getClass();
 
 		InputStream is = cl.getResourceAsStream(name);
 		BufferedInputStream bis = new BufferedInputStream(is);
 		ByteArrayOutputStream baos = new ByteArrayOutputStream();
 
 		try
 		{
 			int pos = 0;
 			int readed;
 			final int chunk_size = 4096;
 		  	byte [] buf = new byte [chunk_size];
 
 			while ((readed = bis.read(buf, 0, chunk_size)) != -1)
 			{
 				baos.write(buf, pos, readed);
 				pos += readed;
 			}
 
 			return baos.toByteArray();
 		}
 		catch (Exception e)
 		{
 			throw new IOException("Cannot open image file " + name);
 		}
 	}
 */
 
 	private static Image createImage(String resource_name)
 	{
 /*
 		try
 		{
 			byte [] image = getResource(resource_name, target);
 			return (Toolkit.getDefaultToolkit().createImage(image));
 		}
 		catch (IOException e) { System.err.println(e); }
 		return(null);
 */
 		try
 		{
 			URL url = getResource(resource_name);
 			Image image = ((Applet)obj).getImage(url);
 			return(image);
 		}
 		catch (Exception e)	{}
 
 		System.err.println("Cannot open image file : " + resource_name);
 		return(null);
 	}
 
 	private static AudioClip createSound(String resource_name)
 	{
 //			URL url = new URL(((Applet)obj).getCodeBase() + resource_name);

 		URL url = getResource(resource_name);
 		AudioClip clip = ((Applet)obj).getAudioClip(url);
 		
 		if (clip != null)
 			return(clip);
 		else
 			System.err.println("Cannot open sound file : " + resource_name);
 
 		return(null);
 	}
 }