/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
package lu.tudor.santec.gecamed.core.gui;

import java.awt.Image;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.Permission;
import java.util.HashMap;

import javax.swing.ImageIcon;

import org.apache.log4j.Logger;

/**
 * Class with static helper methods to fetch icons.
 * <b>Use this class whenever you want to load icons in GECAMed!</b>
 * 
 *
 * @author Johannes Hermen johannes.hermen(at)tudor.lu
 *
 * @version
 * <br>$Log: IconFetcher.java,v $
 * <br>Revision 1.11  2013-12-27 18:09:26  donak
 * <br>Cleanup of imports
 * <br>
 * <br>Revision 1.10  2013-07-15 06:18:35  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.9  2013-01-02 13:18:22  ferring
 * <br>getNormalIcon method added - for 32 pixel icons
 * <br>
 * <br>Revision 1.8  2012-07-18 07:49:22  ferring
 * <br>SSN constants and formating removed from class SSNField and added to class Patient to give the server access to it
 * <br>
 * <br>Revision 1.7  2012-03-05 10:11:12  troth
 * <br>add new scaled icon function with param width and height.
 * <br>
 * <br>Revision 1.6  2011-02-28 15:41:45  troth
 * <br>To provide smaller resolutions for the user interface add the navigation bar icons and function bar icons to the user setting "use small icons"
 * <br>
 * <br>Revision 1.5  2010-03-19 12:01:06  hermen
 * <br>improved and unified iconfetching
 * <br>
 * <br>Revision 1.4  2009-01-22 07:35:51  hermen
 * <br>improved startup logging and progress dialog
 * <br>
 * <br>Revision 1.3  2008-12-16 10:35:43  hermen
 * <br>added fixJarUrl for Webstart icon url bug
 * <br>
 * <br>Revision 1.2  2008-09-25 09:43:07  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.1  2008-01-28 08:28:05  hermen
 * <br>moved functionality to IconFetcher Class and GECAMedIconNames Interface
 * <br>
 *
 */
public class IconFetcher implements GECAMedIconNames {

	/**
	 * static logger for this class
	 */
	private static Logger logger = Logger
			.getLogger(IconFetcher.class.getName());
	
	private static final String EMPTY_ICON = "empty_32.png";
	
	
	private static HashMap<String, ImageIcon> icons = new HashMap<String, ImageIcon>();
	// ---------------------------------------------------------------------------

	
	/**
	 * fetches an Icon from the "resources/icons/" folder placed related 
	 * to the given reference class.
	 * @param referenceClass Class from where to find the icon folder. 
	 * @param iconName name of the wanted icon
	 * @return the loaded ImageIcon
	 */
	public static ImageIcon getIcon(Class referenceClass, String iconName) {
		String iconPath = "resources/icons/" + iconName;
		URL location = referenceClass.getResource(iconPath);
		
		// try to take from hashmap
		ImageIcon icon = icons.get(referenceClass+iconName);
		if (icon != null)
		    return icon;
		

		if (location != null)
			icon = new ImageIcon(location);

		if ((icon == null) || (icon.getIconHeight() <= 0)) {
			logger.warn("Couldn't find Icon: " + iconPath + " taking empty default icon...");
			icon = new ImageIcon(IconFetcher.class.getResource("resources/icons/" + EMPTY_ICON));
		}
		
		
		
		icons.put(referenceClass+iconName, icon);
		
		return icon;
	}

	/**
	 * fetches an Icon from the "resources/icons/" folder placed related 
	 * to the given reference class.
	 * @param referenceClass Class from where to find the icon folder. 
	 * @param iconName name of the wanted icon
	 * @param size pixel size of the icon
	 * @return the loaded ImageIcon
	 */
	@SuppressWarnings("unchecked")
	public static ImageIcon getScaledIcon(Class referenceClass, 	String iconName, int size) {
		// try to take from hashmap
		ImageIcon icon = icons.get(referenceClass+iconName+size);
		if (icon != null)
		    return icon;
	    
		icon = new ImageIcon(getIcon(referenceClass, iconName).getImage()
			.getScaledInstance(size, size, Image.SCALE_SMOOTH));
		
		icons.put(referenceClass+iconName+size, icon);
		
		return icon;
	}

	/**
	 * fetches an Icon from the "resources/icons/" folder placed related 
	 * to the given reference class.
	 * @param referenceClass Class from where to find the icon folder. 
	 * @param iconName name of the wanted icon
	 * @param width pixel width of the icon
	 * @param height pixel height of the icon
	 * @return the loaded ImageIcon
	 */
	@SuppressWarnings("unchecked")
	public static ImageIcon getScaledIcon(Class referenceClass, String iconName, int width, int height) {
		// try to take from hashmap
		ImageIcon icon = icons.get(referenceClass+iconName+width+height);
		if (icon != null)
		    return icon;
	    
		icon = new ImageIcon(getIcon(referenceClass, iconName).getImage()
			.getScaledInstance(width, height, Image.SCALE_SMOOTH));
		
		icons.put(referenceClass+iconName+width+height, icon);
		
		return icon;
	}
	
	/**
	 * fetches an Icon in mini size from the "resources/icons/" folder placed related 
	 * to the given reference class.
	 * @param referenceClass Class from where to find the icon folder. 
	 * @param iconName name of the wanted icon
	 * @return the loaded ImageIcon
	 */
	@SuppressWarnings("unchecked")
	public static ImageIcon getMiniIcon(Class referenceClass, String iconName) {
		return getScaledIcon(referenceClass, iconName, MINIPIX);
	}


	/**
	 * fetches an Icon in small size from the "resources/icons/" folder placed related 
	 * to the given reference class.
	 * @param referenceClass Class from where to find the icon folder. 
	 * @param iconName name of the wanted icon
	 * @return the loaded ImageIcon
	 */
	@SuppressWarnings("unchecked")
	public static ImageIcon getSmallIcon(Class referenceClass, String iconName) {
		return getScaledIcon(referenceClass, iconName, SMALLPIX);
	}

	/**
	 * fetches an Icon in medium size from the "resources/icons/" folder placed related 
	 * to the given reference class.
	 * @param referenceClass Class from where to find the icon folder. 
	 * @param iconName name of the wanted icon
	 * @return the loaded ImageIcon
	 */
	@SuppressWarnings("unchecked")
	public static ImageIcon getMediumIcon(Class referenceClass, String iconName) {
		return getScaledIcon(referenceClass, iconName, MEDIPIX);
	}
	
	
	/**
	 * fetches an Icon in medium size from the "resources/icons/" folder placed related 
	 * to the given reference class.
	 * @param referenceClass Class from where to find the icon folder. 
	 * @param iconName name of the wanted icon
	 * @return the loaded ImageIcon
	 */
	@SuppressWarnings("unchecked")
	public static ImageIcon getNormalIcon(Class referenceClass, String iconName) {
		return getScaledIcon(referenceClass, iconName, NORMALPIX);
	}


	/**
	 * fetches an Icon in big size from the "resources/icons/" folder placed related 
	 * to the given reference class.
	 * @param referenceClass Class from where to find the icon folder. 
	 * @param iconName name of the wanted icon
	 * @return the loaded ImageIcon
	 */
	@SuppressWarnings("unchecked")
	public static ImageIcon getBigIcon(Class referenceClass, String iconName) {
		return getScaledIcon(referenceClass, iconName, LARGEPIX);
	}

	
	/**
	 * 
	 * ORIGINAL COMMENT OF THE AUTHOR:
	 * 
	 * I believe I have successfully created a work-around for Bug ID: 6746185. 
	 * Unlike the fixes which have been posted in that bug's comments, I believe 
	 * my fix will work for resources located in classless JARs (JARs which have no 
	 * class files in them.) I would like to solicit comments on my approach 
	 * (especially flaws, limitations, risks.) As well, I would like to share my 
	 * workaround with the Java / Web Start community.
	 * Reference: http://bugs.sun.com/view_bug.do?bug_id=6746185
	 * (Please excuse the excessive logging and verbosity of the code, I wanted to be thorough.)
	 * 
	 * END COMMENT
	 * @param url
	 * @return
	 */
    public static URL fixJarURL(URL url)
    {
        // final String method = _module + ".fixJarURL";
        String originalURLProtocol = url.getProtocol();
        // if (log.isDebugEnabled()) { log.debug(method + " examining '" + originalURLProtocol + "' protocol url: " + url); }
        if ("jar".equalsIgnoreCase(originalURLProtocol) == false)
        {
            // if (log.isDebugEnabled()) { log.debug(method + " skipping fix: URL is not 'jar' protocol: " + url); }
            return url;
        }
 
        // if (log.isDebugEnabled()) { log.debug(method + " URL is jar protocol, continuing"); }
        String originalURLString = url.toString();
        // if (log.isDebugEnabled()) { log.debug(method + " using originalURLString: " + originalURLString); }
        int bangSlashIndex = originalURLString.indexOf("!/");
        if (bangSlashIndex > -1)
        {
            // if (log.isDebugEnabled()) { log.debug(method + " skipping fix: originalURLString already has bang-slash: " + originalURLString); }
            return url;
        }
 
        // if (log.isDebugEnabled()) { log.debug(method + " originalURLString needs fixing (it has no bang-slash)"); }
        String originalURLPath = url.getPath();
        // if (log.isDebugEnabled()) { log.debug(method + " using originalURLPath: " + originalURLPath); }
 
        URLConnection urlConnection;
        try
        {
            urlConnection = url.openConnection();
            if (urlConnection == null)
            {
                throw new IOException("urlConnection is null");
            }
        }
        catch (IOException e)
        {
            // if (log.isDebugEnabled()) { log.debug(method + " skipping fix: openConnection() exception", e); }
            return url;
        }
        // if (log.isDebugEnabled()) { log.debug(method + " using urlConnection: " + urlConnection); }
 
        Permission urlConnectionPermission;
        try
        {
            urlConnectionPermission = urlConnection.getPermission();
            if (urlConnectionPermission == null)
            {
                throw new IOException("urlConnectionPermission is null");
            }
        }
        catch (IOException e)
        {
            // if (log.isDebugEnabled()) { log.debug(method + " skipping fix: getPermission() exception", e); }
            return url;
        }
        // if (log.isDebugEnabled()) { log.debug(method + " using urlConnectionPermission: " + urlConnectionPermission); }
 
        String urlConnectionPermissionName = urlConnectionPermission.getName();
        if (urlConnectionPermissionName == null)
        {
            // if (log.isDebugEnabled()) { log.debug(method + " skipping fix: urlConnectionPermissionName is null"); }
            return url;
        }
 
        // if (log.isDebugEnabled()) { log.debug(method + " using urlConnectionPermissionName: " + urlConnectionPermissionName); }
 
        File file = new File(urlConnectionPermissionName);
        if (file.exists() == false)
        {
            // if (log.isDebugEnabled()) { log.debug(method + " skipping fix: file does not exist: " + file); }
            return url;
        }
        // if (log.isDebugEnabled()) { log.debug(method + " using file: " + file); }
 
        String newURLStr;
        try
        {
            newURLStr = "jar:" + file.toURL().toExternalForm() + "!/" + originalURLPath;
        }
        catch (MalformedURLException e)
        {
            // if (log.isDebugEnabled()) { log.debug(method + " skipping fix: exception creating newURLStr", e); }
            return url;
        }
        // if (log.isDebugEnabled()) { log.debug(method + " using newURLStr: " + newURLStr); }
 
        try
        {
            url = new URL(newURLStr);
        }
        catch (MalformedURLException e)
        {
            // if (log.isDebugEnabled()) { log.debug(method + " skipping fix: exception creating new URL", e); }
            return url;
        }
 
        return url;
    }
    
	@SuppressWarnings("unchecked")
	public static ImageIcon scaleIcon(ImageIcon icon, int size) {

		icon = new ImageIcon(icon.getImage()
			.getScaledInstance(size, size, Image.SCALE_SMOOTH));
		
		return icon;
	}
	
}
