/*******************************************************************************
 * Copyright (c) 2005, 2014 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.jdt.jeview.properties;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;

import org.eclipse.core.runtime.jobs.ISchedulingRule;

import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertySource;
import org.eclipse.ui.views.properties.PropertyDescriptor;

import org.eclipse.jdt.core.BindingKey;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IImportDeclaration;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.ILocalVariable;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IOpenable;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IParent;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;

import org.eclipse.jdt.jeview.JEViewPlugin;

public class JavaElementProperties implements IPropertySource {

	private static HashMap<String, Property> fgIdToProperty= new HashMap<>();
	private static LinkedHashMap<Class<?>, List<Property>> fgTypeToProperty= new LinkedHashMap<>();


	private static abstract class Property {
		private final Class<?> fType;
		private final String fName;
		private final String fId;
		private final PropertyDescriptor fDescriptor;

		public Property(Class<?> type, String name) {
			fType= type;
			fName= name;
			fId= "org.eclipse.jdt.jeview." + type.getSimpleName() + "." + name;
			fDescriptor= new PropertyDescriptor(fId, fName);
			fDescriptor.setAlwaysIncompatible(true);
			fDescriptor.setCategory(type.getSimpleName());
		}

		public abstract Object compute(IJavaElement javaElement) throws JavaModelException;


		public Class<?> getType() {
			return fType;
		}


		public String getName() {
			return fName;
		}

		public String getId() {
			return fId;
		}

		public PropertyDescriptor getDescriptor() {
			return fDescriptor;
		}

	}

	static {
		addJavaElementProperties();
		addClassFileProperties();
		addCompilationUnitProperties();
		addImportDeclarationProperties();
		addJavaProjectProperties();
		addLocalVariableProperties();
		addMemberProperties();
		addFieldProperties();
		addMethodProperties();
		addTypeProperties();
		addAnnotationProperties();
		addPackageFragmentProperties();
		addPackageFragmentRootProperties();
		addParentProperties();
		addSourceReferenceProperties();
		addOpenableProperties();
	}

	private static void addJavaElementProperties() {
		addProperty(new Property(IJavaElement.class, "elementName") {
			@Override public Object compute(IJavaElement element) {
				return element.getElementName();
			}
		});
		addProperty(new Property(IJavaElement.class, "elementType") {
			@Override public Object compute(IJavaElement element) {
				return getElementTypeString(element.getElementType());
			}
		});
		addProperty(new Property(IJavaElement.class, "exists") {
			@Override public Object compute(IJavaElement element) {
				return element.exists();
			}
		});
		addProperty(new Property(IJavaElement.class, "isReadOnly") {
			@Override public Object compute(IJavaElement element) {
				return element.isReadOnly();
			}
		});
		addProperty(new Property(IJavaElement.class, "isStructureKnown") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return element.isStructureKnown();
			}
		});
		addProperty(new Property(IJavaElement.class, "handleIdentifier") {
			@Override public Object compute(IJavaElement element) {
				return element.getHandleIdentifier();
			}
		});
		addProperty(new Property(IJavaElement.class, "path") {
			@Override public Object compute(IJavaElement element) {
				return element.getPath();
			}
		});
		addProperty(new Property(IJavaElement.class, "schedulingRule") {
			@Override public Object compute(IJavaElement element) {
				return getSchedulingRuleString(element.getSchedulingRule());
			}
		});
		addProperty(new Property(IJavaElement.class, "| IJavaProject#isOnClasspath(this)") {
			@Override public Object compute(IJavaElement element) {
				IJavaProject javaProject = element.getJavaProject();
				return javaProject == null ? null : javaProject.isOnClasspath(element);
			}
		});
	}

	private static void addClassFileProperties() {
		addProperty(new Property(IClassFile.class, "isClass") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IClassFile) element).isClass();
			}
		});
		addProperty(new Property(IClassFile.class, "isInterface") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IClassFile) element).isInterface();
			}
		});
	}

	private static void addCompilationUnitProperties() {
		addProperty(new Property(ICompilationUnit.class, "hasResourceChanged") {
			@Override public Object compute(IJavaElement element) {
				return ((ICompilationUnit) element).hasResourceChanged();
			}
		});
		addProperty(new Property(ICompilationUnit.class, "isWorkingCopy") {
			@Override public Object compute(IJavaElement element) {
				return ((ICompilationUnit) element).isWorkingCopy();
			}
		});
	}

	private static void addImportDeclarationProperties() {
		addProperty(new Property(IImportDeclaration.class, "flags") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return getFlagsString(((IImportDeclaration) element).getFlags(), IImportDeclaration.class);
			}
		});
		addProperty(new Property(IImportDeclaration.class, "isOnDemand") {
			@Override public Object compute(IJavaElement element) {
				return ((IImportDeclaration) element).isOnDemand();
			}
		});
	}

	private static void addJavaProjectProperties() {
		addProperty(new Property(IJavaProject.class, "hasBuildState") {
			@Override public Object compute(IJavaElement element) {
				return ((IJavaProject) element).hasBuildState();
			}
		});
		addProperty(new Property(IJavaProject.class, "getOutputLocation") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IJavaProject) element).getOutputLocation();
			}
		});
		addProperty(new Property(IJavaProject.class, "readOutputLocation") {
			@Override public Object compute(IJavaElement element) {
				return ((IJavaProject) element).readOutputLocation();
			}
		});
	}

	private static void addLocalVariableProperties() {
		addProperty(new Property(ILocalVariable.class, "typeSignature") {
			@Override public Object compute(IJavaElement element) {
				return ((ILocalVariable) element).getTypeSignature();
			}
		});
		addProperty(new Property(ILocalVariable.class, "flags") {
			@Override public Object compute(IJavaElement element) {
				return getFlagsString(((ILocalVariable) element).getFlags(), element.getClass());
			}
		});
		addProperty(new Property(ILocalVariable.class, "isParameter") {
			@Override public Object compute(IJavaElement element) {
				return ((ILocalVariable) element).isParameter();
			}
		});
	}

	private static void addAnnotationProperties() {
		addProperty(new Property(IAnnotation.class, "occurrenceCount") {
			@Override public Object compute(IJavaElement element) {
				return ((IAnnotation) element).getOccurrenceCount();
			}
		});
	}

	private static void addMemberProperties() {
		addProperty(new Property(IMember.class, "javadocRange") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return getSourceRangeString(((IMember) element).getJavadocRange());
			}
		});
		addProperty(new Property(IMember.class, "flags") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return getFlagsString(((IMember) element).getFlags(), element.getClass());
			}
		});
		addProperty(new Property(IMember.class, "isBinary") {
			@Override public Object compute(IJavaElement element) {
				return ((IMember) element).isBinary();
			}
		});
		addProperty(new Property(IMember.class, "occurrenceCount") {
			@Override public Object compute(IJavaElement element) {
				return ((IMember) element).getOccurrenceCount();
			}
		});
	}

	private static void addFieldProperties() {
		addProperty(new Property(IField.class, "isResolved") {
			@Override public Object compute(IJavaElement element) {
				return ((IField) element).isResolved();
			}
		});
		addProperty(new Property(IField.class, "key") {
			@Override public Object compute(IJavaElement element) {
				return ((IField) element).getKey();
			}
		});
		addProperty(new Property(IField.class, "typeSignature") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IField) element).getTypeSignature();
			}
		});
		addProperty(new Property(IField.class, "constant") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IField) element).getConstant();
			}
		});
		addProperty(new Property(IField.class, "isEnumConstant") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IField) element).isEnumConstant();
			}
		});
	}

	private static void addMethodProperties() {
		addProperty(new Property(IMethod.class, "isResolved") {
			@Override public Object compute(IJavaElement element) {
				return ((IMethod) element).isResolved();
			}
		});
		addProperty(new Property(IMethod.class, "key") {
			@Override public Object compute(IJavaElement element) {
				return ((IMethod) element).getKey();
			}
		});
		addProperty(new Property(IMethod.class, "key - signature") {
			@Override public Object compute(IJavaElement element) {
				String key= ((IMethod) element).getKey();
				if (key != null)
					return new BindingKey(key).toSignature();
				else
					return "<no key>";
			}
		});
		addProperty(new Property(IMethod.class, "numberOfParameters") {
			@Override public Object compute(IJavaElement element) {
				return ((IMethod) element).getNumberOfParameters();
			}
		});
		addProperty(new Property(IMethod.class, "signature") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IMethod) element).getSignature();
			}
		});
		addProperty(new Property(IMethod.class, "returnType") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IMethod) element).getReturnType();
			}
		});
		addProperty(new Property(IMethod.class, "isConstructor") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IMethod) element).isConstructor();
			}
		});
		addProperty(new Property(IMethod.class, "isMainMethod") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IMethod) element).isMainMethod();
			}
		});
		addProperty(new Property(IMethod.class, "isLambdaMethod") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IMethod) element).isLambdaMethod();
			}
		});
	}

	private static void addTypeProperties() {
		addProperty(new Property(IType.class, "isResolved") {
			@Override public Object compute(IJavaElement element) {
				return ((IType) element).isResolved();
			}
		});
		addProperty(new Property(IType.class, "key") {
			@Override public Object compute(IJavaElement element) {
				return ((IType) element).getKey();
			}
		});
		addProperty(new Property(IType.class, "fullyQualifiedName") {
			@Override public Object compute(IJavaElement element) {
				return ((IType) element).getFullyQualifiedName();
			}
		});
		addProperty(new Property(IType.class, "fullyQualifiedName('*')") {
			@Override public Object compute(IJavaElement element) {
				return ((IType) element).getFullyQualifiedName('*');
			}
		});
		addProperty(new Property(IType.class, "fullyQualifiedParameterizedName") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IType) element).getFullyQualifiedParameterizedName();
			}
		});
		addProperty(new Property(IType.class, "typeQualifiedName") {
			@Override public Object compute(IJavaElement element) {
				return ((IType) element).getTypeQualifiedName();
			}
		});
		addProperty(new Property(IType.class, "typeQualifiedName('*')") {
			@Override public Object compute(IJavaElement element) {
				return ((IType) element).getTypeQualifiedName('*');
			}
		});
		addProperty(new Property(IType.class, "isAnnotation") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IType) element).isAnnotation();
			}
		});
		addProperty(new Property(IType.class, "isClass") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IType) element).isClass();
			}
		});
		addProperty(new Property(IType.class, "isEnum") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IType) element).isEnum();
			}
		});
		addProperty(new Property(IType.class, "isInterface") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IType) element).isInterface();
			}
		});
		addProperty(new Property(IType.class, "isAnonymous") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IType) element).isAnonymous();
			}
		});
		addProperty(new Property(IType.class, "isLocal") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IType) element).isLocal();
			}
		});
		addProperty(new Property(IType.class, "isMember") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IType) element).isMember();
			}
		});
		addProperty(new Property(IType.class, "isLambda") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IType) element).isLambda();
			}
		});
	}

	private static void addPackageFragmentProperties() {
		addProperty(new Property(IPackageFragment.class, "containsJavaResources") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IPackageFragment) element).containsJavaResources();
			}
		});
		addProperty(new Property(IPackageFragment.class, "kind") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return getPFRKindString(((IPackageFragment) element).getKind());
			}
		});
		addProperty(new Property(IPackageFragment.class, "hasSubpackages") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IPackageFragment) element).hasSubpackages();
			}
		});
		addProperty(new Property(IPackageFragment.class, "isDefaultPackage") {
			@Override public Object compute(IJavaElement element) {
				return ((IPackageFragment) element).isDefaultPackage();
			}
		});
	}

	private static void addPackageFragmentRootProperties() {
		addProperty(new Property(IPackageFragmentRoot.class, "kind") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return getPFRKindString(((IPackageFragmentRoot) element).getKind());
			}
		});
		addProperty(new Property(IPackageFragmentRoot.class, "sourceAttachmentPath") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IPackageFragmentRoot) element).getSourceAttachmentPath();
			}
		});
		addProperty(new Property(IPackageFragmentRoot.class, "sourceAttachmentRootPath") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IPackageFragmentRoot) element).getSourceAttachmentRootPath();
			}
		});
		addProperty(new Property(IPackageFragmentRoot.class, "isArchive") {
			@Override public Object compute(IJavaElement element) {
				return ((IPackageFragmentRoot) element).isArchive();
			}
		});
		addProperty(new Property(IPackageFragmentRoot.class, "isExternal") {
			@Override public Object compute(IJavaElement element) {
				return ((IPackageFragmentRoot) element).isExternal();
			}
		});
	}

	private static void addParentProperties() {
		addProperty(new Property(IParent.class, "hasChildren") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IParent) element).hasChildren();
			}
		});
	}

	private static void addSourceReferenceProperties() {
		addProperty(new Property(ISourceReference.class, "sourceRange") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return getSourceRangeString(((ISourceReference) element).getSourceRange());
			}
		});
		addProperty(new Property(ISourceReference.class, "nameRange") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return getSourceRangeString(((ISourceReference) element).getNameRange());
			}
		});
	}

	private static void addOpenableProperties() {
		addProperty(new Property(IOpenable.class, "hasUnsavedChanges") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IOpenable) element).hasUnsavedChanges();
			}
		});
		addProperty(new Property(IOpenable.class, "isConsistent") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				return ((IOpenable) element).isConsistent();
			}
		});
		addProperty(new Property(IOpenable.class, "isOpen") {
			@Override public Object compute(IJavaElement element) {
				return ((IOpenable) element).isOpen();
			}
		});
		addProperty(new Property(IOpenable.class, "findRecommendedLineSeparator") {
			@Override public Object compute(IJavaElement element) throws JavaModelException {
				String lineSeparator= ((IOpenable) element).findRecommendedLineSeparator();
				lineSeparator= lineSeparator.replace("\r", "\\r").replace("\n", "\\n");
				return lineSeparator;
			}
		});
	}

	private static void addProperty(Property property) {
		fgIdToProperty.put(property.getId(), property);
		List<Property> properties= fgTypeToProperty.get(property.getType());
		if (properties == null) {
			properties= new ArrayList<>();
			fgTypeToProperty.put(property.getType(), properties);
		}
		properties.add(property);
	}

	protected IJavaElement fJavaElement;

	public JavaElementProperties(IJavaElement javaElement) {
		fJavaElement= javaElement;
	}

	@Override
	public IPropertyDescriptor[] getPropertyDescriptors() {
		List<IPropertyDescriptor> result= new ArrayList<>();
		for (Entry<Class<?>, List<Property>> entry : fgTypeToProperty.entrySet()) {
			if (entry.getKey().isAssignableFrom(fJavaElement.getClass())) {
				for (Property property : entry.getValue()) {
					result.add(property.getDescriptor());
				}
			}
		}
		return result.toArray(new IPropertyDescriptor[result.size()]);
	}

	@Override
	public Object getPropertyValue(Object id) {
		Property property= fgIdToProperty.get(id);
		if (property == null) {
			return null;
		} else {
			try {
				return property.compute(fJavaElement);
			} catch (JavaModelException e) {
				if (e.isDoesNotExist()) {
					return "JavaModelException: " + e.getLocalizedMessage();
				} else {
					JEViewPlugin.log("error calculating property '" + property.getType().getSimpleName() + '#' + property.getName() + '\'', e);
					return "Error: " + e.getLocalizedMessage();
				}
			}
		}
	}

	static String getElementTypeString(int elementType) {
		String name;
		switch (elementType) {
			case IJavaElement.JAVA_MODEL :
				name= "IJavaModel";
				break;
			case IJavaElement.JAVA_PROJECT :
				name= "IJavaProject";
				break;
			case IJavaElement.PACKAGE_FRAGMENT_ROOT :
				name= "IPackageFragmentRoot";
				break;
			case IJavaElement.PACKAGE_FRAGMENT :
				name= "IPackageFragment";
				break;
			case IJavaElement.COMPILATION_UNIT :
				name= "ICompilationUnit";
				break;
			case IJavaElement.CLASS_FILE :
				name= "IClassFile";
				break;
			case IJavaElement.TYPE :
				name= "IType";
				break;
			case IJavaElement.FIELD :
				name= "IField";
				break;
			case IJavaElement.METHOD :
				name= "IMethod";
				break;
			case IJavaElement.INITIALIZER :
				name= "IInitializer";
				break;
			case IJavaElement.PACKAGE_DECLARATION :
				name= "IPackageDeclaration";
				break;
			case IJavaElement.IMPORT_CONTAINER :
				name= "IImportContainer";
				break;
			case IJavaElement.IMPORT_DECLARATION :
				name= "IImportDeclaration";
				break;
			case IJavaElement.LOCAL_VARIABLE :
				name= "ILocalVariable";
				break;
			case IJavaElement.TYPE_PARAMETER :
				name= "ITypeParameter";
				break;
			case IJavaElement.ANNOTATION :
				name= "IAnnotation";
				break;
			default :
				name= "UNKNOWN";
				break;
		}
		return elementType + " (" + name + ")";
	}

	static String getSourceRangeString(ISourceRange range) {
		return range == null ? "null" : range.getOffset() + " + " + range.getLength();
	}

	static String getFlagsString(int flags, Class<? extends IJavaElement> clazz) {
		StringBuffer sb = new StringBuffer().append("0x").append(Integer.toHexString(flags)).append(" (");
		int prologLen= sb.length();
		int rest= flags;

		rest&= ~ appendFlag(sb, flags, Flags.AccPublic, "public ");
		rest&= ~ appendFlag(sb, flags, Flags.AccPrivate, "private ");
		rest&= ~ appendFlag(sb, flags, Flags.AccProtected, "protected ");
		rest&= ~ appendFlag(sb, flags, Flags.AccStatic, "static ");
		rest&= ~ appendFlag(sb, flags, Flags.AccFinal, "final ");
		boolean isMethod = IMethod.class.isAssignableFrom(clazz);
		if (isMethod) {
			rest&= ~ appendFlag(sb, flags, Flags.AccSynchronized, "synchronized ");
			rest&= ~ appendFlag(sb, flags, Flags.AccBridge, "bridge ");
			rest&= ~ appendFlag(sb, flags, Flags.AccVarargs, "varargs ");
			rest&= ~ appendFlag(sb, flags, Flags.AccDefaultMethod, "default(method) ");
		} else {
			rest&= ~ appendFlag(sb, flags, Flags.AccSuper, "super ");
			rest&= ~ appendFlag(sb, flags, Flags.AccVolatile, "volatile ");
			rest&= ~ appendFlag(sb, flags, Flags.AccTransient, "transient ");
		}
		rest&= ~ appendFlag(sb, flags, Flags.AccNative, "native ");
		rest&= ~ appendFlag(sb, flags, Flags.AccInterface, "interface ");
		rest&= ~ appendFlag(sb, flags, Flags.AccAbstract, "abstract ");
		rest&= ~ appendFlag(sb, flags, Flags.AccStrictfp, "strictfp ");
		rest&= ~ appendFlag(sb, flags, Flags.AccSynthetic, "synthetic ");
		rest&= ~ appendFlag(sb, flags, Flags.AccAnnotation, "annotation ");
		rest&= ~ appendFlag(sb, flags, Flags.AccEnum, "enum ");
		rest&= ~ appendFlag(sb, flags, Flags.AccDeprecated, "deprecated ");
		if (isMethod) {
			rest&= ~ appendFlag(sb, flags, Flags.AccAnnotationDefault, "default(annotation) ");
		}

		if (rest != 0)
			sb.append("unknown:0x").append(Integer.toHexString(rest)).append(" ");
		int len = sb.length();
		if (len != prologLen)
			sb.setLength(len - 1);
		sb.append(")");
		return sb.toString();
	}

	private static int appendFlag(StringBuffer sb, int flags, int flag, String name) {
		if ((flags & flag) != 0) {
			sb.append(name);
			return flag;
		} else {
			return 0;
		}
	}

	static String getPFRKindString(int kind) {
		StringBuffer sb = new StringBuffer().append("0x").append(Integer.toHexString(kind)).append(" (");
		int prologLen= sb.length();
		int rest= kind;

		rest&= ~ appendFlag(sb, kind, IPackageFragmentRoot.K_BINARY, "binary ");
		rest&= ~ appendFlag(sb, kind, IPackageFragmentRoot.K_SOURCE, "source ");

		if (rest != 0)
			sb.append("unknown:0x").append(Integer.toHexString(rest));
		int len = sb.length();
		if (len != prologLen)
			sb.setLength(len - 1);
		sb.append(")");
		return sb.toString();
	}

	static String getSchedulingRuleString(ISchedulingRule schedulingRule) {
		if (schedulingRule == null)
			return null;
		else
			return schedulingRule.getClass().getSimpleName() + ": " + schedulingRule.toString();
	}

	@Override
	public void setPropertyValue(Object name, Object value) {
		// do nothing
	}

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

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

	@Override
	public void resetPropertyValue(Object property) {
		// do nothing
	}
}
