/* *******************************************************************
 * Copyright (c) 2004 IBM Corporation
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Common Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://www.eclipse.org/legal/cpl-v10.html 
 *  
 * Contributors: 
 *     Matthew Webster, Adrian Colyer, 
 *     Martin Lippert     initial implementation 
 * ******************************************************************/

package org.aspectj.weaver;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.aspectj.weaver.tools.WeavingAdaptor;
import org.aspectj.weaver.tools.WeavingClassLoader;

public class WeavingURLClassLoader extends ExtensibleURLClassLoader implements WeavingClassLoader {

	public static final String WEAVING_CLASS_PATH = "aj.class.path"; 
	public static final String WEAVING_ASPECT_PATH = "aj.aspect.path"; 
	
	private URL[] aspectURLs;
	private WeavingAdaptor adaptor; 
	private Map generatedClasses = new HashMap(); /* String -> byte[] */ 

	/*
	 * This constructor is needed when using "-Djava.system.class.loader". 
	 */
	public WeavingURLClassLoader (ClassLoader parent) {
		this(getURLs(getClassPath()),getURLs(getAspectPath()),parent);
//		System.err.println("? WeavingURLClassLoader.<init>(" + parent + ")");
	}
	
	public WeavingURLClassLoader (URL[] classURLs, URL[] aspectURLs, ClassLoader parent) {
		super(classURLs,parent);
//		System.err.println("? WeavingURLClassLoader.<init>()");
		this.aspectURLs = aspectURLs;
		adaptor = new WeavingAdaptor(this);
	}
	
	private static String getAspectPath () {
		return System.getProperty(WEAVING_ASPECT_PATH,"");
	}
	
	private static String getClassPath () {
		return System.getProperty(WEAVING_CLASS_PATH,"");
	}
	
	private static URL[] getURLs (String path) {
		List urlList = new ArrayList();
		for (StringTokenizer t = new StringTokenizer(path,File.pathSeparator);
			 t.hasMoreTokens();) {
			File f = new File(t.nextToken().trim());
			try {
				if (f.exists()) {
					URL url = f.toURL();
					if (url != null) urlList.add(url);
				}
			} catch (MalformedURLException e) {}
		}

		URL[] urls = new URL[urlList.size()];
		urlList.toArray(urls);
		return urls;
	}

	protected void addURL(URL url) {
		adaptor.addURL(url);
		super.addURL(url);
	}

	/**
	 * Override to weave class using WeavingAdaptor 
	 */
	protected Class defineClass(String name, byte[] b, CodeSource cs) throws IOException {
//		System.err.println("? WeavingURLClassLoader.defineClass(" + name + ", [" + b.length + "])");
		b = adaptor.weaveClass(name,b);
		return super.defineClass(name, b, cs);
	}

	/**
	 * Override to find classes generated by WeavingAdaptor
	 */
	protected byte[] getBytes (String name) throws IOException {
		byte[] bytes = super.getBytes(name);
		
		if (bytes == null) {
//			return adaptor.findClass(name);
			return (byte[])generatedClasses.remove(name);
		}
		
		return bytes;
	}

	/**
	 * Implement method from WeavingClassLoader
	 */
	public URL[] getAspectURLs() {
		return aspectURLs;
	}

	public void acceptClass (String name, byte[] bytes) {
		generatedClasses.put(name,bytes);
	}

}
