/*******************************************************************************
 * Copyright (c) 2000, 2015 QNX Software Systems 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:
 *     QNX Software Systems - Initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.internal.core.model;

import java.io.File;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.CoreModelUtil;
import org.eclipse.cdt.core.model.ICModelMarker;
import org.eclipse.cdt.core.model.ICModelStatus;
import org.eclipse.cdt.core.model.ICModelStatusConstants;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.IContainerEntry;
import org.eclipse.cdt.core.model.IIncludeEntry;
import org.eclipse.cdt.core.model.IIncludeFileEntry;
import org.eclipse.cdt.core.model.ILibraryEntry;
import org.eclipse.cdt.core.model.IMacroEntry;
import org.eclipse.cdt.core.model.IMacroFileEntry;
import org.eclipse.cdt.core.model.IOutputEntry;
import org.eclipse.cdt.core.model.IPathEntry;
import org.eclipse.cdt.core.model.IPathEntryContainer;
import org.eclipse.cdt.core.model.IProjectEntry;
import org.eclipse.cdt.core.model.ISourceEntry;
import org.eclipse.cdt.core.resources.IPathEntryVariableManager;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.preferences.DefaultScope;

public class PathEntryUtil {
	static final PathEntryManager manager = PathEntryManager.getDefault();
	static final IMarker[] NO_MARKERS = new IMarker[0];
	static final boolean VALIDATE_INCLUDE_ENTRIES = 
			DefaultScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID).getBoolean("validate_include_entries", true); //$NON-NLS-1$

	private PathEntryUtil() {
		super();
	}

	public static IPathEntry getExpandedPathEntry(IPathEntry entry, ICProject cproject) throws CModelException {
		switch (entry.getEntryKind()) {
			case IPathEntry.CDT_INCLUDE: {
				IIncludeEntry includeEntry = (IIncludeEntry) entry;
				IPath refPath = includeEntry.getBaseReference();
				if (refPath != null && !refPath.isEmpty()) {
					IPath includePath = includeEntry.getIncludePath();
					if (refPath.isAbsolute()) {
						IResource res = cproject.getCModel().getWorkspace().getRoot().findMember(refPath);
						if (res != null && res.getType() == IResource.PROJECT) {
							IProject project = (IProject)res;
							if (CoreModel.hasCNature(project) || CoreModel.hasCCNature(project)) {
								ICProject refCProject = CoreModel.getDefault().create(project);
								if (refCProject != null) {
									IPathEntry[] entries = manager.getResolvedPathEntries(refCProject);
									for (IPathEntry pathEntry : entries) {
										if (pathEntry.getEntryKind() == IPathEntry.CDT_INCLUDE) {
											IIncludeEntry refEntry = (IIncludeEntry) pathEntry;
											if (refEntry.getIncludePath().equals(includePath)) {
												IPath newBasePath = refEntry.getBasePath();
												// If the includePath is relative, give a new base
												// path if none.
												if (!newBasePath.isAbsolute() && !includePath.isAbsolute()) {
													IResource refRes;
													if (!newBasePath.isEmpty()) {
														refRes = cproject.getCModel().getWorkspace().getRoot().findMember(
																newBasePath);
													} else {
														IPath refResPath = refEntry.getPath();
														refRes = cproject.getCModel().getWorkspace().getRoot().findMember(
																refResPath);
													}
													if (refRes != null) {
														if (refRes.getType() == IResource.FILE) {
															refRes = refRes.getParent();
														}
														newBasePath = refRes.getLocation().append(newBasePath);
													}
												}
												return CoreModel.newIncludeEntry(includeEntry.getPath(), newBasePath, includePath);
											}
										}
									}
								}
							}
						}
					} else { // Container ref
						IPathEntryContainer container = manager.getPathEntryContainer(refPath, cproject);
						if (container != null) {
							IPathEntry[] entries = container.getPathEntries();
							for (IPathEntry pathEntry : entries) {
								if (pathEntry.getEntryKind() == IPathEntry.CDT_INCLUDE) {
									IIncludeEntry refEntry = (IIncludeEntry) pathEntry;
									if (refEntry.getIncludePath().equals(includePath)) {
										IPath newBasePath = refEntry.getBasePath();
										return CoreModel.newIncludeEntry(includeEntry.getPath(), newBasePath, includePath);
									}
								}
							}
						}
					}
				}
				break;
			}

			case IPathEntry.CDT_MACRO: {
				IMacroEntry macroEntry = (IMacroEntry) entry;
				IPath refPath = macroEntry.getBaseReference();
				if (refPath != null && !refPath.isEmpty()) {
					String name = macroEntry.getMacroName();
					if (refPath.isAbsolute()) {
						IResource res = cproject.getCModel().getWorkspace().getRoot().findMember(refPath);
						if (res != null && res.getType() == IResource.PROJECT) {
							IProject project = (IProject)res;
							if (CoreModel.hasCNature(project) || CoreModel.hasCCNature(project)) {
								ICProject refCProject = CoreModel.getDefault().create(project);
								if (refCProject != null) {
									IPathEntry[] entries = manager.getResolvedPathEntries(refCProject);
									for (IPathEntry pathEntry : entries) {
										if (pathEntry.getEntryKind() == IPathEntry.CDT_MACRO) {
											IMacroEntry refEntry = (IMacroEntry) pathEntry;
											if (refEntry.getMacroName().equals(name)) {
												String value = refEntry.getMacroValue();
												return CoreModel.newMacroEntry(macroEntry.getPath(), name, value);
											}
										}
									}
								}
							}
						}
					} else { // Container ref
						IPathEntryContainer container = manager.getPathEntryContainer(refPath, cproject);
						if (container != null) {
							IPathEntry[] entries = container.getPathEntries();
							for (IPathEntry pathEntry : entries) {
								if (pathEntry.getEntryKind() == IPathEntry.CDT_MACRO) {
									IMacroEntry refEntry = (IMacroEntry) pathEntry;
									if (refEntry.getMacroName().equals(name)) {
										String value = refEntry.getMacroValue();
										return CoreModel.newMacroEntry(macroEntry.getPath(), name, value);
									}
								}
							}
						}
					}
				}
				break;
			}

			case IPathEntry.CDT_LIBRARY: {
				ILibraryEntry libEntry = (ILibraryEntry) entry;
				IPath refPath = libEntry.getBaseReference();
				if (refPath != null && !refPath.isEmpty()) {
					IPath libraryPath = libEntry.getLibraryPath();
					if (refPath.isAbsolute()) {
						IResource res = cproject.getCModel().getWorkspace().getRoot().findMember(refPath);
						if (res != null && res.getType() == IResource.PROJECT) {
							IProject project = (IProject)res;
							if (CoreModel.hasCNature(project) || CoreModel.hasCCNature(project)) {
								ICProject refCProject = CoreModel.getDefault().create(project);
								if (refCProject != null) {
									IPathEntry[] entries = manager.getResolvedPathEntries(refCProject);
									for (IPathEntry pathEntry : entries) {
										if (pathEntry.getEntryKind() == IPathEntry.CDT_LIBRARY) {
											ILibraryEntry refEntry = (ILibraryEntry) pathEntry;
											if (refEntry.getLibraryPath().equals(libraryPath)) {
												IPath newBasePath = refEntry.getBasePath();
												// If the libraryPath is
												// relative give a new basepath
												// if none
												if (!newBasePath.isAbsolute() && !libraryPath.isAbsolute()) {
													IResource refRes;
													if (!newBasePath.isEmpty()) {
														refRes = cproject.getCModel().getWorkspace().getRoot().findMember(
																newBasePath);
													} else {
														IPath refResPath = refEntry.getPath();
														refRes = cproject.getCModel().getWorkspace().getRoot().findMember(
																refResPath);
													}
													if (refRes != null) {
														if (refRes.getType() == IResource.FILE) {
															refRes = refRes.getParent();
														}
														newBasePath = refRes.getLocation().append(newBasePath);
													}
												}

												return CoreModel.newLibraryEntry(entry.getPath(), newBasePath,
														refEntry.getLibraryPath(), refEntry.getSourceAttachmentPath(),
														refEntry.getSourceAttachmentRootPath(),
														refEntry.getSourceAttachmentPrefixMapping(), false);
											}
										}
									}
								}
							}
						}
					} else { // Container ref
						IPathEntryContainer container = manager.getPathEntryContainer(refPath, cproject);
						if (container != null) {
							IPathEntry[] entries = container.getPathEntries();
							for (IPathEntry pathEntry : entries) {
								if (pathEntry.getEntryKind() == IPathEntry.CDT_LIBRARY) {
									ILibraryEntry refEntry = (ILibraryEntry) pathEntry;
									if (refEntry.getPath().equals(libraryPath)) {
										return CoreModel.newLibraryEntry(entry.getPath(), refEntry.getBasePath(),
												refEntry.getLibraryPath(), refEntry.getSourceAttachmentPath(),
												refEntry.getSourceAttachmentRootPath(),
												refEntry.getSourceAttachmentPrefixMapping(), false);
									}
								}
							}
						}
					}
				}
				break;
			}

		}
		return entry;
	}

	public static IPathEntry cloneEntryAndExpand(IPath rpath, IPathEntry entry) {
		// Get the path
		IPath entryPath = entry.getPath();
		if (entryPath == null) {
			entryPath = Path.EMPTY;
		}
		IPath resourcePath = (entryPath.isAbsolute()) ? entryPath : rpath.append(entryPath);
	
		IPathEntryVariableManager varManager = CCorePlugin.getDefault().getPathEntryVariableManager();
		switch (entry.getEntryKind()) {
			case IPathEntry.CDT_INCLUDE: {
				IIncludeEntry include = (IIncludeEntry) entry;

				IPath basePath = include.getBasePath();
				basePath = varManager.resolvePath(basePath);

				IPath includePath = include.getIncludePath();
				includePath = varManager.resolvePath(includePath);
				
				return CoreModel.newIncludeEntry(resourcePath, basePath, includePath,
						include.isSystemInclude(), include.getExclusionPatterns(), include.isExported());
			}
			case IPathEntry.CDT_INCLUDE_FILE: {
				IIncludeFileEntry includeFile = (IIncludeFileEntry) entry;

				IPath basePath = includeFile.getBasePath();
				basePath = varManager.resolvePath(basePath);

				IPath includeFilePath = includeFile.getIncludeFilePath();
				includeFilePath = varManager.resolvePath(includeFilePath);
				
				return CoreModel.newIncludeFileEntry(resourcePath, basePath, Path.EMPTY, includeFilePath,
						includeFile.getExclusionPatterns(), includeFile.isExported());
			}
			case IPathEntry.CDT_LIBRARY: {
				ILibraryEntry library = (ILibraryEntry) entry;

				IPath basePath = library.getBasePath();
				basePath = varManager.resolvePath(basePath);

				IPath libraryPath = library.getLibraryPath();
				libraryPath = varManager.resolvePath(libraryPath);

				IPath sourceAttachmentPath = library.getSourceAttachmentPath();
				sourceAttachmentPath = varManager.resolvePath(sourceAttachmentPath);

				IPath sourceAttachmentRootPath = library.getSourceAttachmentRootPath();
				sourceAttachmentRootPath = varManager.resolvePath(sourceAttachmentRootPath);

				IPath sourceAttachmentPrefixMapping = library.getSourceAttachmentPrefixMapping();
				sourceAttachmentPrefixMapping = varManager.resolvePath(sourceAttachmentPrefixMapping);

				return CoreModel.newLibraryEntry(resourcePath, basePath, libraryPath,
						sourceAttachmentPath, sourceAttachmentRootPath,
						sourceAttachmentPrefixMapping, library.isExported());
			}
			case IPathEntry.CDT_MACRO: {
				IMacroEntry macro = (IMacroEntry) entry;
				return CoreModel.newMacroEntry(resourcePath, macro.getMacroName(), macro.getMacroValue(),
						macro.getExclusionPatterns(), macro.isExported());
			}
			case IPathEntry.CDT_MACRO_FILE: {
				IMacroFileEntry macroFile = (IMacroFileEntry) entry;

				IPath basePath = macroFile.getBasePath();
				basePath = varManager.resolvePath(basePath);

				IPath macroFilePath = macroFile.getMacroFilePath();
				macroFilePath = varManager.resolvePath(macroFilePath);
				
				return CoreModel.newMacroFileEntry(resourcePath, basePath, Path.EMPTY, macroFilePath,
						macroFile.getExclusionPatterns(), macroFile.isExported());
			}
			case IPathEntry.CDT_OUTPUT: {
				IOutputEntry out = (IOutputEntry) entry;
				return CoreModel.newOutputEntry(resourcePath, out.getExclusionPatterns());
			}
			case IPathEntry.CDT_PROJECT: {
				IProjectEntry projEntry = (IProjectEntry) entry;
				return CoreModel.newProjectEntry(projEntry.getPath(), projEntry.isExported());
			}
			case IPathEntry.CDT_SOURCE: {
				ISourceEntry source = (ISourceEntry) entry;
				return CoreModel.newSourceEntry(resourcePath, source.getExclusionPatterns());
			}
			case IPathEntry.CDT_CONTAINER: {
				return CoreModel.newContainerEntry(entry.getPath(), entry.isExported());
			}
		}
		return entry;
	}

	public static ICModelStatus validatePathEntry(ICProject cProject, IPathEntry[] entries) {
		// Check duplication.
		Set<IPathEntry> entrySet = new HashSet<IPathEntry>(entries.length);
		for (IPathEntry entry : entries) {
			if (entry != null) {
				if (entrySet.contains(entry)) {
					return new CModelStatus(ICModelStatusConstants.INVALID_PATHENTRY, 
							MessageFormat.format(CCorePlugin.getResourceString("CoreModel.PathEntry.DuplicateEntry"), //$NON-NLS-1$
									entry, entry.getPath()));
				} else {
					entrySet.add(entry);
				}
			}
		}

		// Check duplication of sources
		List<IPathEntry> dups = checkForDuplication(Arrays.asList(entries), IPathEntry.CDT_SOURCE);
		if (dups.size() > 0) {
			ICModelStatus[] cmodelStatus = new ICModelStatus[dups.size()];
			for (int i = 0; i < dups.size(); ++i) {
				StringBuffer errMesg = new StringBuffer(CCorePlugin.getResourceString("CoreModel.PathEntry.DuplicateEntry")); //$NON-NLS-1$
				cmodelStatus[i] = new CModelStatus(ICModelStatusConstants.INVALID_PATHENTRY, errMesg.toString());
			}
			return CModelStatus.newMultiStatus(ICModelStatusConstants.INVALID_PATHENTRY, cmodelStatus);
		}

		// Check duplication of outputs
		dups = checkForDuplication(Arrays.asList(entries), IPathEntry.CDT_OUTPUT);
		if (dups.size() > 0) {
			ICModelStatus[] cmodelStatus = new ICModelStatus[dups.size()];
			for (int i = 0; i < dups.size(); ++i) {
				StringBuffer errMesg = new StringBuffer(CCorePlugin.getResourceString("CoreModel.PathEntry.DuplicateEntry")); //$NON-NLS-1$
				cmodelStatus[i] = new CModelStatus(ICModelStatusConstants.NAME_COLLISION, errMesg.toString());
			}
			return CModelStatus.newMultiStatus(ICModelStatusConstants.INVALID_PATHENTRY, cmodelStatus);
		}

		// Allow nesting source entries in each other as long as the outer entry
		// excludes the inner one
		for (IPathEntry entry : entries) {
			if (entry == null) {
				continue;
			}
			IPath entryPath = entry.getPath();
			int kind = entry.getEntryKind();
			if (kind == IPathEntry.CDT_SOURCE) {
				for (IPathEntry otherEntry : entries) {
					if (otherEntry == null) {
						continue;
					}
					int otherKind = otherEntry.getEntryKind();
					IPath otherPath = otherEntry.getPath();
					if (entry != otherEntry && (otherKind == IPathEntry.CDT_SOURCE)) {
						char[][] exclusionPatterns = ((ISourceEntry)otherEntry).fullExclusionPatternChars();
						if (otherPath.isPrefixOf(entryPath) && !otherPath.equals(entryPath)
								&& !CoreModelUtil.isExcluded(entryPath.append("*"), exclusionPatterns)) { //$NON-NLS-1$

							if (CoreModelUtil.isExcluded(entryPath, exclusionPatterns)) {
								StringBuffer errMesg = new StringBuffer(
										CCorePlugin.getResourceString("CoreModel.PathEntry.NestedEntry")); //$NON-NLS-1$
								return new CModelStatus(ICModelStatusConstants.INVALID_PATHENTRY, errMesg.toString());
							} else if (otherKind == IPathEntry.CDT_SOURCE) {
								StringBuffer errMesg = new StringBuffer(
										CCorePlugin.getResourceString("CoreModel.PathEntry.NestedEntry")); //$NON-NLS-1$
								return new CModelStatus(ICModelStatusConstants.INVALID_PATHENTRY, errMesg.toString());
							} else {
								StringBuffer errMesg = new StringBuffer(
										CCorePlugin.getResourceString("CoreModel.PathEntry.NestedEntry")); //$NON-NLS-1$
								return new CModelStatus(ICModelStatusConstants.INVALID_PATHENTRY, errMesg.toString()); 
							}
						}
					}
				}
			}
		}

		return CModelStatus.VERIFIED_OK;
	}

	public static ICModelStatus validatePathEntry(ICProject cProject, IPathEntry entry, boolean checkSourceAttachment,
			boolean recurseInContainers) {
		IProject project = cProject.getProject();
		IPath path = entry.getPath();
		if (entry.getEntryKind() != IPathEntry.CDT_PROJECT &&
				entry.getEntryKind() != IPathEntry.CDT_CONTAINER
				&& entry.getEntryKind() != IPathEntry.CDT_OUTPUT) {
			if (!isValidWorkspacePath(project, path)) {
				return new CModelStatus(
						ICModelStatusConstants.INVALID_PATHENTRY,
						CoreModelMessages.getFormattedString("PathEntryManager.0", new Object[]{ path.toOSString(), ((PathEntry) entry).getKindString()})); //$NON-NLS-1$
			}
		}

		switch (entry.getEntryKind()) {
			case IPathEntry.CDT_INCLUDE: {
				if (VALIDATE_INCLUDE_ENTRIES) {
					IIncludeEntry include = (IIncludeEntry) entry;
					IPath includePath = include.getFullIncludePath();
					if (!isValidExternalPath(includePath)) {
						return new CModelStatus(ICModelStatusConstants.INVALID_PATHENTRY,
								CoreModelMessages.getFormattedString("PathEntryManager.2", includePath.toOSString())); //$NON-NLS-1$
					}
					if (!isValidBasePath(include.getBasePath())) {
						return new CModelStatus(ICModelStatusConstants.INVALID_PATHENTRY,
								CoreModelMessages.getFormattedString("PathEntryManager.1", includePath.toOSString()));  //$NON-NLS-1$
					}
				}
				break;
			}
			case IPathEntry.CDT_LIBRARY: {
				ILibraryEntry library = (ILibraryEntry) entry;
				if (checkSourceAttachment) {
					IPath sourceAttach = library.getSourceAttachmentPath();
					if (sourceAttach != null) {
						if (!sourceAttach.isAbsolute()) {
							if (!isValidWorkspacePath(project, sourceAttach) || !isValidExternalPath(sourceAttach)) {
								return new CModelStatus(ICModelStatusConstants.INVALID_PATHENTRY,
										CoreModelMessages.getFormattedString("PathEntryManager.3", sourceAttach.toOSString())); //$NON-NLS-1$
							}
						}
					}
				}
				IPath libraryPath = library.getFullLibraryPath();
				if (!isValidExternalPath(libraryPath)) {
					return new CModelStatus(ICModelStatusConstants.INVALID_PATHENTRY,
							CoreModelMessages.getFormattedString("PathEntryManager.4", libraryPath.toOSString())); //$NON-NLS-1$
				}
				if (!isValidBasePath(library.getBasePath())) {
					return new CModelStatus(ICModelStatusConstants.INVALID_PATHENTRY,
							CoreModelMessages.getFormattedString("PathEntryManager.7",libraryPath.toOSString()));  //$NON-NLS-1$
				}
				break;
			}
			case IPathEntry.CDT_PROJECT: {
				IProjectEntry projEntry = (IProjectEntry) entry;
				path = projEntry.getPath();
				IProject reqProject = project.getWorkspace().getRoot().getProject(path.segment(0));
				if (!reqProject.isAccessible()) {
					return new CModelStatus(ICModelStatusConstants.INVALID_PATHENTRY,
							CoreModelMessages.getString("PathEntryManager.5")); //$NON-NLS-1$
				}
				if (! (CoreModel.hasCNature(reqProject) || CoreModel.hasCCNature(reqProject))) {
					return new CModelStatus(ICModelStatusConstants.INVALID_PATHENTRY,
							CoreModelMessages.getString("PathEntryManager.6")); //$NON-NLS-1$
				}
				break;
			}
			case IPathEntry.CDT_CONTAINER:
				if (recurseInContainers) {
					try {
						IPathEntryContainer cont = manager.getPathEntryContainer((IContainerEntry) entry, cProject);
						IPathEntry[] contEntries = cont.getPathEntries();
						for (IPathEntry contEntrie : contEntries) {
							ICModelStatus status = validatePathEntry(cProject, contEntrie, checkSourceAttachment, false);
							if (!status.isOK()) {
								return status;
							}
						}
					} catch (CModelException e) {
						return new CModelStatus(e);
					}
				}
				break;
		}
		return CModelStatus.VERIFIED_OK;
	}

	private static boolean isValidWorkspacePath(IProject project, IPath path) {
		if (path == null) {
			return false;
		}
		IWorkspaceRoot workspaceRoot = project.getWorkspace().getRoot();
		// We accept empty path as the project
		IResource res = null;
		if (path.isAbsolute()) {
			res = workspaceRoot.findMember(path);
		} else {
			res = project.findMember(path);
		}
		return (res != null && res.isAccessible());
	}

	private static boolean isValidExternalPath(IPath path) {
		if (path != null) {
			if (path.isUNC()) {
				return true;
			}
			File file = path.toFile();
			if (file != null) {
				return file.exists();
			}
		}
		return false;
	}

	private static boolean isValidBasePath(IPath path) {
		if (!path.isEmpty() && !path.isAbsolute()) {
			IResource res = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
			if (res == null || !res.isAccessible()) {
				return false;
			}
		}
		return true;
	}

	public static List<IPathEntry> checkForDuplication(List<IPathEntry> pathEntries, int type) {
		List<IPathEntry> duplicate = new ArrayList<IPathEntry>(pathEntries.size());
		for (int i = 0; i < pathEntries.size(); ++i) {
			IPathEntry pathEntry = pathEntries.get(i);
			if (pathEntry.getEntryKind() == type) {
				for (int j = 0; j < pathEntries.size(); ++j) {
					IPathEntry otherEntry = pathEntries.get(j);
					if (otherEntry.getEntryKind() == type) {
						if (!pathEntry.equals(otherEntry)) {
							if (!duplicate.contains(pathEntry)) {
								if (pathEntry.getPath().equals(otherEntry.getPath())) {
									// duplication of sources
									duplicate.add(otherEntry);
								}
							}
						}
					}
				}
			}
		}
		return duplicate;
	}

	/**
	 * Record a new marker denoting a path entry problem
	 */
	public static void createPathEntryProblemMarker(IProject project, ICModelStatus status) {
		int severity = code2Severity(status);
		try {
			IMarker marker = project.createMarker(ICModelMarker.PATHENTRY_PROBLEM_MARKER);
			marker.setAttributes(new String[]{IMarker.MESSAGE, IMarker.SEVERITY, IMarker.LOCATION,
					ICModelMarker.PATHENTRY_FILE_FORMAT,}, new Object[]{status.getMessage(), new Integer(severity), "pathentry",//$NON-NLS-1$
					"false",//$NON-NLS-1$
			});
		} catch (CoreException e) {
			// could not create marker: cannot do much
			//e.printStackTrace();
		}
	}

	/**
	 * Remove all markers denoting path entry problems
	 */
	public static void flushPathEntryProblemMarkers(IProject project) {
		IWorkspace workspace = project.getWorkspace();

		try {
			IMarker[] markers = getPathEntryProblemMarkers(project);
			workspace.deleteMarkers(markers);
		} catch (CoreException e) {
			// could not flush markers: not much we can do
			//e.printStackTrace();
		}
	}

	/**
	 * get all markers denoting path entry problems
	 */
	public static IMarker[] getPathEntryProblemMarkers(IProject project) {

		try {
			IMarker[] markers = project.findMarkers(ICModelMarker.PATHENTRY_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
			if (markers != null) {
				return markers;
			}
		} catch (CoreException e) {
			//e.printStackTrace();
		}
		return NO_MARKERS;
	}

	public static boolean hasPathEntryProblemMarkersChange(IProject project, ICModelStatus[] status) {
		IMarker[] markers = getPathEntryProblemMarkers(project);
		if (markers.length != status.length) {
			return true;
		}
		for (int i = 0; i < markers.length; ++i) {
			boolean found = false;
			String message = markers[i].getAttribute(IMarker.MESSAGE, ""); //$NON-NLS-1$
			int severity = markers[i].getAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
			for (int j = 0; j < status.length; ++j) {
				String msg = status[j].getMessage();
				int cseverity = code2Severity(status[j]);
				if (msg.equals(message) && severity == cseverity) {
					found = true;
				}
			}
			if (!found) {
				return true;
			}
		}
		return false;
	}

	public static int code2Severity(ICModelStatus status) {
		int severity;
		switch (status.getCode()) {
			case ICModelStatusConstants.INVALID_PATHENTRY:
				severity = IMarker.SEVERITY_WARNING;
				break;

			case ICModelStatusConstants.INVALID_PATH:
				severity = IMarker.SEVERITY_WARNING;
				break;

			default:
				severity = IMarker.SEVERITY_ERROR;
				break;
		}

		return severity;
	}
}
