// Copyright (c) 1996-2002 Brian D. Carlstrom

package bdc.scheme;

import bdc.scheme.expression.GlobalVariable;
import bdc.scheme.procedure.JavaNew;
import java.util.HashMap;

/**
    The Global Environment for Scheme
*/
public final class GlobalEnvironment
{
    /**
        Location indicates that this is an ordinary GlobalVariable
    */
    public static final int Location = 0;

    /**
        Special indicates that this is a SpecialFormCompiler
    */
    public static final int Special = 1;

    /**
        Macro indicates that this is a procedure that does syntax rewritting
    */
    public static final int Macro = 2;

    /**
        The global environment for Scheme
    */
    private final HashMap globalEnvironment = new HashMap();


    /*
        Setup the global environment
    */
    GlobalEnvironment ()
    {
        define(Symbol.get("new"), new JavaNew());
    }

    /**
        lookup global variable by String name
    */
    public GlobalVariable lookup (String name)
    {
        return lookup(Symbol.get(name));
    }

    /**
        lookup GlobalVariable by Symbol
    */
    public GlobalVariable lookup (Symbol symbol)
    {
        GlobalVariable globalVariable;
        synchronized (globalEnvironment) {
            globalVariable = (GlobalVariable)globalEnvironment.get(symbol);
        }
        if (globalVariable == null) {
            return null;
        }
        return globalVariable;
    }

    /**
        Return a possible existing GlobalVariable.

        If it does not exist it is a forward reference marked as Undefined
        possible to be filled in by a later Definition.
    */
    public GlobalVariable define (Symbol name)
    {
        return define(name, Scheme.Undefined, GlobalEnvironment.Location);
    }

    /**
        Return a possible existing GlobalVariable.

        If it does not exist it is a create it initialized to object.
    */
    public GlobalVariable define (Symbol name, Object object)
    {
        return define(name, object, GlobalEnvironment.Location);
    }

    /**
        Return a possible existing GlobalVariable.

        If it does not exist it is a create it initialized to an
        object of the specifed type.
    */
    public GlobalVariable define (Symbol name, Object object, int type)
    {
        GlobalVariable globalVariable;
        synchronized (globalEnvironment) {
            globalVariable = (GlobalVariable)globalEnvironment.get(name);
        }
        if (globalVariable != null) {
            return globalVariable;
        }
        GlobalVariable gv = new GlobalVariable(name, object, type);
        synchronized (globalEnvironment) {
            globalEnvironment.put(gv.name, gv);
        }
        return gv;
    }
}
