import java.util.*;


public final class VariableTable {
	
	private int level;
	private boolean isInitialized;
	/* hash map permits null value */
	private Hashtable table;
	private VariableEntry variable;
	
	public VariableTable () {
		level = 0;
		table = new Hashtable();
	}
	
	public void put(String _variableName, Object _value, String _description) {
		
		/* when key's already in the table. */
		if ( exists(_variableName) ) {
			if (_variableName == null) {
				System.out.println("The name of the variable can't be null!! Insertion rejected." );
			}		// end of if (_variableName == null)
			/* description is non-nil */
			else if ( (_value == null) && (_description != null) ) {
				variable =  (VariableEntry) (table.get(_variableName) );
				variable.setDescription( _description );
				table.put( _variableName, variable );
			}
			else if ( (_description == null) && ( _value != null) )  {
				variable =  (VariableEntry) (table.get(_variableName) );
				variable.setValue( _value );
				variable.setInitialized(true);
				table.put( _variableName, variable );
			}
			else if ( (_description == null) && ( _value == null) ) {
				// do nothing
			}
			/* _description and _value are non-nil. */
			else {
				variable =  (VariableEntry) (table.get(_variableName) );
				variable.setValue( _value );
				variable.setInitialized(true);
				variable.setDescription( _description );
				table.put( _variableName, variable );
			}
		}
		/* if it's not in the table yet */
		else {
			if ( _variableName == null) {
				System.out.println("The name of the variable can't be null!! Insertion rejected." );
			}		// end of if (_variableName == null)
			/* description is non-nil */
			else if ( (_value == null) && (_description != null) ) {
				isInitialized = false;
				variable = new VariableEntry(_variableName, _value, level, isInitialized);
				variable.setDescription( _description);
				
				table.put(_variableName, variable);
			}
			else if ( (_description == null) && ( _value != null) )  {
				
				isInitialized = true;
				variable = new VariableEntry(_variableName, _value, level, isInitialized);
				
				table.put(_variableName, variable);
			}
			else if ( (_description == null) && ( _value == null) ) {
				// do nothing
			}
			/* _description and _value are non-nil. */
			else {
				isInitialized = true;
				variable = new VariableEntry(_variableName, _value, level, isInitialized);
				variable.setDescription ( _description);
				
				table.put( _variableName, variable );
			}
		}
	}
	
	
	
	
	public void put(String _variableName, Object _value) {
		
		/* when key's already in the table. */
		if ( exists(_variableName) ) {
			if (_variableName == null) {
				System.out.println("The name of the variable can't be null!! Insertion rejected." );
			}		// end of if (_variableName == null)
			else if ( _value == null) {
				// do nothing
			}
			else {
				variable =  (VariableEntry) (table.get(_variableName) );
				variable.setValue( _value );
				variable.setInitialized(true);
				table.put( _variableName, variable );
			}
			
		}
		/* if it's not in the table yet */
		else {
			if (_variableName == null) {
				System.out.println("The name of the variable can't be null!! Insertion rejected." );
			}		// end of if (_variableName == null)
			else if (_value == null) {
				isInitialized = false;
				variable = new VariableEntry(_variableName, _value, level, isInitialized);
				table.put(_variableName, variable);
			}		// end of else if (_value == null)
			else {
				isInitialized = true;
				variable = new VariableEntry(_variableName, _value, level, isInitialized);
				table.put(_variableName, variable);
			}
		}
		
	}
	
/*
 * INVARIANT: each key is non-empty-string or non-nil.
 */
	public String[] getKeys() {
		
		String[] keys = new String[table.size()];
		
		Enumeration table_enum = table.keys();
		for (int i = 0; table_enum.hasMoreElements(); i++) {
			Object key = table_enum.nextElement();
//			   System.out.println("Key: " + key);
			keys[i] = (String) key;
		}
		return keys;
	}
	
/*
 * INVARIANTS: each key is non-nil or non-empty-string. Each value is non-nil.
 */
	public Object[] getValues() {
		String[] keys = new String[table.size()];
		Object [] values = new Object[table.size()];
		
		Enumeration table_enum = table.keys();
		for (int i = 0; table_enum.hasMoreElements(); i++) {
			Object key = table_enum.nextElement();
			keys[i] = (String) key;
			
			/* VariableEntry to Integer. Then Integer to int. */
			values[i] = table.get(keys[i]);
		}
		
		return values;
		
	}
	
//	 public int[] getValues() {
//		 String[] keys = new String[table.size()];
//		 int [] values = new int[table.size()];
	
//		 Enumeration table_enum = table.keys();
//		 for (int i = 0; table_enum.hasMoreElements(); i++) {
//			 Object key = table_enum.nextElement();
// //			  System.out.println("Key: " + key);
//			 keys[i] = (String) key;
	
//			 /* VariableEntry to Integer. Then Integer to int. */
//			 values[i] = ((Integer) ((VariableEntry) table.get(keys[i])).getValue()).intValue();
// //			 System.out.println(" Value: " + values[i]);
	
//		 }
	
//		 return values;
	
//	 }
	
	
	public int size() {
		return table.size();
	}
	
	public Object get(String _variableName) {
		Object variable = table.get(_variableName);
		return variable;
	}
	
	public boolean exists(String _variableName) {
		return table.containsKey(_variableName);
	}
	
	// Opens a new level in the identification table, 1 higher than the
	// current topmost level.
	public void openScope () {
		level++;
	}
	
	// Closes the topmost level in the identification table, discarding
	// all entries belonging to that level.
	public void closeScope () {
		if (level > 0) {
			
			level--;
			
		}		// end of if (level > 0)
	}
	
	
	public static void main(String[] args) {
		
	} // end of main()
	
}
