//------------------------------------------------------------------------------
// 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.publishing.services;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
import org.eclipse.epf.common.utils.FileUtil;
import org.eclipse.epf.common.utils.StrUtil;
import org.eclipse.epf.common.utils.Timer;
import org.eclipse.epf.library.configuration.ConfigurationFilter;
import org.eclipse.epf.library.configuration.ConfigurationHelper;
import org.eclipse.epf.library.edit.IFilter;
import org.eclipse.epf.library.edit.TngAdapterFactory;
import org.eclipse.epf.library.edit.process.IBSItemProvider;
import org.eclipse.epf.library.edit.util.ProcessUtil;
import org.eclipse.epf.library.edit.util.Suppression;
import org.eclipse.epf.library.layout.HtmlBuilder;
import org.eclipse.epf.library.layout.IElementLayout;
import org.eclipse.epf.library.layout.elements.ActivityLayout;
import org.eclipse.epf.library.layout.elements.ProcessElementItem;
import org.eclipse.epf.library.layout.elements.ProcessLayoutData;
import org.eclipse.epf.library.layout.elements.SummaryPageLayout;
import org.eclipse.epf.library.layout.util.XmlElement;
import org.eclipse.epf.library.util.LibraryUtil;
import org.eclipse.epf.publishing.PublishingResources;
import org.eclipse.epf.publishing.layout.Bookmark;
import org.eclipse.epf.publishing.util.PublishingUtil;
import org.eclipse.epf.uma.Activity;
import org.eclipse.epf.uma.Artifact;
import org.eclipse.epf.uma.ContentCategory;
import org.eclipse.epf.uma.DeliveryProcess;
import org.eclipse.epf.uma.Discipline;
import org.eclipse.epf.uma.Guidance;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.MethodLibrary;
import org.eclipse.epf.uma.MethodPackage;
import org.eclipse.epf.uma.MethodPlugin;
import org.eclipse.epf.uma.ProcessElement;
import org.eclipse.epf.uma.Role;
import org.eclipse.epf.uma.Task;
import org.eclipse.epf.uma.Tool;
import org.eclipse.epf.uma.UmaPackage;
import org.eclipse.epf.uma.WorkProduct;
import org.eclipse.epf.uma.util.AssociationHelper;


/**
 * @author Shilpa Toraskar
 * @author Jinhua Xi
 * @since 1.0
 */
public class ConfigurationViewBuilder extends AbstractViewBuilder {

	private static final String PREFIX_Reference_Workflows = "Reference_Workflows"; //$NON-NLS-1$

	private static final String PREFIX_Tasks = "Tasks"; //$NON-NLS-1$

	private static final String PREFIX_ResponsibleFor_Tasks = "Primarily_Performs"; //$NON-NLS-1$

	private static final String PREFIX_ParticipatesIn_Tasks = "Additionally_Performs"; //$NON-NLS-1$

	private static final String PREFIX_Performing_Roles = "Performing_Roles"; //$NON-NLS-1$

	private static final String PREFIX_Input_Work_Products = "Input_Work_Products"; //$NON-NLS-1$

	private static final String PREFIX_Output_Work_Products = "Output_Work_Products"; //$NON-NLS-1$

	private static final String PREFIX_Work_Products_Created = "Responsible_For"; //$NON-NLS-1$

	private static final String PREFIX_Work_Products_Modified = "Modifies"; //$NON-NLS-1$

	private static final String PREFIX_Responsible_Role = "Responsible_Role"; //$NON-NLS-1$

	private static final String PREFIX_Containing_Work_Product = "Containing_Work_Product"; //$NON-NLS-1$

	private static final String PREFIX_Contained_Work_Products = "Contained_Work_Products"; //$NON-NLS-1$

	private static final String PREFIX_Guidances = "Guidance"; //$NON-NLS-1$

	private static final String PREFIX_InputTo_Task = "Input_to"; //$NON-NLS-1$

	private static final String PREFIX_OutputOf_Task = "Output_from"; //$NON-NLS-1$

	private static final String ICON_FOLDER = DefaultNodeIconResources
			.getIconName("folder"); //$NON-NLS-1$

	private static final String NODE_Reference_Workflows = PublishingResources.referenceWorkflowsNode_text; //$NON-NLS-1$

	private static final String NODE_Tasks = PublishingResources.taskNode_text; //$NON-NLS-1$

	private static final String NODE_ResponsibleFor_Tasks = PublishingResources.primarilyPerformsNode_text; //$NON-NLS-1$

	private static final String NODE_ParticipatesIn_Tasks = PublishingResources.additionallyPerformsNode_text; //$NON-NLS-1$

	private static final String NODE_Performing_Roles = PublishingResources.performingRolesNode_text; //$NON-NLS-1$

	private static final String NODE_Input_Work_Products = PublishingResources.inputWorkProductsNode_text; //$NON-NLS-1$

	private static final String NODE_Output_Work_Products = PublishingResources.outputWorkProductsNode_text; //$NON-NLS-1$

	private static final String NODE_Work_Products_Created = PublishingResources.responsibleForNode_text; //$NON-NLS-1$

	private static final String NODE_Work_Products_Modified = PublishingResources.modifiesNode_text; //$NON-NLS-1$

	private static final String NODE_Responsible_Role = PublishingResources.responsibleRoleNode_text; //$NON-NLS-1$

	private static final String NODE_Containing_Work_Product = PublishingResources.containingWorkProductNode_text; //$NON-NLS-1$

	private static final String NODE_Contained_Work_Products = PublishingResources.containedWorkProductsNode_text; //$NON-NLS-1$

	private static final String NODE_Guidances = PublishingResources.guidanceNode_text; //$NON-NLS-1$

	private static final String NODE_InputTo_Task = PublishingResources.inputToNode_text; //$NON-NLS-1$

	private static final String NODE_OutputOf_Task = PublishingResources.outputFromNode_text; //$NON-NLS-1$

	// MethodConfiguration config;
	List bookmarks = new ArrayList();

	AdapterFactory adapterFactory;

	private static final Class ITreeItemContentProviderClass = ITreeItemContentProvider.class;

	protected IProgressMonitor monitor = null;

	protected EObjectComparator nameComparator = new EObjectComparator();
	
	public ConfigurationViewBuilder(HtmlBuilder builder, PublishOptions options) {
		super(builder, options);
	}

//	public static ConfigurationViewBuilder getViewBuilder(String pubDir,
//			MethodConfiguration config, PublishOptions options) {
//		boolean validateExternalLinks = (options != null)
//				&& options.checkExtLinks;
//
//		PublishingContentValidator validator = null;
//		ElementRealizer realizer = null;
//		if ((options != null) && options.publishProcess) {
//			validator = new ProcessPublishingContentValidator(pubDir,
//					validateExternalLinks);
//			realizer = new ProcessPublishingElementRealizer(config, 
//					(ProcessPublishingContentValidator)validator);
//		} else {
//			validator = new PublishingContentValidator(pubDir,
//					validateExternalLinks);
//			realizer = new PublishingElementRealizer(config, validator);
//		}
//
//		ElementLayoutManager layoutMgr = new ElementLayoutManager(config,
//				pubDir, validator, true);
//		layoutMgr.setElementRealizer(realizer);
//		HtmlBuilder builder = new HtmlBuilder(layoutMgr);
//
//		return new ConfigurationViewBuilder(builder, options);
//	}

	public List buildViews(IProgressMonitor monitor)
	{
		this.monitor = monitor;

		// System.out.println("Building views..."); //$NON-NLS-1$

		if (config != null)
		{
			// first of all, we need to load the libray,
			// otherwise, some relationships and opposite features are not
			// established
			monitor.subTask(PublishingResources.loadLibraryTask_name); 
			LibraryUtil.loadAll((MethodLibrary)config.eContainer());
			
			
		    IFilter configFilter = new ConfigurationFilter(config, null);
			adapterFactory = TngAdapterFactory.INSTANCE.getConfigurationView_AdapterFactory(configFilter);

			if ( options != null && options.isPublishProcess() )
			{
				makeProcessClosure();
			} 

			// publish all the views in the configuration
			List views = config.getProcessViews();
			for ( Iterator it = views.iterator(); it.hasNext(); )
			{
				if ( monitor.isCanceled() )
				{
					return null;
				}
				
				ContentCategory v = (ContentCategory)it.next();
				if ( !ConfigurationHelper.canShow(v, config) )
				{
					continue;
				}
				
				Object element = LibraryUtil.unwrap(v);
				Bookmark b = createBookmark(this.monitor, element);

				if ( v == config.getDefaultView() )
				{
					super.defaultView = b;
				}

				// iterate thru configuration to build the view
				iterate(v, b);
				if ( b.getChildCount() > 0 )
				{
					bookmarks.add(b);					
				}
			}
			
			if ( monitor.isCanceled() )
			{
				return null;
			}
		}			


		publishReferenceElements();
		
		copyIconsForNonApplet();
		
		if ( monitor.isCanceled() )
		{
			return null;
		}
		
		// save published element urls
		saveElementUrls();
		
		return bookmarks;
	}	
	
	/**
	 * The process element closure is generated as follows:
	 * 
	 * 1. publish the selected processses, which brings in all the related process elements
	 * 2. publish all the referenced process elements from step 1, this brings in all the directly referenced content elements.
	 *    make a first level closure to include the published elements and the referenced elements. 
	 *    Any direct references to any type of guidances are also in this closure.
	 * 3. publish all the referened non-ContentCategory content elements from step 2. based on the first level closure. 
	 * The purpose of the first level closure is to allow bring in guidances with valid element link 
	 * and any other references such as a Task or Role, being linked with a missing element link.
	 *  This again brings in all the direct references
	 * 4. Make the final closure by including the following elements:
	 *     a. all published elements from step 1,2,3. 
	 *     b. all referenced Guidances from step 3
	 *     c. all Guidances of type Practice, RoadMap, Suporting Material, and Term Definition, in the configuration
	 *     d. all Content Categories that contains at least one element of type a, b, or c. and their parent categories
	 *
	 * The selected view is published based on the element closure defined above.
	 */
	private void makeProcessClosure() {
		monitor.subTask(PublishingResources.buildingProcessClosureTask_name); 

		// publish the selected processes
		// need to build a closure of all the elements involved in the
		// processes
		List processes = options.getDeliverProcessList();
		if ( processes != null && processes.size() > 0 ) {
			for (Iterator it = processes.iterator(); it.hasNext(); ) {
				makeProcessClosure( (org.eclipse.epf.uma.Process)it.next());
				if (monitor.isCanceled()) {
					return;
				}
			}
		}
		
		// make the first level closure to include all the process elements and it's referenced elements
		// any thing except Guidances and ContentCategories outside the closure is filtered 
		getValidator().addClosureElements(getValidator().getPublishedElements());
		getValidator().addClosureElements(getValidator().getReferencedElements());

		// now publish all referenced elements, any direct references in the process elements are 
		// part of the closure
		// don't publish content categories for now since they might be empty and discarded later 
		List refs = new ArrayList(getValidator().getReferencedElements());		
		for (Iterator it = refs.iterator(); it.hasNext(); ) {
			MethodElement e = (MethodElement)it.next();
			if ( !(e instanceof ContentCategory) ) {
				super.publish(monitor, e);
				
				// collect process specific layout info with suppression status
				// this will incldue the diagrams and the supression states of
				// each item under the current procee
				if (e instanceof org.eclipse.epf.uma.Process) {
					publishProcessLayout((org.eclipse.epf.uma.Process) e);
				}

			}
		}
		
		
		// now, any referenced guidance should be in the closure, 
		// so include them and make the final closure
		refs.clear();	
		for (Iterator it = getValidator().getReferencedElements().iterator(); it.hasNext(); ) {
			MethodElement e = (MethodElement)it.next();
			if ( e instanceof Guidance ) {
				refs.add(e);				
			}
		}
		
		if ( refs.size() > 0 ) {
			getValidator().addClosureElements(refs);
		}
		
		// now all the published elements are the element closure, make the final closure
		getValidator().makeElementClosure();
	}
	
	private void makeProcessClosure(org.eclipse.epf.uma.Process proc) {
	
		if ( proc == null ) {
			return;
		}
		
		if ( ConfigurationHelper.canShow(proc, config) )
		{
			ActivityLayout l = new ActivityLayout();
			l.init(getLayoutMgr(), proc, proc, null);
			l.findAllLinkedElements();
		}
	
		if (monitor.isCanceled()) {
			return;
		}
		
		if ( ConfigurationHelper.isExtender(proc) ) {
			org.eclipse.epf.uma.Process baseProc = (org.eclipse.epf.uma.Process)
				proc.getVariabilityBasedOnElement();
			if ( ConfigurationHelper.inConfig(baseProc, config) ) {
				makeProcessClosure(baseProc);
			}
		}
		
	}


	private void publishReferenceElements() {
		// now process the referenced elements and publish the contents
		while (getValidator().getReferencedElements().size() > 0) {
			MethodElement e = (MethodElement) getValidator()
					.getReferencedElements().remove(0);

			try {
				if (monitor.isCanceled()) {
					return;
				}

				// references to method plugins and method packages can be
				// ignored
				if (e instanceof MethodPlugin || e instanceof MethodPackage) {
					continue;
				}
				super.publish(monitor, e);

				// collect process specific layout info with suppression status
				// this will incldue the diagrams and the supression states of
				// each item under the current procee
				if (e instanceof org.eclipse.epf.uma.Process) {
					publishProcessLayout((org.eclipse.epf.uma.Process) e);
				}
			} catch (Exception ex) {
				ex.printStackTrace();
				getValidator().logError(e, "Error publishing element", ex); //$NON-NLS-1$
			}
		}
	}

	private void publishProcessLayout(final org.eclipse.epf.uma.Process e) {

		Runnable runnable = new Runnable() {
			public void run() {
				try {
					ActivityLayout layout = new ActivityLayout();
					layout.init(getLayoutMgr(), (org.eclipse.epf.uma.Process) e, null,
							null);
					ProcessLayoutData pd = new ProcessLayoutData(e.getGuid());
					layout.loadLayoutData(pd);
					printLayoutScript(pd);
				} catch (Exception e1) {
					getValidator()
							.logError(
									e,
									"Error publishing process specific layout data", e1); //$NON-NLS-1$
				}

			}
		};

		Timer timer = new Timer();
		try {

			// run the publishing and check the time, if timeout, terminate it
			Thread t = new Thread(runnable);
			t.start();
			t.join(timeout_millis);
			if (t.isAlive()) {
				// wait for the thread to die and log an error
				timer.stop();
				getValidator()
						.logInfo(
								e,
								"publishing process specific layout data takes " + timer.getTime() + " mini seconds already and is still not done yet ..."); //$NON-NLS-1$ //$NON-NLS-2$
				timer.start();
				t.join();
			}
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		} finally {
			timer.stop();
			getValidator()
					.logInfo(
							e,
							timer.getTotalTime()
									+ " mini seconds publishing process specific layout data"); //$NON-NLS-1$
		}

	}

	private void printLayoutScript(ProcessLayoutData data) {
		File outputFile = new File(getLayoutMgr().getPublishDir(),
				"/scripts/activitylayout.js"); //$NON-NLS-1$
		PrintStream ps = null;
		try {
			ps = new PrintStream(new FileOutputStream(outputFile, true), true);
			data.print(ps);
		} catch (Exception e) {

		} finally {
			if (ps != null) {
				ps.flush();
				ps.close();
			}
		}

	}

	// /**
	// * build a closure for the element and fill the list with the elements
	// referenced by this element and it's referenced elements, ..., within the
	// configuration
	// * @param element MethodElement
	// * @param colsureElements List
	// */
	// private void buildElementClosure(MethodElement element,
	// MethodConfiguration config, List closureElements)
	// {
	// if ( monitor != null )
	// {
	// monitor.subTask(PublishingResources.formatString("Publishing.buildingElementClosureTask.name",
	// element.getName()) ); //$NON-NLS-1$
	// }
	//
	// List properties = element.getInstanceProperties();
	// if (properties != null)
	// {
	// // get element references
	// for (int i = 0; i < properties.size(); i++)
	// {
	// EStructuralFeature feature = (EStructuralFeature)properties.get(i);
	// EClassifier type = feature.getEType();
	// if ( !(type instanceof EClass) )
	// {
	// continue;
	// }
	//
	// if ( feature.isMany() )
	// {
	// List items = calc0nFeatureValue(element, feature);
	// if ( items != null && items.size() > 0 )
	// {
	// for ( Iterator it = items.iterator(); it.hasNext(); )
	// {
	// MethodElement e = (MethodElement) it.next();
	// if ( (e != null) && (e != element) && !closureElements.contains(e) )
	// {
	// closureElements.add(e);
	// buildElementClosure(e, config, closureElements);
	// }
	// }
	// }
	// }
	// else
	// {
	// MethodElement e = calc01FeatureValue(element, feature);
	// if ( (e != null) && (e != element) && !closureElements.contains(e) )
	// {
	// closureElements.add(e);
	// buildElementClosure(e, config, closureElements);
	// }
	// }
	// }
	// }
	// }

	/**
	 * Iterate thru tuee
	 * 
	 * @param obj
	 * @param parent
	 */
	private void iterate(Object obj, Bookmark parent) {
		try {
			if (monitor.isCanceled()) {
				return;
			}

			// Get the adapter from the factory.
			ITreeItemContentProvider treeItemContentProvider = null;
			if (obj instanceof ITreeItemContentProvider) {
				treeItemContentProvider = (ITreeItemContentProvider) obj;
			} else {
				treeItemContentProvider = (ITreeItemContentProvider) adapterFactory
						.adapt(obj, ITreeItemContentProvider.class);
			}

			// Either delegate the call or return nothing.
			if (treeItemContentProvider != null) {
				Collection items = treeItemContentProvider.getChildren(obj);
				for (Iterator it = items.iterator(); it.hasNext();) {
					if (monitor.isCanceled()) {
						return;
					}

					// create bookmark
					Object itorObj = it.next();
					Object element = LibraryUtil.unwrap(itorObj);

					if ((element instanceof MethodElement)) {
						MethodElement me = (MethodElement) element;
						try {
							if (ConfigurationHelper.canShow(me, config)) {
								me = ConfigurationHelper
										.getCalculatedElement(me,
												getLayoutMgr()
														.getElementRealizer());
								if (me != null) {
									if (me instanceof Tool) {
										buildToolSubTree((Tool) me, parent);
									} else if (me instanceof Discipline) {
										buildDisciplineSubTree((Discipline) me,
												parent);
									}

									// else if (me instanceof DisciplineGrouping
									// || me instanceof Domain || me instanceof
									// WorkProductType
									// || me instanceof RoleSetGrouping || me
									// instanceof RoleSet )
									else if (me instanceof ContentCategory) {
										
										ContentCategory cc = (ContentCategory)me;
										
										// if the content category is empty,
										// don't add to the parent
										Bookmark b = createBookmark(
												this.monitor, cc);
										iterate(itorObj, b);
										if ( options.includeEmptyCategories || 
												b.getChildCount() > 0) {
											parent.addChild(b);
											discardEmptyCategory(cc, false);
										} else {
											discardEmptyCategory(cc, true);
										}
									} else {
										Bookmark b = createBookmark(me, parent);
										if (!buildSubTree(itorObj, me, b)) {
											iterate(itorObj, b);
										}
									}
								}
							}
						} catch (Exception e) {
							String message = "Error building navigation tree for " + LibraryUtil.getTypeName(me); //$NON-NLS-1$
							builder.getValidator().logError(message, e);
							e.printStackTrace();
						}
					} else {
						iterate(itorObj, parent);
					}

				}
			}
		} catch (Exception e) {
			String message = "Error building navigation tree"; //$NON-NLS-1$
			builder.getValidator().logError(message, e);

			e.printStackTrace();
		}
	}

	/**
	 * create a bookmark under the specified parent. If no parent is specified,
	 * 
	 * @param monitor
	 * @param element
	 * @param parent
	 * @return
	 */
	protected Bookmark createBookmark(Object element, Bookmark parent) {
		Bookmark b = createBookmark(this.monitor, element);
		if (parent == null) {
			bookmarks.add(b);
		} else {
			parent.addChild(b);
		}

		return b;
	}

	/**
	 * build the sub tree for the given element. return true if the element is
	 * handled, false otherwise
	 * 
	 * @param element
	 * @param bm
	 * @return boolean
	 */
	private boolean buildSubTree(Object obj, MethodElement element, Bookmark bm) {
		if (element instanceof Task) {
			buildTaskSubTree((Task) element, bm);
		} else if (element instanceof Role) {
			buildRoleSubTree((Role) element, bm);
		} else if (element instanceof WorkProduct) {
			buildWorkProductSubTree((WorkProduct) element, bm);
		} else if (element instanceof org.eclipse.epf.uma.Process) {
			buildProcessSubTree(obj, (org.eclipse.epf.uma.Process) element, bm);
		} else {
			// System.out.println("Not handled: " + element);
			return false;
		}

		return true;
	}


	private void buildItems(List elements, Bookmark bm) {
		buildItems(elements, bm, false);
	}

	private void buildItems(List elements, Bookmark bm, boolean buildSubTree) {
		for (Iterator it = elements.iterator(); it.hasNext();) {
			if (monitor.isCanceled()) {
				return;
			}

			Object element = it.next();
			buildItem((MethodElement) element, bm, buildSubTree);
		}
	}

	private Bookmark buildItem(MethodElement element, Bookmark parent,
			boolean buildSubTree) {
		if (monitor.isCanceled()) {
			return null;
		}

		Bookmark b = null;

		// make sure the element is showable
		MethodElement e = ConfigurationHelper.getCalculatedElement(element,
				getLayoutMgr().getElementRealizer());
		if (canShow(e)) {
			b = createBookmark(this.monitor, e);
			if (b == null) {
				return b;
			}

			parent.addChild(b);

			if (buildSubTree) {
				if (e instanceof Artifact) {
					buildContainedArtifactsSubTree((Artifact) e, b, true);
				}
			}
		}

		return b;
	}

	/**
	 * create the folder bookmark and it's children. generate the folder summary
	 * page
	 * 
	 * @param element
	 * @param bm
	 * @param nodeName
	 * @param items
	 */

	private Bookmark createFolderBookmark(MethodElement element, Bookmark bm,
			String nodeName, List items, boolean createChildren) {
		Bookmark b = null;
		if (items.size() > 0) {
			IElementLayout l = new SummaryPageLayout(
					builder.getLayoutManager(), element, nodeName, items);
			String url = l.getUrl();
			builder.generateHtml(l);
			b = createBookmark(nodeName, nodeName, url, ICON_FOLDER,
					ICON_FOLDER);
			bm.addChild(b);
			if (createChildren) {
				buildItems(items, b);
			}
		}

		return b;
	}

	private Bookmark createFolderBookmark(MethodElement element, Bookmark bm,
			String prefixName, String nodeName, List items,
			boolean createChildren) {
		Bookmark b = null;
		if (items.size() > 0) {
			IElementLayout l = new SummaryPageLayout(
					builder.getLayoutManager(), element, prefixName, nodeName,
					items);
			String url = l.getUrl();
			builder.generateHtml(l);
			b = createBookmark(nodeName, nodeName, url, ICON_FOLDER,
					ICON_FOLDER);
			bm.addChild(b);
			if (createChildren) {
				buildItems(items, b);
			}
		}

		return b;
	}

	private Bookmark buildDisciplineSubTree(Discipline element, Bookmark parent) {
		String url = ""; //$NON-NLS-1$
		Bookmark b;

		// need to calculate the realized value of the feature
		List items_workflow = calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getDiscipline_ReferenceWorkflows());

		// RATLC00384499 - Tasks in published site under Disciplines are in
		// random order
		// use the adaptor factory to get the childrens
		// List items_task = ConfigurationHelper.calc0nFeatureValue(element,
		// UmaPackage.eINSTANCE.getDiscipline_Tasks(), config);
		List items_task = new ArrayList();
		List item_subDisciplies = new ArrayList();
		ITreeItemContentProvider treeItemContentProvider = (ITreeItemContentProvider) adapterFactory
				.adapt(element, ITreeItemContentProvider.class);
		if (treeItemContentProvider != null) {
			Collection items = treeItemContentProvider.getChildren(element);
			for (Iterator it = items.iterator(); it.hasNext();) {
				if (monitor.isCanceled()) {
					return null;
				}

				// create bookmark
				Object itorObj = it.next();
				Object e = LibraryUtil.unwrap(itorObj);
				if ((e instanceof Task)) {
					MethodElement t = ConfigurationHelper.getCalculatedElement(
							(MethodElement) e, getLayoutMgr()
									.getElementRealizer());
					if ( t != null ) {
						items_task.add(t);
					}
				} else if ( e instanceof Discipline ) {
					MethodElement d = ConfigurationHelper.getCalculatedElement(
							(MethodElement) e, getLayoutMgr()
									.getElementRealizer());
					if ( d != null ) {
						item_subDisciplies.add(d);
					}
					
				}
			}
		}

		if (monitor.isCanceled()) {
			return null;
		}

		// all guidances
		List items_guidance = new ArrayList();
		items_guidance.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Assets()));
		items_guidance.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Checklists()));
		items_guidance.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_ConceptsAndPapers()));
		items_guidance.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Examples()));
		items_guidance.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Guidelines()));
		items_guidance.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_SupportingMaterials()));

		if (!options.includeEmptyCategories && 
				items_workflow.size() + items_task.size() + items_guidance.size() 
				+ item_subDisciplies.size() == 0) {
			// do nothing, don't show the folder
			discardEmptyCategory(element, true);
			return null;
		}

		if (monitor.isCanceled()) {
			return null;
		}

		// create the item bookmark
		// don't set to the parent yet. make sure it's not empty
		// need to check the sub-disciplines
		// 150984 - Publishing: Nested discipline is not display in the publish page 
		//Bookmark bm = createBookmark(element, parent);
		Bookmark bm = createBookmark(this.monitor, element);

		// sub-disciplines come first
		if ( item_subDisciplies.size() > 0 ) {
			for (Iterator it = item_subDisciplies.iterator();  it.hasNext(); ) {
				Discipline d = (Discipline)it.next();
				buildDisciplineSubTree(d, bm);
			}
		}
		
		if ( options.generateLightWeightTree ) {
			
			Collections.sort(items_workflow, nameComparator);
			Collections.sort(items_task, nameComparator);
			Collections.sort(items_guidance, nameComparator);
			
			buildItems(items_workflow, bm);
			buildItems(items_task, bm);
			buildItems(items_guidance, bm);			
		} else {
			if (items_workflow.size() > 0) {
				Bookmark wfFolder = createFolderBookmark(element, bm,
						PREFIX_Reference_Workflows, NODE_Reference_Workflows,
						items_workflow, false);
	
				// RATLC00384489 - Capability Patterns in treebrowser under
				// disciplines-reference workflows cannot be expanded
				for (Iterator it = items_workflow.iterator(); it.hasNext();) {
					if (monitor.isCanceled()) {
						return null;
					}
	
					org.eclipse.epf.uma.Process proc = (org.eclipse.epf.uma.Process) it.next();
					Bookmark bmWorkflow = buildItem(proc, wfFolder, false);
					buildProcessSubTree(proc, proc, bmWorkflow);
				}
			}
	
			if (monitor.isCanceled()) {
				return null;
			}
	
			if (items_task.size() > 0) {
				createFolderBookmark(element, bm, PREFIX_Tasks, NODE_Tasks,
						items_task, true);
			}
	
			if (monitor.isCanceled()) {
				return null;
			}
	
			if (items_guidance.size() > 0) {
				createFolderBookmark(element, bm, PREFIX_Guidances, NODE_Guidances,
						items_guidance, true);
			}
		}
		
		if (options.includeEmptyCategories || bm.getChildCount() > 0) {
			parent.addChild(bm);
			discardEmptyCategory(element, false);
		} else {
			discardEmptyCategory(element, true);
		}
		
		return bm;
	}

	private void buildToolSubTree(Tool element, Bookmark parent) {
		if (monitor.isCanceled()) {
			return;
		}

		List items = calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getTool_ToolMentors());
		if (options.includeEmptyCategories || items.size() > 0) {
			Bookmark b = createBookmark(element, parent);
			buildItems(items, b);
			discardEmptyCategory(element, false);
		} else {
			discardEmptyCategory(element, true);
		}
	}

	private void buildTaskSubTree(Task element, Bookmark bm) {
		
		String url;
		Bookmark b;

		List allItems = new ArrayList();
		
		// performing roles
		List items = new ArrayList();
		Role r = (Role) calc01FeatureValue(element, UmaPackage.eINSTANCE
				.getTask_PerformedBy());
		if (r != null) {
			items.add(r);
		}
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getTask_AdditionallyPerformedBy()));

		if (items.size() > 0) {
			if ( options.generateLightWeightTree ) {
				Collections.sort(items, nameComparator);
				allItems.addAll(items);
			} else {
				createFolderBookmark(element, bm, PREFIX_Performing_Roles,
						NODE_Performing_Roles, items, true); 
			}
		}

		if (monitor.isCanceled()) {
			return;
		}

		if ( !options.generateLightWeightTree ) {
			// input work products, need a summary page,
			items = new ArrayList();
			items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
					.getTask_MandatoryInput()));
			items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
					.getTask_OptionalInput()));
	
			if (items.size() > 0) {
				createFolderBookmark(element, bm, PREFIX_Input_Work_Products,
						NODE_Input_Work_Products, items, true);
			}
	
			if (monitor.isCanceled()) {
				return;
			}
		}
		
		// output work products, need a summary page, TODO
		items = calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getTask_Output());

		if (items.size() > 0) {
			if ( options.generateLightWeightTree ) {
				Collections.sort(items, nameComparator);
				allItems.addAll(items);
			} else {
				createFolderBookmark(element, bm, PREFIX_Output_Work_Products,
						NODE_Output_Work_Products, items, true);
			}
		}

		if (monitor.isCanceled()) {
			return;
		}

		// all guidances
		items.clear();
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Assets()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Checklists()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_ConceptsAndPapers()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Examples()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Guidelines()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_SupportingMaterials()));
//		Object e = calc01FeatureValue(element, UmaPackage.eINSTANCE
//				.getTask_Estimate());
//		if (e != null) {
//			items.add(e);
//		}
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getTask_ToolMentors()));

		if (items.size() > 0) {
			if ( options.generateLightWeightTree ) {
				Collections.sort(items, nameComparator);
				allItems.addAll(items);
			} else {
				createFolderBookmark(element, bm, PREFIX_Guidances, NODE_Guidances,
						items, true);
			}
		}
		
		if ( options.generateLightWeightTree ) {
			buildItems(allItems, bm);
		} 

	}

	private void buildRoleSubTree(Role element, Bookmark bm) {
		String url;
		Bookmark b;

		if (monitor.isCanceled()) {
			return;
		}

		List allItems = new ArrayList();
		
		// tasks, // need a general overview page, TODO
		// List items = AssociationHelper.getPrimaryTasks(element);
		List items = calc0nFeatureValue(element,
				AssociationHelper.Role_Primary_Tasks);
		if (items.size() > 0 ) {
			if ( options.generateLightWeightTree ) {
				Collections.sort(items, nameComparator);
				allItems.addAll(items);
			} else {
				createFolderBookmark(element, bm, PREFIX_ResponsibleFor_Tasks,
						NODE_ResponsibleFor_Tasks, items, true);
			}
		}

		if (monitor.isCanceled()) {
			return;
		}

		if ( !options.generateLightWeightTree ) {
			// secondary tasks
			items = calc0nFeatureValue(element,
					AssociationHelper.Role_Secondary_Tasks);
			if (items.size() > 0) {
				createFolderBookmark(element, bm, PREFIX_ParticipatesIn_Tasks,
						NODE_ParticipatesIn_Tasks, items, true);
			}
		}
		
		if (monitor.isCanceled()) {
			return;
		}

		// responsible for work products, need a summary page, TODO
		// items = element.getResponsibleFor();
		items = calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getRole_ResponsibleFor());
		if (items.size() > 0 ) {
			if ( options.generateLightWeightTree ) {
				Collections.sort(items, nameComparator);
				allItems.addAll(items);
			} else {
				b = createFolderBookmark(element, bm, PREFIX_Work_Products_Created,
						NODE_Work_Products_Created, items, false);
				buildItems(items, b, true);
			}
		}

		if (monitor.isCanceled()) {
			return;
		}

		if ( !options.generateLightWeightTree ) {
			// modifies work products, need a summary page, TODO
			items = calc0nFeatureValue(element, UmaPackage.eINSTANCE
					.getRole_Modifies());
			if (items.size() > 0) {
				b = createFolderBookmark(element, bm,
						PREFIX_Work_Products_Modified, NODE_Work_Products_Modified,
						items, false);
				buildItems(items, b, true);
			}
	
			if (monitor.isCanceled()) {
				return;
			}
		}
		
		// all guidances
		items.clear();
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Assets()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Checklists()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_ConceptsAndPapers()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Examples()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Guidelines()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_SupportingMaterials()));

		if (items.size() > 0) {
			if ( options.generateLightWeightTree ) {
				Collections.sort(items, nameComparator);
				allItems.addAll(items);
			} else {
				createFolderBookmark(element, bm, NODE_Guidances, items, true);
			}
		}

		if ( options.generateLightWeightTree ) {
			// light weight tree, no sub folders
			buildItems(allItems, bm);
		} 
	}

	private void buildWorkProductSubTree(WorkProduct element, Bookmark bm) {
		List items;
		String url = ""; //$NON-NLS-1$
		// Bookmark b;

		if (monitor.isCanceled()) {
			return;
		}

		List allItems = new ArrayList();
		
		// performing roles, 0.1 reference element will be realized in buildItem
//		multiplicity change for opposite features
//		Role r = AssociationHelper.getResponsibleRole(element);
		items = calc0nFeatureValue(element, AssociationHelper.WorkProduct_ResponsibleRoles);
		if ( items.size() > 0 ) {
			if ( options.generateLightWeightTree ) {
				Collections.sort(items, nameComparator);
				allItems.addAll(items);
			} else {
				createFolderBookmark(element, bm, PREFIX_Responsible_Role,
							NODE_Responsible_Role, items, true);
			}
		}

		if (monitor.isCanceled()) {
			return;
		}

		// containing work products, need a summary page, TODO
		if (element instanceof Artifact) {
			
			if ( !options.generateLightWeightTree ) {
				WorkProduct wp = ((Artifact) element).getContainerArtifact();
				createBookmark(NODE_Containing_Work_Product,
						NODE_Containing_Work_Product, url, "", ""); //$NON-NLS-1$ //$NON-NLS-2$
				if (wp != null) {
					items = new ArrayList();
					items.add(wp);
					createFolderBookmark(element, bm,
							PREFIX_Containing_Work_Product,
							NODE_Containing_Work_Product, items, true);
				}
	
				if (monitor.isCanceled()) {
					return;
				}
			}
			
			// contained work products, need a summary page, TODO
			// items = ((Artifact)element).getContainedArtifacts();
			items = calc0nFeatureValue(element, UmaPackage.eINSTANCE
					.getArtifact_ContainedArtifacts());

			// make sure the contained elements does not contain the container,
			// this is possible due to realization, say, the containing element
			// contribute to the container
			items.remove(element);

			if (items.size() > 0) {
				if ( options.generateLightWeightTree ) {
					Collections.sort(items, nameComparator);
					allItems.addAll(items);
				} else {
					Bookmark b = createFolderBookmark(element, bm,
							PREFIX_Contained_Work_Products,
							NODE_Contained_Work_Products, items, false);
	
					// for each contained work product, create the nested sub tree
					buildItems(items, b, true);
				}
			}
		}

		if (monitor.isCanceled()) {
			return;
		}

		if ( !options.generateLightWeightTree ) {
			// input to tasks
			items = new ArrayList();
			items.addAll(calc0nFeatureValue(element,
					AssociationHelper.WorkProduct_MandatoryInputTo_Tasks));
			items.addAll(calc0nFeatureValue(element,
					AssociationHelper.WorkProduct_OptionalInputTo_Tasks));
			if (items.size() > 0) {
				createFolderBookmark(element, bm, PREFIX_InputTo_Task,
						NODE_InputTo_Task, items, true);
			}
	
			if (monitor.isCanceled()) {
				return;
			}
	
			// output from tasks
			items = calc0nFeatureValue(element,
					AssociationHelper.WorkProduct_OutputFrom_Tasks);
			if (items.size() > 0) {
				createFolderBookmark(element, bm, PREFIX_OutputOf_Task,
						NODE_OutputOf_Task, items, true);
			}
	
			if (monitor.isCanceled()) {
				return;
			}
		}
		
		// all guidances
		items = new ArrayList();
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Assets()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Checklists()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_ConceptsAndPapers()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Examples()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Guidelines()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_SupportingMaterials()));
//		Object e = calc01FeatureValue(element, UmaPackage.eINSTANCE
//				.getWorkProduct_Estimate());
//		if (e != null) {
//			items.add(e);
//		}
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getWorkProduct_Reports()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getWorkProduct_Templates()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getWorkProduct_ToolMentors()));

		if (items.size() > 0) {
			if ( options.generateLightWeightTree ) {
				Collections.sort(items, nameComparator);
				allItems.addAll(items);
			} else {
				createFolderBookmark(element, bm, PREFIX_Guidances, NODE_Guidances,
						items, true);
			}
		}
		
		if ( options.generateLightWeightTree ) {
			buildItems(allItems, bm);
		}
	}

	private void buildContainedArtifactsSubTree(Artifact element, Bookmark bm,
			boolean showGuidances) {
		if (monitor.isCanceled()) {
			return;
		}

		List items;
		String url = ""; //$NON-NLS-1$
		// Bookmark b;

		// // performing roles, 0.1 reference element will be realized in
		// buildItem
		// Role r = AssociationHelper.getResponsibleRole(element);
		// if ( r != null )
		// {
		// items = new ArrayList();
		// items.add(r);
		// createFolderBookmark(element, bm, NODE_Responsible_Role, items,
		// true);
		// }

		// WorkProduct wp = ((Artifact)element).getContainerArtifact();
		// createBookmark(NODE_Containing_Work_Product,
		// NODE_Containing_Work_Product, url, "", "");
		// if ( wp != null )
		// {
		// items = new ArrayList();
		// items.add(wp);
		// createFolderBookmark(element, bm, NODE_Containing_Work_Product,
		// items, true);
		// }

		// contained work products, need a summary page, TODO
		// items = ((Artifact)element).getContainedArtifacts();
		items = calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getArtifact_ContainedArtifacts());

		// make sure the contained elements does not contain the container,
		// this is possible due to realization, say, the containing element
		// contribute to the container
		items.remove(element);

		if (monitor.isCanceled()) {
			return;
		}

		if (items.size() > 0) {
			// Bookmark b = createFolderBookmark(element, bm,
			// NODE_Contained_Work_Products, items, false);

			// for each contained work product, create the nested sub tree
			for (Iterator it = items.iterator(); it.hasNext();) {
				if (monitor.isCanceled()) {
					return;
				}

				Artifact e = (Artifact) it.next();
				buildItem(e, bm, true);
			}
		}

		// // input to tasks
		// items = new ArrayList();
		// items.addAll(ConfigurationHelper.calc0nFeatureValue(element,
		// AssociationHelper.WorkProduct_MandatoryInputTo_Tasks, config));
		// items.addAll(ConfigurationHelper.calc0nFeatureValue(element,
		// AssociationHelper.WorkProduct_OptionalInputTo_Tasks, config));
		// if ( items.size() > 0 )
		// {
		// createFolderBookmark(element, bm, NODE_InputTo_Task, items, true);
		// }
		//
		// // output from tasks
		// items = ConfigurationHelper.calc0nFeatureValue(element,
		// AssociationHelper.WorkProduct_OutputFrom_Tasks, config);
		// if ( items.size() > 0 )
		// {
		// createFolderBookmark(element, bm, NODE_OutputOf_Task, items, true);
		// }

		if (!showGuidances) {
			return;
		}

		if (monitor.isCanceled()) {
			return;
		}

		// all guidances
		items = new ArrayList();
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Assets()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Checklists()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_ConceptsAndPapers()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Examples()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_Guidelines()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getContentElement_SupportingMaterials()));
//		Object e = calc01FeatureValue(element, UmaPackage.eINSTANCE
//				.getWorkProduct_Estimate());
//		if (e != null) {
//			items.add(e);
//		}
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getWorkProduct_Reports()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getWorkProduct_Templates()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getWorkProduct_ToolMentors()));

		if (items.size() > 0) {
			// createFolderBookmark(element, bm, NODE_Guidances, items, true);
			buildItems(items, bm);
		}
	}

	/**
	 * iterate the break down structure and build the xml document
	 * 
	 * @param parentObj
	 *            The object to iterate. It can be a breakdown element, or it's
	 *            adaptor
	 * @param parentXml
	 * @param adapterFactory
	 */
	private void iterateActivity(ProcessElementItem parentItem,
			Bookmark parentBm, ComposedAdapterFactory adapterFactory,
			Suppression sup) {
		if (monitor.isCanceled()) {
			return;
		}

		ITreeItemContentProvider provider = null;
		Object parentObj = parentItem.rawItem;

		if (parentObj instanceof ITreeItemContentProvider) {
			provider = (ITreeItemContentProvider) parentObj;
		} else {
			provider = (ITreeItemContentProvider) adapterFactory.adapt(
					parentObj, ITreeItemContentProvider.class);
		}

		if (provider != null) {
			// String displayName = ProcessUtil.getAttribute(parentObj,
			// IBSItemProvider.COL_PRESENTATION_NAME, provider);
			// parentXml.setAttribute("DisplayName", displayName);

			Collection children = provider.getChildren(parentObj);
			for (Iterator it = children.iterator(); it.hasNext();) {
				if (monitor.isCanceled()) {
					return;
				}

				Object rawitem = it.next();
				if (sup.isSuppressed(rawitem)) {
					continue;
				}

				MethodElement item = (MethodElement) LibraryUtil
						.unwrap(rawitem);
				if (!(item instanceof Activity)) {
					continue;
				}

				ProcessElementItem elementItem = new ProcessElementItem(
						rawitem, item, parentItem);

				Bookmark child = buildItem(elementItem.element, parentBm, false);
				if (child != null) {
					// set the query string
					child.setQueryString(elementItem.getQueryString());

					IBSItemProvider adapter = null;
					if (rawitem instanceof IBSItemProvider) {
						adapter = (IBSItemProvider) rawitem;
					} else {
						adapter = (IBSItemProvider) adapterFactory.adapt(item,
								ITreeItemContentProvider.class);
						;
					}

					String displayName = ProcessUtil.getAttribute(item,
							IBSItemProvider.COL_PRESENTATION_NAME, adapter);
					child.setPresentationName(displayName);

					iterateActivity(elementItem, child, adapterFactory, sup);
				}
			}
		}
	}

	private void buildProcessSubTree(Object obj, org.eclipse.epf.uma.Process element,
			Bookmark bm) {
		if (monitor.isCanceled()) {
			return;
		}

		List items = new ArrayList();

		ProcessElementItem procItem = new ProcessElementItem(obj, element,
				element.getGuid());

		ComposedAdapterFactory adapterFactory = super.getLayoutMgr()
				.getWBSAdapterFactory();
		Suppression sup = new Suppression(element);
		iterateActivity(procItem, bm, adapterFactory, sup);

		// ITreeItemContentProvider provider = null;
		//		
		// if ( obj instanceof ITreeItemContentProvider )
		// {
		// provider = (ITreeItemContentProvider)obj;
		// }
		// else
		// {
		// // work breakdown structure
		// ComposedAdapterFactory adapterFactory =
		// TngAdapterFactory.INSTANCE.getWBS_ComposedAdapterFactory();
		// provider = (ITreeItemContentProvider) adapterFactory.adapt(element,
		// ITreeItemContentProvider.class);
		// }
		//		
		// if (provider != null )
		// {
		// Collection children = provider.getChildren(element) ;
		// for (Iterator it = children.iterator(); it.hasNext();)
		// {
		// items.add(LibraryUtil.unwrap(it.next()));
		// }
		// }

		String url;
		Bookmark b;

		// if ( items.size() > 0 )
		// {
		// //createFolderBookmark(element, bm, NODE_Work_Break_Down_Structure,
		// items, true);
		// buildItems(items, bm);
		// }

		// // included patterns, need a summary page, TODO
		// //items = element.getIncludesPatterns();
		// items = ConfigurationHelper.calc0nFeatureValue(element,
		// UmaPackage.eINSTANCE.getProcess_IncludesPatterns(), config);
		//
		// if ( items.size() > 0 )
		// {
		// createFolderBookmark(element, bm, NODE_Included_Patterns, items,
		// true);
		// }

		if (monitor.isCanceled()) {
			return;
		}

		// all guidances
		items = new ArrayList();
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getActivity_Checklists()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getActivity_Concepts()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getActivity_Examples()));
		items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
				.getActivity_Guidelines()));

		if (element instanceof DeliveryProcess) {
			DeliveryProcess dp = (DeliveryProcess) element;
			items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
					.getDeliveryProcess_CommunicationsMaterials()));
			items.addAll(calc0nFeatureValue(element, UmaPackage.eINSTANCE
					.getDeliveryProcess_EducationMaterials()));
		}

		if (items.size() > 0) {
			createFolderBookmark(element, bm, PREFIX_Guidances, NODE_Guidances,
					items, true);
		}
	}

	public void dispose() {
		super.dispose();
		
		elementUrls.clear();
	}
	
	protected Set elementUrls = new HashSet();
	protected void elementPublished(IElementLayout layout, String htmlfile) {
		// only for process element for now
		// may cover all method elements later
		if ( layout.getElement() instanceof ProcessElement ) {
			ElementUrl url = new ElementUrl(layout.getElement().getGuid(), layout.getUrl(), layout.getDisplayName() );
			elementUrls.add(url);
		}
	}
	
	private void saveElementUrls() {
		// save published element urls
		// need to escape the url and text since it will be assigned to a javascript variable as literal
		XmlElement xml = new XmlElement("ElementUrls"); //$NON-NLS-1$
		for ( Iterator it = elementUrls.iterator(); it.hasNext(); ) {
			ElementUrl url = (ElementUrl)it.next();
			xml.newChild("elementUrl", url.guid) //$NON-NLS-1$
				.setAttribute("text", StrUtil.escape(url.text)) //$NON-NLS-1$
				.setAttribute("url", StrUtil.escape(url.url));	//$NON-NLS-1$
		}
		
//		StringBuffer buffer = new StringBuffer();
//		buffer.append(XmlHelper.XML_HEADER).append(xml.toXml());
//		File f = new File(getLayoutMgr().getPublishDir(), "ElementUrls.xml"); //$NON-NLS-1$
//		FileUtil.writeUTF8File(f.getAbsolutePath(), buffer.toString());
		
		String html = PublishingUtil.getHtml(xml, "xsl/elementUrls.xsl");
		File f = new File(getLayoutMgr().getPublishDir(), "scripts/elementUrls.js"); //$NON-NLS-1$
		FileUtil.writeUTF8File(f.getAbsolutePath(), html, true);
	}

	public class ElementUrl{

		String guid;
		String url; 
		String text;
		
		public ElementUrl(String guid, String url, String text) {
			this.guid = guid;
			this.url = url;
			this.text = text;
		}
	}
	
	class EObjectComparator implements Comparator {
		private EStructuralFeature pName = UmaPackage.eINSTANCE.getDescribableElement_PresentationName();
		private EStructuralFeature name = UmaPackage.eINSTANCE.getNamedElement_Name();
		public EObjectComparator() {
			
		}
		
		public int compare(Object e1, Object e2) {
			if ( e1 instanceof EObject && e2 instanceof EObject ) {
				Object v1 = getValue(e1);
				Object v2 = getValue(e2);
				
				if ( v1 == null && v2 == null ) {
					return e1.toString().compareTo(e2.toString());
				} else if ( v1 == null ) {
					return -1;
				} else if ( v2 == null ) {
					return 1;
				} else {
					return v1.toString().compareTo(v2.toString());
				}
			} else {
				return e1.toString().compareTo(e2.toString());
			}
		}
		
		private Object getValue(Object e) {
			Object v = null;
			try { 
				v = ((EObject)e).eGet(pName); 
			} catch (Exception ex){
				
			};
			
			if ( v == null || v.toString().length() == 0 ) { 
				try { 
					v = ((EObject)e).eGet(name); 
				} catch (Exception ex) {
					
				};					
			}

			return v;
		}
	}
}
