/*******************************************************************************
 * Copyright (c) 2001, 2009 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 API and implementation
 *     David Carver - STAR - [205989] - [validation] validate XML after XInclude resolution
 *     
 *    
 * The class is partially copied from WTP because of its poor visibility 
 * 	org.eclipse.wst.xml.core.internal.validation.XMLValidator.MyEntityResolver
 *     
 *******************************************************************************/

package org.jboss.tools.jsf.web.validation;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import org.apache.xerces.xni.XMLResourceIdentifier;
import org.apache.xerces.xni.XNIException;
import org.apache.xerces.xni.parser.XMLEntityResolver;
import org.apache.xerces.xni.parser.XMLInputSource;
import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolver;
import org.eclipse.wst.xml.core.internal.validation.XMLNestedValidatorContext;
import org.eclipse.wst.xml.core.internal.validation.core.LazyURLInputStream;
import org.eclipse.wst.xml.core.internal.validation.core.NestedValidatorContext;

/**
 * A custom entity resolver that uses the URI resolver specified to resolve
 * entities.
 */
public class XHTMLEntityResolver implements XMLEntityResolver {
	private URIResolver uriResolver;
	private String resolvedDTDLocation;
	private NestedValidatorContext context;

	/**
	 * Constructor.
	 * 
	 * @param uriResolver
	 *            The URI resolver to use with this entity resolver.
	 * @param context
	 *            The XML validator context.
	 */
	public XHTMLEntityResolver(URIResolver uriResolver,
			NestedValidatorContext context) {
		this.uriResolver = uriResolver;
		this.context = context;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.apache.xerces.xni.parser.XMLEntityResolver#resolveEntity(org.apache
	 * .xerces.xni.XMLResourceIdentifier)
	 */
	public XMLInputSource resolveEntity(XMLResourceIdentifier rid)
			throws XNIException, IOException {
		XMLInputSource inputSource = _internalResolveEntity(uriResolver, rid,
				context);
		if (inputSource != null) {
			resolvedDTDLocation = inputSource.getSystemId();
		}
		return inputSource;
	}

	public String getLocation() {
		return resolvedDTDLocation;
	}

	// cs : I've refactored the common SAX based resolution code into this
	// method for use by other validators
	// (i.e. XML Schema, WSDL etc). The other approach is maintain a copy for
	// each validator that has
	// identical code. In any case we should strive to ensure that the
	// validators perform resolution consistently.
	public static XMLInputSource _internalResolveEntity(
			URIResolver uriResolver, XMLResourceIdentifier rid)
			throws IOException {
		return _internalResolveEntity(uriResolver, rid, null);
	}

	public static XMLInputSource _internalResolveEntity(
			URIResolver uriResolver, XMLResourceIdentifier rid,
			NestedValidatorContext context) throws IOException {
		XMLInputSource is = null;

		if (uriResolver != null) {
			String id = rid.getPublicId();
			if (id == null) {
				id = rid.getNamespace();
			}

			String location = null;
			if (id != null || rid.getLiteralSystemId() != null) {
				location = uriResolver.resolve(rid.getBaseSystemId(), id, rid
						.getLiteralSystemId());
			}

			if (location != null) {
				String physical = uriResolver.resolvePhysicalLocation(rid
						.getBaseSystemId(), id, location);

				// if physical is already a known bad uri, just go ahead and
				// throw an exception
				if (context instanceof XMLNestedValidatorContext) {
					XMLNestedValidatorContext xmlContext = ((XMLNestedValidatorContext) context);

					if (xmlContext.isURIMarkedInaccessible(physical)) {
						throw new FileNotFoundException(physical);
					}
				}

//				// This block checks that the file exists. If it doesn't we need
//				// to throw
//				// an exception so Xerces will report an error. note: This may
//				// not be
//				// necessary with all versions of Xerces but has specifically
//				// been
//				// experienced with the version included in IBM's 1.4.2 JDK.
//				InputStream isTemp = null;
//				try {
//					isTemp = new URL(physical).openStream();
//				} catch (IOException e) {
//					// physical was a bad url, so cache it so we know next time
//					if (context instanceof XMLNestedValidatorContext) {
//						XMLNestedValidatorContext xmlContext = ((XMLNestedValidatorContext) context);
//						xmlContext.markURIInaccessible(physical);
//					}
//					throw e;
//				} finally {
//					if (isTemp != null) {
//						isTemp.close();
//					}
//				}
				if(physical.startsWith("file:")||physical.startsWith("jar:")) {
					is = new XMLInputSource(rid.getPublicId(), location, location);
					is.setByteStream(new LazyURLInputStream(physical));
				}
			}
		}
		return is;
	}

}
