import java.util.*;
import java.io.PrintWriter;

/**
 * Symbol table class: dual parent supported: static and dynamic
 *
 * @author Hanhua Feng - hf2048@columbia.edu
 * @version $Id: MxSymbolTable.java,v 1.8 2003/05/12 23:44:34 hanhua Exp $
 */
class MxSymbolTable extends HashMap {
    MxSymbolTable static_parent, dynamic_parent;
    boolean read_only;

    public MxSymbolTable( MxSymbolTable sparent, MxSymbolTable dparent ) {
        static_parent = sparent;
        dynamic_parent = dparent;
        read_only = false;
    }

    public void setReadOnly() {
        read_only = true;
    }

    public final MxSymbolTable staticParent() {
        return static_parent;
    }

    public final MxSymbolTable dynamicParent() {
        return dynamic_parent;
    }

    public final MxSymbolTable parent( boolean is_static ) {
        return is_static ? static_parent : dynamic_parent;
    }

    public final boolean containsVar( String name ) {
        return containsKey( name );
    }

    private final MxSymbolTable gotoLevel( int level, boolean is_static ) {
        MxSymbolTable st = this;

        if ( level < 0 ) 
        {
            // global variable
            while ( null != st.static_parent )
                st = st.parent( is_static );
        }
        else
        {
            // local variable
            for ( int i=level; i>0; i-- )
            {
                while ( st.read_only )
                {
                    st = st.parent( is_static );
                    assert st != null;
                }
                
                if ( null != st.parent( is_static ) )
                    st = st.parent( is_static );
                else
                    break;
            }
        }

        return st;
    }

    public final MxDataType getValue( String name, boolean is_static,
                                      int level ) {
        MxSymbolTable st = gotoLevel( level, is_static );
        Object x = st.get( name );

        while ( null == x && null != st.parent( is_static ) )
        {
            st = st.parent( is_static );
            x = st.get( name );
        }

        return (MxDataType) x;
    }

    public final void setValue( String name, MxDataType data, 
                                boolean is_static, int level ) {
 
        MxSymbolTable st = gotoLevel( level, is_static );
        while ( st.read_only )
        {
            st = st.parent( is_static );
            assert st != null;
        }

        st.put( name, data );
    }

    public void what( PrintWriter output ) {
        for ( Iterator it = values().iterator() ; it.hasNext(); )
        {
            MxDataType d = ((MxDataType)(it.next()));
            if ( !( d instanceof MxFunction && ((MxFunction)d).isInternal() ) )
                d.what( output );
        }
    }

    public void what() {
        what( new PrintWriter( System.out, true ) );
    }
}
