/*
 * EnvAccess.java
 *
 * Copyright (C) 2010 Alessio Stalla
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * As a special exception, the copyright holders of this library give you
 * permission to link this library with independent modules to produce an
 * executable, regardless of the license terms of these independent
 * modules, and to copy and distribute the resulting executable under
 * terms of your choice, provided that you also meet, for each linked
 * independent module, the terms and conditions of the license of that
 * module.  An independent module is a module which is not derived from
 * or based on this library.  If you modify this library, you may extend
 * this exception to your version of the library, but you are not
 * obligated to do so.  If you do not wish to do so, delete this
 * exception statement from your version.
 */

package org.armedbear.lisp;

import static org.armedbear.lisp.Lisp.*;

public final class EnvAccess {
    
        //THIS IS COPIED HERE FROM Environment.java IN MY LOCAL COPY OF ABCL
    //this should make Snow work with stock abcl.

    //Experimental port of the Franz Environment Access library
    //(http://www.franz.com/support/documentation/8.0/doc/environments.htm)
    //
    //astalla 2010-01-05 - for now I'm only interested in variable-information
    //(actually just to check if a lexical variable is bound), but this could
    //grow in the future.
    //
    //I'm placing everything in SYSTEM like ACL does, but I believe we should
    //have a SYS.ENV package or something like that.

    /**
     * Ensures the argument is an environment designator: either an environment
     * object or NIL which means the global environment.
     * TODO: on NIL it returns a fresh, empty environment, which is wrong.
     */
    public static final Environment ensureEnvironment(LispObject o) {
	if(o == NIL) {
	    return new Environment(); //TODO
	} else {
	    return checkEnvironment(o);
	}
    }

    private static final Symbol KEYWORD_LEXICAL = internKeyword("LEXICAL");
    private static final Symbol KEYWORD_SPECIAL = internKeyword("SPECIAL");

    // ### variable-information
    //http://www.franz.com/support/documentation/8.0/doc/operators/system/variable-information.htm
    private static final Primitive VARIABLE_INFORMATION =
	new Primitive("variable-information", PACKAGE_SYS, true, "symbol &optional env all-declarations")
    {
      @Override
      public LispObject execute(LispObject[] args) {
	  if(args.length < 1 || args.length > 3) {
	      return error(new WrongNumberOfArgumentsException(this));
	  }
	  Environment env = ensureEnvironment(args.length > 1 ? args[1] : NIL);
	  Binding b = env.getBinding(args[0]);
	  LispThread t = LispThread.currentThread();
	  if(b != null) {
	      return t.setValues(b.specialp ? KEYWORD_SPECIAL : KEYWORD_LEXICAL,
				 NIL, //TODO
				 NIL, //TODO
				 T);
	  } else {
	      return t.setValues(NIL, NIL, NIL, NIL); //TODO check
	  }
      }
    };

}