/*
 *        JacORB - a free Java ORB
 *
 *   Copyright (C) 1997-98  Gerald Brose.
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Library General Public
 *   License as published by the Free Software Foundation; either
 *   version 2 of the License, or (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *   Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this library; if not, write to the Free
 *   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package jacorb.orb.ir;

/** 
 *
 * This loader loads classes from the local file system using 
 * the file name which can be either an absolute path or be
 * relative to the class path the class loader was initialized
 * with.
 *
 * @author Gerald Brose, FU Berlin 1997/1998
 */

import java.util.Hashtable;
import java.io.*;
//import sun.tools.java.*;

public final class ClassLoader 
    extends java.lang.ClassLoader 
{

    static Hashtable classes = new Hashtable();
    static Hashtable classes_by_filename = new Hashtable();

    protected static char fileSeparator = 
	System.getProperty("file.separator").charAt(0);
    protected static String pathSeparator = 
	System.getProperty("path.separator");

    private static String OS = System.getProperty("os.name");

    int indent = 0;
    private ClassPath classpath;

    public ClassLoader( ClassPath cp )
    {
	classpath = cp;
    }

    public ClassPath getPath()
    {
	return classpath;
    }

    // Load a class from an input stream

    private Class loadClass(String name, InputStream is) 
	throws ClassNotFoundException 
    {
	byte	bytes[] = new byte[4096];
	byte	buffer[] = new byte[1024];
	int	n;
	int	totalBytes = 0;

	try
	{
	    while ((n = is.read(buffer, 0, buffer.length)) >= 0) 
	    {
		if (totalBytes + n >= bytes.length) 
		{
		    byte newbytes[] = new byte[((bytes.length + n) * 3) / 2];

		    System.arraycopy(bytes, 0, newbytes, 0, totalBytes);
		    bytes = newbytes;
		}
		System.arraycopy(buffer, 0, bytes, totalBytes, n);
		totalBytes += n;
	    }
	} 
	catch ( IOException e )
	{
	    e.printStackTrace();
	}
	if( totalBytes == 0 ) 
	    throw (new ClassNotFoundException("No bytes read."));

	return defineClass( name, bytes, 0, totalBytes);
    }


    public Class loadClass(String name) 
	throws ClassNotFoundException 
    {
	return  loadClass(name, true);
    }

    protected Class loadClass(String name, boolean resolve) 
	throws ClassNotFoundException 
    {
	Class cl = (Class)classes.get(name);

	if( cl != null )
	    return cl;

	if (cl == null && name.replace( fileSeparator,'.').startsWith("java.") )
	{
	    try 
	    {
		if( name.indexOf(".class") > 0 )
		    name = name.substring(0,name.indexOf(".class"));
		name = name.replace( fileSeparator,'.');
		cl = Class.forName(name);
		classes.put( name, cl );
		return cl;
	    } 
	    catch (Exception e) 
	    {
	    }
	}


	if( cl == null )
	{	
	    cl = findClass( name );
	}

	if( cl == null )
	    throw new ClassNotFoundException( name );

	if( resolve )
	{
	    try 
	    {
		resolveClass( cl );
	    } catch ( Exception e )
	    {
		e.printStackTrace();
		throw new ClassNotFoundException( name );
	    }
	}

	classes.put( cl.getName(), cl );
	return cl;
    }

    /**
     * This method finds a class. The returned class may be unresolved.
     * Must be called with a file name argument.
     */

    protected Class findClass( String name ) 
	throws ClassNotFoundException 
    {
	Class cl = null;
	InputStream fis = null;
	String fname = null;

	// debug: 
System.out.println("Looking at class " + name );
	try 
	{
	    cl = (Class)classes.get( name );
	    
	    if( cl == null )
	    {
		try 
		{
		    fis = classpath.getInputStream( name );	
		    cl = loadClass( null , fis );
		} 
		catch ( ClassFormatError cfe )
		{
		    throw new IOException();
		}
	    }
	    fis.close();
	    
	    if( cl != null )
		return cl;
	    } 
	catch ( Exception e )
	{
				// debug: e.printStackTrace();
				// System.out.println("***Looking at File " + fname );	    
	    throw new ClassNotFoundException( name );
	}
	return null;
    }

}


