/*******************************************************************************
 * Copyright (c) 2005, 2006 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.ui.internal.cheatsheets.composite.explorer;

import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.internal.cheatsheets.CheatSheetPlugin;
import org.eclipse.ui.internal.cheatsheets.composite.model.TaskStateUtilities;
import org.eclipse.ui.internal.cheatsheets.composite.parser.ICompositeCheatsheetTags;
import org.eclipse.ui.internal.cheatsheets.composite.views.TaskEditorManager;
import org.eclipse.ui.internal.provisional.cheatsheets.ICompositeCheatSheetTask;
import org.eclipse.ui.internal.provisional.cheatsheets.ITaskGroup;
import org.osgi.framework.Bundle;

public class TreeLabelProvider extends LabelProvider {

	private static int BLOCKED = -1;
	private Image defaultImage = null; // Image for tasks with null kind
	
	/*
	 * A set of related images
	 */
	private class ImageSet {
		// Use a map rather than array so the nuber of icons is not hard coded
		Map images = new HashMap();
		
		public void put(int index, Image image) {
			images.put(Integer.toString(index), image);
		}
		
		public Image getImage(int index) {
			return (Image)images.get(Integer.toString(index));
		}
		
		void dispose() {
			for (Iterator iter = images.values().iterator(); iter.hasNext(); ) {
				Image nextImage = (Image)iter.next();
				nextImage.dispose();
			}		
		}
	}
	
	private Map imageMap = null; // each entry is an ImageSet
		
	public TreeLabelProvider() {
		imageMap = new HashMap();
	}

	public String getText(Object obj) {
		String result;
		if (obj instanceof ICompositeCheatSheetTask) {
			result =  ((ICompositeCheatSheetTask) obj).getName();
		} else {
		    result =  obj.toString();
		}
		if (result == null) {
			result = ""; //$NON-NLS-1$
		}
		return result;
	}

	public Image getImage(Object obj) {
		if (obj instanceof ICompositeCheatSheetTask) {
			ICompositeCheatSheetTask task = (ICompositeCheatSheetTask) obj;
			return lookupImage(task.getKind(), task.getState(), TaskStateUtilities.isBlocked(task));		
		}
		return super.getImage(obj);
	}

	public Image lookupImage(String kind, int state, boolean isBlocked) {
		ImageSet images = (ImageSet) imageMap.get(kind);
		if (images == null) {
			images = createImages(kind);
			imageMap.put(kind, images);
		}
		if (isBlocked) {
			return images.getImage(BLOCKED);
		}
	    return images.getImage(state);
	}

	/**
	 * Create a set of images for a task which may be [redefined.
	 * @param kind
	 * @return
	 */
	private ImageSet createImages(String kind) {
		ImageSet images = new ImageSet();
		ImageDescriptor desc;
		desc = getPredefinedImageDescriptor(kind, true);
        if (desc == null) {
		    desc = TaskEditorManager.getInstance().getImageDescriptor(kind);
        }
		if (desc != null) {		
			Image baseImage = desc.createImage();
			images.put(ICompositeCheatSheetTask.NOT_STARTED, baseImage);
			
			createImageWithOverlay(ICompositeCheatSheetTask.IN_PROGRESS, 
		               "$nl$/icons/ovr16/task_in_progress.gif",  //$NON-NLS-1$
		               images, 
		               desc);
			createImageWithOverlay(ICompositeCheatSheetTask.SKIPPED, 
		               "$nl$/icons/ovr16/task_skipped.gif",  //$NON-NLS-1$
		               images, 
		               desc);
			createDisabledImage(kind, BLOCKED, 
		               images, 
		               baseImage);
			createImageWithOverlay(ICompositeCheatSheetTask.COMPLETED, 
		               "$nl$/icons/ovr16/task_complete.gif",  //$NON-NLS-1$
		               images, 
		               desc);
			
		}
		return images;
	}

	private ImageDescriptor getPredefinedImageDescriptor(String kind, boolean isEnabled) {
		String filename;
		if (ICompositeCheatsheetTags.CHEATSHEET_TASK_KIND.equals(kind)) {
			filename = "cheatsheet_task.gif"; //$NON-NLS-1$
		} else if (ITaskGroup.SET.equals(kind)) {
			filename = "task_set.gif"; //$NON-NLS-1$
		} else if (ITaskGroup.CHOICE.equals(kind)) {
			filename = "task_choice.gif"; //$NON-NLS-1$
		} else if (ITaskGroup.SEQUENCE.equals(kind)) {
			filename = "task_sequence.gif"; //$NON-NLS-1$
		} else {
			return null;
		}
		String iconPath =  "$nl$/icons/"; //$NON-NLS-1$
		if (isEnabled) { 
			iconPath += CheatSheetPlugin.T_OBJ;
		} else {
			iconPath += CheatSheetPlugin.T_DLCL;
		}
		iconPath += filename;
		return createImageDescriptor(iconPath);
	}

	private void createImageWithOverlay(int state, String imagePath, ImageSet images, ImageDescriptor baseDescriptor) {
		ImageDescriptor descriptor = createImageDescriptor(imagePath); 
		OverlayIcon icon = new OverlayIcon(baseDescriptor, new ImageDescriptor[][] {
				{}, { descriptor } });
		images.put(state, icon.createImage());
	}
	
	private void createDisabledImage(String kind, int state, ImageSet images, Image baseImage) {
		// The four images for task_set, task_sequence, task_choice and cheatsheet_task can be found
		// in icons/dlcl16. 
		// TODO extend the extension point to allow disabled images to be specified.
		//if 

		ImageDescriptor desc = getPredefinedImageDescriptor(kind, false);
		Image disabledImage;
		if (desc != null) {
			disabledImage = desc.createImage();
		} else {
		    disabledImage = createGrayedImage(baseImage);
		}
		images.put(state, disabledImage);		
	}

	private Image createGrayedImage(Image image) {
		return new Image(image.getDevice(), image, SWT.IMAGE_DISABLE);
	}

	private ImageDescriptor createImageDescriptor(String relativePath) {
		Bundle bundle = CheatSheetPlugin.getPlugin().getBundle();
		URL url = FileLocator.find(bundle, new Path(relativePath),null);
		if (url == null) return null;
		try {
			url = FileLocator.resolve(url);
			return ImageDescriptor.createFromURL(url);
		} catch (IOException e) {
			return null;
		}
	}

	public void dispose() {
		if (imageMap != null) {
			for (Iterator iter = imageMap.values().iterator(); iter.hasNext(); ) {
			    ImageSet nextImages = (ImageSet)iter.next();
			    nextImages.dispose();
			}
			imageMap = null;
		}
		if (defaultImage != null) {
			defaultImage.dispose();
			defaultImage = null;
		}
	}
	
}
