/*
    JPC: A x86 PC Hardware Emulator for a pure Java Virtual Machine
    Release Version 2.0

    A project from the Physics Dept, The University of Oxford

    Copyright (C) 2007 Isis Innovation Limited

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 2 as published by
    the Free Software Foundation.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
    Details (including contact information) can be found at: 

    www.physics.ox.ac.uk/jpc
*/

package org.jpc.sourcecompiler;

import javax.tools.*;
import java.net.*;
import java.lang.*;
import java.io.*;
import java.util.*;
import org.jpc.emulator.memory.codeblock.*;

import static javax.tools.JavaFileObject.Kind;


public class StringJavaFileManager implements JavaFileManager
{
    private JavaFileObject stringReader;
    private BytesHolder bytesHolder;
    private JavaFileManager defaultManager;
    private Location classLoaderLocation;
    private String compiledClassName;
    private ClassLoader newClassLoader;

    StringJavaFileManager(JavaFileManager defaultManager, ClassLoader newClassLoader)
    {
        this.newClassLoader = newClassLoader;
        this.defaultManager = defaultManager;
    }

    //remove this when it works
    StringJavaFileManager(String className, CharSequence classCode, JavaFileManager defaultManager, ClassLoader newClassLoader)
    {
        this.newClassLoader = newClassLoader;
        this.stringReader = new JavaSourceFromString(className, classCode);
        this.bytesHolder = new BytesHolder(className);
        this.defaultManager = defaultManager;
        this.compiledClassName = className;
    }

    //change the contents so we can compile a new block
    public void setContents(String className, CharSequence classCode)
    {
        this.compiledClassName = className;
        this.stringReader = new JavaSourceFromString(className, classCode);
        this.bytesHolder = new BytesHolder(className);
    }

    public ClassLoader getClassLoader(Location location)
    {
        //System.out.println("getting ClassLoader " + location.getName());
        this.classLoaderLocation = location;
        return newClassLoader;//this.getClass().getClassLoader();
    }

    public Location getClassLoaderLocation()
    {
        return classLoaderLocation;
    }

    public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse) throws IOException
    {
        return defaultManager.list(location, packageName, kinds, recurse);
    }

    public String inferBinaryName(Location location, JavaFileObject file)
    {
        //System.out.println("inferring binary name " + defaultManager.inferBinaryName(location, file));
        if (!(file instanceof JavaSourceFromString) && !(file instanceof BytesHolder) )
        {
            //System.out.println(file.getClass());
            return defaultManager.inferBinaryName(location, file);
        }
        return file.getName();

    }

    public BytesHolder getBytesHolder()
    {
        return bytesHolder;
    }

    public boolean isSameFile(FileObject a, FileObject b)
    {
        //System.out.println("comparing two files");
        return false;
    }

    public boolean handleOption(String current, Iterator<String> remaining)
    {
        //System.out.println("can we handle this option?");
        return false;
    }

    public boolean hasLocation(Location location)
    {
        //System.out.println("do we have this location? " + location.getName());
        return true;
    }

    public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException
    {
        return defaultManager.getJavaFileForInput(location, className, kind);
    }

    public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException
    {
        if (className.endsWith(compiledClassName))
            return bytesHolder;
        
        throw new IOException("Cannot write to filesystem");
        //return defaultManager.getJavaFileForOutput(location, className, kind, sibling);
    }

    public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException
    {
        //System.out.println("getting file for input");
        return null;// return getJavaFileForInput(Location location, String className, Kind kind);
    }

    public FileObject getFileForOutput(JavaFileManager.Location location, String packageName, String relativeName, FileObject sibling) throws IOException
    {
        //System.out.println("getting file for output");
        return bytesHolder;
    }

    public int isSupportedOption(String option)
    {
        //System.out.println("do we support option " + option);
        return 0;
    }

    public void flush() throws IOException {}

    public void close() throws IOException {}
}
