/*******************************************************************************
 * Copyright (c) 2005, 2012 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.views;

import java.util.ArrayList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.Callable;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.QualifiedName;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;

import org.eclipse.jdt.core.JavaCore;


public class JEResource extends JEAttribute {

	private final JEAttribute fParent; // can be null
	private final String fName; // can be null
	private IResource fResource;

	JEResource(JEAttribute parent, String name, IResource resource) {
		Assert.isNotNull(resource);
		fParent= parent;
		fName= name;
		fResource= resource;
	}

	@Override
	public JEAttribute getParent() {
		return fParent;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null || !obj.getClass().equals(getClass())) {
			return false;
		}

		JEResource other= (JEResource) obj;
		if (!Objects.equals(fParent, other.fParent)) {
			return false;
		}

		if (!Objects.equals(fName, other.fName)) {
			return false;
		}

		return true;
	}

	@Override
	public int hashCode() {
		return (fParent != null ? fParent.hashCode() : 0)
				+ (fName != null ? fName.hashCode() : 0)
				+ fResource.hashCode();
	}

	@Override
	public Object getWrappedObject() {
		return fResource;
	}

	public IResource getResource() {
		return fResource;
	}

	@Override
	public JEAttribute[] getChildren() {
		ArrayList<JEAttribute> result= new ArrayList<>();

		IContainer parent= fResource.getParent();
		if (parent != null )
			result.add(new JEResource(this, "PARENT", parent));
		else
			result.add(new JavaElementProperty(this, "PARENT", parent));

		result.add(new JavaElement(this, "JavaCore.create(..)", JavaCore.create(fResource)));

		if (fResource instanceof IContainer) {
			final IContainer container= (IContainer) fResource;
//			result.add(new JavaElementProperty(this, "ModificationStamp") {
//				@Override protected Object computeValue() throws CoreException {
//					return container.getDefaultCharset();
//				}
//			});
			result.add(new JavaElementChildrenProperty(this, "MEMBERS") {
				@Override protected JEAttribute[] computeChildren() throws CoreException {
					IResource[] resources= container.members();
					JEAttribute[] children= new JEAttribute[resources.length];
					for (int i= 0; i < resources.length; i++) {
						children[i]= new JEResource(this, null, resources[i]);
					}
					return children;
				}
			});
		}
		result.add(new JavaElementChildrenProperty(this, "FIND MARKERS (DEPTH_ZERO)") {
			@Override protected JEAttribute[] computeChildren() throws CoreException {
				IMarker[] markers= getResource().findMarkers(null, true, IResource.DEPTH_ZERO);
				JEAttribute[] children= new JEAttribute[markers.length];
				for (int i= 0; i < markers.length; i++) {
					children[i]= new JEMarker(this, "[" + i + "]", markers[i]);
				}
				return children;
			}
		});
		result.add(new JavaElementChildrenProperty(this, "PERSISTENT PROPERTIES") {
			@Override protected JEAttribute[] computeChildren() throws CoreException {
				Map<QualifiedName, String> properties= getResource().getPersistentProperties();
				JEAttribute[] children= new JEAttribute[properties.size()];
				int i= 0;
				for (Entry<QualifiedName, String> property : properties.entrySet()) {
					children[i]= new JavaElementProperty(this, property.getKey().toString(), property.getValue());
					i++;
				}
				return children;
			}
		});
		result.add(new JavaElementChildrenProperty(this, "SESSION PROPERTIES") {
			@Override protected JEAttribute[] computeChildren() throws CoreException {
				Map<QualifiedName, Object> properties= getResource().getSessionProperties();
				JEAttribute[] children= new JEAttribute[properties.size()];
				int i= 0;
				for (Entry<QualifiedName, Object> property : properties.entrySet()) {
					children[i]= new JavaElementProperty(this, property.getKey().toString(), property.getValue());
					i++;
				}
				return children;
			}
		});

		return result.toArray(new JEAttribute[result.size()]);
	}

	@Override
	public String getLabel() {
		String label= fResource.getName();
		if (fName != null)
			label= fName +  ": " + label;
		if (! fResource.exists())
			label= label + " (does not exist)";
		return label;
	}

	public static JEAttribute compute(JEAttribute parent, String name, Callable<IResource> computer) {
		try {
			IResource resource= computer.call();
			return create(parent, name, resource);
		} catch (Exception e) {
			return new Error(parent, name, e);
		}
	}

	public static JEAttribute create(JEAttribute parent, String name, IResource resource) {
		if (resource == null) {
			return new Null(parent, name);
		} else {
			return new JEResource(parent, name, resource);
		}
	}

}
