/*******************************************************************************
 * Copyright (c) 2000, 2015 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.ui.views.properties;

import java.io.File;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourceAttributes;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.viewers.IBasicPropertyConstants;
import org.eclipse.osgi.util.TextProcessor;
import org.eclipse.ui.internal.ide.dialogs.IDEResourceInfoUtils;
import org.eclipse.ui.internal.views.properties.IDEPropertiesMessages;

/**
 * A Resource property source.
 */
public class ResourcePropertySource implements IPropertySource {
	protected static String NOT_LOCAL_TEXT = IDEPropertiesMessages.PropertySource_notLocal;

	protected static String FILE_NOT_FOUND = IDEPropertiesMessages.PropertySource_notFound;

	protected static String UNDEFINED_PATH_VARIABLE = IDEPropertiesMessages.PropertySource_undefinedPathVariable;

	protected static String FILE_NOT_EXIST_TEXT = IDEPropertiesMessages.PropertySource_fileNotExist;

	// The element for the property source
	protected IResource element;

	// Error message when setting a property incorrectly
	protected String errorMessage = IDEPropertiesMessages.PropertySource_readOnly;

	// Property Descriptors
	static protected IPropertyDescriptor[] propertyDescriptors = new IPropertyDescriptor[7];

	static protected IPropertyDescriptor[] propertyDescriptorsLinkVariable = new IPropertyDescriptor[8];
	static {
		PropertyDescriptor descriptor;

		// resource name
		descriptor = new PropertyDescriptor(IBasicPropertyConstants.P_TEXT,
				IResourcePropertyConstants.P_LABEL_RES);
		descriptor.setAlwaysIncompatible(true);
		descriptor
				.setCategory(IResourcePropertyConstants.P_FILE_SYSTEM_CATEGORY);
		propertyDescriptors[0] = descriptor;
		propertyDescriptorsLinkVariable[0] = descriptor;

		// Relative path
		descriptor = new PropertyDescriptor(
				IResourcePropertyConstants.P_PATH_RES,
				IResourcePropertyConstants.P_DISPLAYPATH_RES);
		descriptor.setAlwaysIncompatible(true);
		descriptor
				.setCategory(IResourcePropertyConstants.P_FILE_SYSTEM_CATEGORY);
		propertyDescriptors[1] = descriptor;
		propertyDescriptorsLinkVariable[1] = descriptor;

		// readwrite state
		descriptor = new PropertyDescriptor(
				IResourcePropertyConstants.P_EDITABLE_RES,
				IResourcePropertyConstants.P_DISPLAYEDITABLE_RES);
		descriptor.setAlwaysIncompatible(true);
		descriptor
				.setCategory(IResourcePropertyConstants.P_FILE_SYSTEM_CATEGORY);
		propertyDescriptors[2] = descriptor;
		propertyDescriptorsLinkVariable[2] = descriptor;

		// derived state
		descriptor = new PropertyDescriptor(
				IResourcePropertyConstants.P_DERIVED_RES,
				IResourcePropertyConstants.P_DISPLAYDERIVED_RES);
		descriptor.setAlwaysIncompatible(true);
		descriptor
				.setCategory(IResourcePropertyConstants.P_FILE_SYSTEM_CATEGORY);
		propertyDescriptors[3] = descriptor;
		propertyDescriptorsLinkVariable[3] = descriptor;

		// last modified state
		descriptor = new PropertyDescriptor(
				IResourcePropertyConstants.P_LAST_MODIFIED_RES,
				IResourcePropertyConstants.P_DISPLAY_LAST_MODIFIED);
		descriptor.setAlwaysIncompatible(true);
		descriptor
				.setCategory(IResourcePropertyConstants.P_FILE_SYSTEM_CATEGORY);
		propertyDescriptors[4] = descriptor;
		propertyDescriptorsLinkVariable[4] = descriptor;

		// link state
		descriptor = new PropertyDescriptor(
				IResourcePropertyConstants.P_LINKED_RES,
				IResourcePropertyConstants.P_DISPLAYLINKED_RES);
		descriptor.setAlwaysIncompatible(true);
		descriptor
				.setCategory(IResourcePropertyConstants.P_FILE_SYSTEM_CATEGORY);
		propertyDescriptors[5] = descriptor;
		propertyDescriptorsLinkVariable[5] = descriptor;

		// location
		descriptor = new PropertyDescriptor(
				IResourcePropertyConstants.P_LOCATION_RES,
				IResourcePropertyConstants.P_DISPLAYLOCATION_RES);
		descriptor.setAlwaysIncompatible(true);
		descriptor
				.setCategory(IResourcePropertyConstants.P_FILE_SYSTEM_CATEGORY);
		propertyDescriptors[6] = descriptor;
		propertyDescriptorsLinkVariable[6] = descriptor;

		// resolved location
		descriptor = new PropertyDescriptor(
				IResourcePropertyConstants.P_RESOLVED_LOCATION_RES,
				IResourcePropertyConstants.P_DISPLAYRESOLVED_LOCATION_RES);
		descriptor.setAlwaysIncompatible(true);
		descriptor
				.setCategory(IResourcePropertyConstants.P_FILE_SYSTEM_CATEGORY);
		propertyDescriptorsLinkVariable[7] = descriptor;

	}

	/**
	 * Creates a PropertySource and stores its IResource
	 *
	 * @param res the resource for which this is a property source
	 */
	public ResourcePropertySource(IResource res) {
		Assert.isNotNull(res);
		this.element = res;
	}

	@Override
	public Object getEditableValue() {
		return this;
	}

	@Override
	public IPropertyDescriptor[] getPropertyDescriptors() {
		if (isPathVariable(element)) {
			return propertyDescriptorsLinkVariable;
		}
		return propertyDescriptors;
	}

	@Override
	public Object getPropertyValue(Object name) {
		if (name.equals(IBasicPropertyConstants.P_TEXT)) {
			return element.getName();
		}
		if (name.equals(IResourcePropertyConstants.P_PATH_RES)) {
			return TextProcessor.process(element.getFullPath().toString());
		}
		if (name.equals(IResourcePropertyConstants.P_LAST_MODIFIED_RES)) {
			return IDEResourceInfoUtils.getDateStringValue(element);
		}
		if (name.equals(IResourcePropertyConstants.P_EDITABLE_RES)) {
			final ResourceAttributes attributes = element.getResourceAttributes();
			if (attributes == null || attributes.isReadOnly()) {
				return IDEPropertiesMessages.ResourceProperty_false;
			}
			return IDEPropertiesMessages.ResourceProperty_true;
		}
		if (name.equals(IResourcePropertyConstants.P_DERIVED_RES)) {
			if (element.isDerived())
				return IDEPropertiesMessages.ResourceProperty_true;
			return IDEPropertiesMessages.ResourceProperty_false;
		}
		if (name.equals(IResourcePropertyConstants.P_LINKED_RES)) {
			if (element.isLinked())
				return IDEPropertiesMessages.ResourceProperty_true;
			return IDEPropertiesMessages.ResourceProperty_false;
		}
		if (name.equals(IResourcePropertyConstants.P_LOCATION_RES)) {
			return TextProcessor.process(IDEResourceInfoUtils.getLocationText(element));
		}
		if (name.equals(IResourcePropertyConstants.P_RESOLVED_LOCATION_RES)) {
			return TextProcessor.process(IDEResourceInfoUtils.getResolvedLocationText(element));
		}
		return null;
	}

	/**
	 * Returns whether the given resource is a linked resource bound
	 * to a path variable.
	 *
	 * @param resource resource to test
	 * @return boolean <code>true</code> the given resource is a linked
	 * 	resource bound to a path variable. <code>false</code> the given
	 * 	resource is either not a linked resource or it is not using a
	 * 	path variable.
	 */
	private boolean isPathVariable(IResource resource) {
		if (!resource.isLinked()) {
			return false;
		}

		IPath resolvedLocation = resource.getLocation();
		if (resolvedLocation == null) {
			// missing path variable
			return true;
		}
		IPath rawLocation = resource.getRawLocation();
		if (resolvedLocation.equals(rawLocation)) {
			return false;
		}

		return true;
	}

	@Override
	public boolean isPropertySet(Object property) {
		return false;
	}

	/**
	 * The <code>ResourcePropertySource</code> implementation of this
	 * <code>IPropertySource</code> method does nothing since all
	 * properties are read-only.
	 */
	@Override
	public void resetPropertyValue(Object property) {
	}

	/**
	 * The <code>ResourcePropertySource</code> implementation of this
	 * <code>IPropertySource</code> method does nothing since all
	 * properties are read-only.
	 */
	@Override
	public void setPropertyValue(Object name, Object value) {
	}

	/**
	 * Get the java.io.File equivalent of the passed
	 * IFile. If the location does not exist then return
	 * <code>null</code>
	 * @param resource the resource to lookup
	 * @return java.io.File or <code>null</code>.
	 */
	protected File getFile(IResource resource) {
		IPath location = resource.getLocation();
		if (location == null) {
			return null;
		}
		return location.toFile();
	}

}
