/*******************************************************************************
 * Copyright (c) 2004 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
 *******************************************************************************/
package org.aspectj.ajdt.internal.core.builder;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.aspectj.bridge.IMessageHandler;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.bcel.ClassPathManager;
import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;

/**
 * @author colyer
 *
 * Provide a type lookup environment for the weaver, without having to convert
 * the various eclipse paths into their external form.
 */
public class EclipseClassPathManager extends ClassPathManager {
	
	private INameEnvironment nameEnv;
	
	public EclipseClassPathManager(INameEnvironment env) {
		this.nameEnv = env;
	}
	
	// class path manager will be used by weaver across multiple compiles,
	// whereas a name environment may be constructed per-compile.
	public void setNameEnvironment(INameEnvironment env) {
		this.nameEnv = env;
	}
	
	/* (non-Javadoc)
	 * @see org.aspectj.weaver.bcel.ClassPathManager#addPath(java.lang.String, org.aspectj.bridge.IMessageHandler)
	 */
	public void addPath(String name, IMessageHandler handler) {
		throw new UnsupportedOperationException("Can't add paths to an *Eclipse*ClassPathManager.");
	}
	
	/* (non-Javadoc)
	 * @see org.aspectj.weaver.bcel.ClassPathManager#find(org.aspectj.weaver.UnresolvedType)
	 */
	public ClassFile find(UnresolvedType type) {
		ClassFile cf = null;
		String name = type.getName();
		if (name.endsWith(".class")) {
			name = name.substring(0,name.length() - ".class".length());
		}
		char[][] cname = CharOperation.splitOn('.',name.toCharArray());
		NameEnvironmentAnswer answer = nameEnv.findType(cname);
		if (answer == null || !answer.isBinaryType()) {
			return null;
		} else {
			IBinaryType binType = answer.getBinaryType();
			// XXX - but better than the alternative hacks
			if (binType instanceof ClassFileReader) {
				ClassFileReader cfr = (ClassFileReader) binType;
				cf = new ClassFileReaderBackedClassFile(cfr);
			} else {
				throw new IllegalArgumentException(
						"I'm only geared up to handle ClassFileReaders, and you gave me a " + 
						binType.getClass().getName());
			}
			return cf;
		} 
	}
	/* (non-Javadoc)
	 * @see org.aspectj.weaver.bcel.ClassPathManager#getAllClassFiles()
	 */
	public List getAllClassFiles() {
		throw new UnsupportedOperationException("I don't implement getAllClassFiles()");
		//return Collections.EMPTY_LIST;
	}
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		StringBuffer buf = new StringBuffer("EclipseClassPathManager: ");
		buf.append(nameEnv.toString());
		return buf.toString();
	}
	
	private class ClassFileReaderBackedClassFile extends ClassPathManager.ClassFile {

		private ClassFileReader source;
		private InputStream is;
		
		public ClassFileReaderBackedClassFile(ClassFileReader cfr) {
			source = cfr;
		}
		
		/* (non-Javadoc)
		 * @see org.aspectj.weaver.bcel.ClassPathManager.ClassFile#getInputStream()
		 */
		public InputStream getInputStream() throws IOException {
			is = new ByteArrayInputStream(source.getReferenceBytes());
			return is;
		}
		
		public void close() {
			try {
				if (is!=null) is.close();
			} catch (IOException e) {
				// Should never happen !
				e.printStackTrace();
			}
		} 

		/* (non-Javadoc)
		 * @see org.aspectj.weaver.bcel.ClassPathManager.ClassFile#getPath()
		 */
		public String getPath() {
			return new String(source.getFileName());
		}		
	}
}
