//------------------------------------------------------------------------------
// 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 implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.library.edit.category;

import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.MissingResourceException;

import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.UnexecutableCommand;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.EMFEditPlugin;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.CopyCommand.Helper;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.provider.ViewerNotification;
import org.eclipse.epf.library.edit.IDefaultNameSetter;
import org.eclipse.epf.library.edit.ILibraryItemProvider;
import org.eclipse.epf.library.edit.LibraryEditPlugin;
import org.eclipse.epf.library.edit.command.MethodElementAddCommand;
import org.eclipse.epf.library.edit.util.LibraryEditConstants;
import org.eclipse.epf.library.edit.util.ModelStructure;
import org.eclipse.epf.library.edit.util.TngUtil;
import org.eclipse.epf.uma.ContentPackage;
import org.eclipse.epf.uma.CustomCategory;
import org.eclipse.epf.uma.DescribableElement;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.UmaFactory;
import org.eclipse.epf.uma.UmaPackage;
import org.eclipse.epf.uma.VariabilityElement;
import org.eclipse.epf.uma.edit.command.MethodElementCreateCopyCommand;
import org.eclipse.epf.uma.edit.command.MethodElementInitializeCopyCommand;
import org.eclipse.epf.uma.util.AssociationHelper;

/**
 * The item provider adapter for a custom category.
 * 
 * @author Phong Nguyen Le
 * @author Kelvin Low
 * @since 1.0
 */
public class CustomCategoryItemProvider extends
		org.eclipse.epf.uma.provider.CustomCategoryItemProvider implements
		IDefaultNameSetter, ILibraryItemProvider {

	/**
	 * Creates a new instance.
	 */
	public CustomCategoryItemProvider(AdapterFactory adapterFactory) {
		super(adapterFactory);
	}

	public void setParent(Object parent) {
		// this.parent = parent;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.emf.edit.provider.ItemProviderAdapter#getParent(java.lang.Object)
	 */
	public Object getParent(Object object) {

		// CustomCategory category = (CustomCategory) object;
		// if(category.eContainer() instanceof CustomCategory) {
		// return super.getParent(object);
		// }
		//		
		// if(parent != null) {
		// return parent;
		// }
		//		
		// if(object instanceof EObject) {
		// MethodPlugin plugin = UmaUtil.getMethodPlugin((EObject) object);
		// //if(plugin == null) return null;
		//			
		// if(plugin != null) {
		// String[] path = {
		// LibraryEditPlugin.INSTANCE.getString("_UI_Content_group")
		// ,LibraryEditPlugin.INSTANCE.getString("_UI_Custom_Categories_group")
		// };
		// return TngUtil.getAdapter(plugin, path);
		// }
		//			
		// }

		if (TngUtil.isRootCustomCategory((CustomCategory) object)) {
			return null;
		}
		return super.getParent(object);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.emf.edit.provider.ItemProviderAdapter#collectNewChildDescriptors(java.util.Collection,
	 *      java.lang.Object)
	 */
	protected void collectNewChildDescriptors(Collection newChildDescriptors,
			Object object) {
		newChildDescriptors.add(createChildParameter(UmaPackage.eINSTANCE
				.getCustomCategory_CategorizedElements(), UmaFactory.eINSTANCE
				.createCustomCategory()));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.emf.edit.provider.ItemProviderAdapter#getChildrenFeatures(java.lang.Object)
	 */
	public Collection getChildrenFeatures(Object object) {
		if (childrenFeatures == null) {
			childrenFeatures = new ArrayList();
			// childrenFeatures.add(UmaPackage.eINSTANCE.getCustomCategory_SubCategories());
			childrenFeatures.add(UmaPackage.eINSTANCE
					.getCustomCategory_CategorizedElements());
			// childrenFeatures.add(UmaPackage.eINSTANCE.getCustomCategory_ProcessElements());
		}
		return childrenFeatures;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.emf.edit.command.CreateChildCommand.Helper#getCreateChildImage(java.lang.Object,
	 *      java.lang.Object, java.lang.Object, java.util.Collection)
	 */
	public Object getCreateChildImage(Object owner, Object feature,
			Object child, Collection selection) {
		if (feature instanceof EReference && child instanceof EObject) {
			EReference reference = (EReference) feature;
			EClass parentClass = reference.getEContainingClass();
			EClass childClass = ((EObject) child).eClass();
			String name = "full/ctool16/Create" + parentClass.getName() + "_" + reference.getName() + "_" + childClass.getName(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
			try {
				return LibraryEditPlugin.INSTANCE.getImage(name);
			} catch (MissingResourceException e) {
				System.err.println(e.getMessage());
				return null;
			}
		}

		return EMFEditPlugin.INSTANCE.getImage("full/ctool16/CreateChild"); //$NON-NLS-1$
	}

	private static void handleRemoved(CustomCategory category) {
		if (AssociationHelper.getCustomCategories(category).isEmpty()) {
			// remove all subcategories
			//
			for (Iterator iter = category.getCategorizedElements().iterator(); iter
					.hasNext();) {
				Object element = iter.next();
				if (element instanceof CustomCategory) {
					iter.remove();
				}
			}

			EcoreUtil.remove(category);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.emf.common.notify.Adapter#notifyChanged(org.eclipse.emf.common.notify.Notification)
	 */
	public void notifyChanged(Notification notification) {
		setDefaultName(notification);

		updateChildren(notification);

		ContentPackage pkg;
		// boolean refreshCustomCategoryRoot = false;
		switch (notification.getFeatureID(CustomCategory.class)) {
		case UmaPackage.METHOD_ELEMENT__NAME:
			TngUtil.refreshContributors(this, notification, false, true);
			break;
		// case UmaPackage.CUSTOM_CATEGORY__SUB_CATEGORIES:
		case UmaPackage.CUSTOM_CATEGORY__CATEGORIZED_ELEMENTS:
			pkg = (ContentPackage) ((EObject) notification.getNotifier())
					.eContainer();
			if ((pkg != null)
					&& (ModelStructure.HIDDEN_PACKAGE_NAME
							.equals(pkg.getName()))) {
				// notifier is the root custom category
				//
				pkg = (ContentPackage) pkg.eContainer();
			}
			Object obj;
			CustomCategory category;
			switch (notification.getEventType()) {
			case Notification.ADD:
				obj = notification.getNewValue();
				if (obj instanceof CustomCategory) {
					category = (CustomCategory) obj;
					if (category.eContainer() == null) {
						pkg.getContentElements().add(category);
					} else {
						// refreshCustomCategoryRoot = true;
					}
				}
				break;
			case Notification.ADD_MANY:
				for (Iterator iter = ((Collection) notification.getNewValue())
						.iterator(); iter.hasNext();) {
					obj = iter.next();
					if (obj instanceof CustomCategory) {
						category = (CustomCategory) obj;
						if (category.eContainer() == null) {
							pkg.getContentElements().add(category);
						} else {
							// refreshCustomCategoryRoot = true;
						}
					}
				}
				break;
			case Notification.REMOVE:
				obj = notification.getOldValue();
				if (obj instanceof CustomCategory) {
					handleRemoved((CustomCategory) obj);
				}
				break;
			case Notification.REMOVE_MANY:
				for (Iterator iter = ((Collection) notification.getOldValue())
						.iterator(); iter.hasNext();) {
					obj = iter.next();
					if (obj instanceof CustomCategory) {
						handleRemoved((CustomCategory) obj);
					}
				}
				break;
			}
			fireNotifyChanged(new ViewerNotification(notification, notification
					.getNotifier(), true, false));

			// // refresh wrappers
			// //
			// if(wrappers != null) {
			// for (Iterator iter = new ArrayList(wrappers).iterator();
			// iter.hasNext();) {
			// fireNotifyChanged(new ViewerNotification(notification,
			// iter.next(), true, false));
			// }
			// }
			//			
			// if(refreshCustomCategoryRoot) {
			// // sub category has been added or removed from the custom
			// category
			// // need to refresh the folder for all custom categories
			// //
			// MethodPlugin plugin = UmaUtil.getMethodPlugin((EObject) target);
			//				
			// if(plugin != null) {
			// String[] path = {
			// LibraryEditPlugin.INSTANCE.getString("_UI_Content_group")
			// ,LibraryEditPlugin.INSTANCE.getString("_UI_Custom_Categories_group")
			// };
			// fireNotifyChanged(new ViewerNotification(notification,
			// TngUtil.getAdapter(plugin, path), true, false));
			// }
			// }

			return;
		}
		super.notifyChanged(notification);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.emf.edit.provider.ItemProviderAdapter#isWrappingNeeded(java.lang.Object)
	 */
	protected boolean isWrappingNeeded(Object object) {
		return true;
	}

	protected Object createWrapper(EObject object, EStructuralFeature feature,
			Object value, int index) {
		if (!isWrappingNeeded(object))
			return value;
		return TngUtil.createWrapper(adapterFactory, object, feature, value,
				index);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.emf.edit.provider.ItemProviderAdapter#getText(java.lang.Object)
	 */
	public String getText(Object object) {
		return TngUtil.getLabel((VariabilityElement) object,
				getString("_UI_CustomCategory_type"), true); //$NON-NLS-1$
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.emf.edit.provider.ItemProviderAdapter#hasChildren(java.lang.Object)
	 */
	public boolean hasChildren(Object object) {
		CustomCategory category = (CustomCategory) object;
		return !category.getCategorizedElements().isEmpty()
		// || !category.getSubCategories().isEmpty()
		;
	}

	public void setDefaultName(Notification msg) {
		IDefaultNameSetter defaultNameSetter = this;
		if (defaultNameSetter.getInterestedFeatureOwnerClass() != null) {
			int featureId = msg.getFeatureID(defaultNameSetter
					.getInterestedFeatureOwnerClass());
			if (featureId == defaultNameSetter.getInterestedFeatureID()) {
				switch (msg.getEventType()) {
				case Notification.ADD:
					setDefaultName(msg.getNewValue(), msg.getNotifier());
					break;
				case Notification.ADD_MANY:
					for (Iterator iter = ((Collection) msg.getNewValue())
							.iterator(); iter.hasNext();) {
						setDefaultName(iter.next(), msg.getNotifier());
					}
					break;
				}
			}
		}
	}

	private void setDefaultName(Object obj, Object parent) {
		String baseName = null;
		if (obj instanceof CustomCategory) {
			baseName = LibraryEditConstants.NEW_CUSTOM_CATEGORY;
		}
		if (baseName != null) {
			TngUtil.setDefaultName(((CustomCategory) parent)
					.getCategorizedElements(), (MethodElement) obj, baseName);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ibm.library.edit.IDefaultNameSetter#getInterestedFeatureID()
	 */
	public int getInterestedFeatureID() {
		return UmaPackage.CUSTOM_CATEGORY__CATEGORIZED_ELEMENTS;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ibm.library.edit.IDefaultNameSetter#getInterestedFeatureOwnerClass()
	 */
	public Class getInterestedFeatureOwnerClass() {
		return CustomCategory.class;
	}

	protected Command createInitializeCopyCommand(EditingDomain domain,
			EObject owner, Helper helper) {
		return new MethodElementInitializeCopyCommand(domain, owner, helper);
	}

	protected Command createCreateCopyCommand(EditingDomain domain,
			EObject owner, Helper helper) {
		return new MethodElementCreateCopyCommand(domain, owner, helper);
	}

	protected Command createAddCommand(EditingDomain domain, EObject owner,
			EStructuralFeature feature, Collection collection, int index) {
		Collection selection = new ArrayList();
		for (Iterator iter = collection.iterator(); iter.hasNext();) {
			Object element = iter.next();
			if (element instanceof CustomCategory) {
				// check custom category for circular dependency
				//
				if (!(owner instanceof DescribableElement && TngUtil
						.isAncessorOf((CustomCategory) element,
								(DescribableElement) owner))) {
					selection.add(element);
				}
			}
		}
		if (selection.isEmpty()) {
			return UnexecutableCommand.INSTANCE;
		}

		return new MethodElementAddCommand((AddCommand) super.createAddCommand(
				domain, owner, feature, collection, index));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.emf.edit.provider.ItemProviderAdapter#createRemoveCommand(org.eclipse.emf.edit.domain.EditingDomain,
	 *      org.eclipse.emf.ecore.EObject,
	 *      org.eclipse.emf.ecore.EStructuralFeature, java.util.Collection)
	 */
	protected Command createRemoveCommand(EditingDomain domain, EObject owner,
			EStructuralFeature feature, Collection collection) {
		return super.createRemoveCommand(domain, owner, feature, collection);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ibm.library.edit.IConfigurable#setLabel(java.lang.String)
	 */
	public void setLabel(String label) {
	}

	public Object getImage(Object object) {
		if (TngUtil.isRootCustomCategory((CustomCategory) object))
			return LibraryEditPlugin.INSTANCE
					.getImage("full/obj16/CustomCategories"); //$NON-NLS-1$
		else {
			if (object instanceof DescribableElement) {
				if (((DescribableElement) object).getNodeicon() != null) {
					URI imgUri = TngUtil.getFullPathURI(
							(DescribableElement) object,
							((DescribableElement) object).getNodeicon());
					Object image = LibraryEditPlugin.INSTANCE
							.getSharedImage(imgUri);
					if (image != null)
						return image;
				}
			}
			return super.getImage(object);
		}
	}

	public void setDefaultName(Object obj) {
		// do nothing, already handled by setDefaultName(Notification)
	}

}
