// Copyright (c) Corporation for National Research Initiatives
// Copyright 2000 Samuele Pedroni

package org.python.core;
import java.io.*;
import java.util.StringTokenizer;
import java.util.Hashtable;
import java.util.zip.*;

public class SyspathJavaLoader extends ClassLoader
{

    public InputStream getResourceAsStream(String res) {
        ClassLoader classLoader = Py.getSystemState().getClassLoader();
        if (classLoader != null) return classLoader.getResourceAsStream(res);

        classLoader = this.getClass().getClassLoader();

        InputStream ret;

        if (classLoader != null) ret = classLoader.getResourceAsStream(res);
        else ret = ClassLoader.getSystemResourceAsStream(res);

        if (ret != null) return ret;

        if(res.charAt(0) == '/') res = res.substring(1);

        res.replace('/',File.separatorChar);

        PyList path = Py.getSystemState().path;
        for (int i=0; i < path.__len__(); i++) {
            PyObject entry = path.__getitem__(i);
            if (entry instanceof SyspathArchive) {
                SyspathArchive archive = (SyspathArchive) entry;
                ZipEntry ze = archive.getEntry(res);
                if (ze != null) {
                    try {
                        return archive.getInputStream(ze);
                    } catch (IOException e) { ; }
                }
                continue;
            }
            String dir = entry.__str__().toString();
            if (dir.length() == 0) dir = null;
            try {
                return new BufferedInputStream(
                       new FileInputStream(new File(dir,res)));
            }
            catch (IOException e) {
                continue;
            }
        }

        return null;
    }

    // override from abstract base class
    protected Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
//         System.err.println("loadClass("+name+", "+resolve+")");
        // First, if the Python runtime system has a default class loader,
        // defer to it.
        ClassLoader classLoader = Py.getSystemState().getClassLoader();
        if (classLoader != null)
            return classLoader.loadClass(name);
        // Search the sys.path for a .class file matching the named class.
        // TBD: This registry option is temporary.
        try {
          return Class.forName(name);
        }
        catch(ClassNotFoundException e) {
        }

        Class c = findLoadedClass(name);
        if (c != null)
         return c;

        /* previously: if
            Options.extendedClassLoader &&
            // KLUDGE ALERT: without this test, running jpython
            // interactively from the build directory will fail with
            // ClassCircularityError or LinkageError.  There's gotta be a
            // better way.
            !name.startsWith("org.python")
        */
        {
            PyList path = Py.getSystemState().path;
            for (int i=0; i < path.__len__(); i++) {
                InputStream fis = null;
                PyObject entry = path.__getitem__(i);
                if (entry instanceof SyspathArchive) {
                    SyspathArchive archive = (SyspathArchive) entry;
                    String entryname = name.replace('.', File.separatorChar) +
                                            ".class";
                    ZipEntry ze = archive.getEntry(entryname);
                    if (ze != null) {
                        try {
                            fis = archive.getInputStream(ze);
                        } catch (IOException exc) { ; }
                    }
                } else {
                    String dir = entry.__str__().toString();
                    fis = open(dir, name);
                }
                if (fis == null) {
                    continue;
                }
                try {
                    int size = fis.available();
                    byte[] buffer = new byte[size];
                    fis.read(buffer);
                    fis.close();
                    return loadClassFromBytes(name, buffer);
                }
                catch (IOException e) {
                    continue;
                }
            }
        }

        // couldn't find the .class file on sys.path
        throw new ClassNotFoundException(name);
    }

    private FileInputStream open(String dir, String name) {
        String accum = "";
        boolean first = true;
        for (StringTokenizer t = new StringTokenizer(name, ".");
             t.hasMoreTokens();)
        {
            String token = t.nextToken();
            if (!first)
                accum += File.separator;
            accum += token;
            first = false;
        }
        try {
            if (dir.length() == 0)
                dir = null;
            return new FileInputStream(new File(dir, accum+".class"));
        }
        catch (FileNotFoundException e) {
            return null;
        }
    }

    private Class loadClassFromBytes(String name, byte[] data) {
//         System.err.println("loadClassFromBytes("+name+", byte[])");
        Class c = defineClass(name, data, 0, data.length);
        resolveClass(c);
        // This method has caused much trouble.  Using it breaks jdk1.2rc1
        // Not using it can make SUN's jdk1.1.6 JIT slightly unhappy.
        // Don't use by default, but allow python.options.compileClass to
        // override
        if (!Options.skipCompile) {
//             System.err.println("compile: "+name);
            Compiler.compileClass(c);
        }
        return c;
    }

}
