/* Author: Jeff Dalton <J.Dalton@ed.ac.uk>
 * Updated: Sat Jun 30 18:53:09 2001 by Jeff Dalton
 */

package ix.util.lisp;

import java.util.*;
import ix.util.*;


/** Non-empty lists. */

public class Cons extends LList implements Cloneable {

    Object car;
    LList cdr;			// only proper lists

    public Cons(Object car, LList cdr) {
	this.car = car;
	this.cdr = cdr;
    }


    public boolean isNull() { return false; }

    public Object car() { return car; }
    public LList cdr() { return cdr; }

    public void setCar(Object c) {
	car = c;
    }

    public void setCdr(Object c) {
	cdr = (LList)c;
    }

    public int length() {
	int i = 1;
	for (Cons at = this; at.cdr != Lisp.NIL; at = (Cons)at.cdr, ++i)
	    {}
	return i;
    }

    public Object elementAt(int i) {
	int j = 0;
	for (LList at = this; at != Lisp.NIL; at = ((Cons)at).cdr) {
	    if (j++ == i)
		return ((Cons)at).car;
	}
	return Lisp.NIL;
    }

    public Enumeration elements() {
	return new ConsEnumeration(this);
    }

    public boolean equal(LList list) {
	return Lisp.equal(this, list);
    }

    public boolean find(Object a) {
	for (LList at = this; at != Lisp.NIL; at = ((Cons)at).cdr) {
	    if (((Cons)at).car == a)
		return true;
	}
	return false;
    }

    public LList append(LList tail) {
	return new Cons(this.car, this.cdr.append(tail));
    }

    /*
     * Java Object stuff
     */

    public Object clone() {
	return append(Lisp.NIL);	// yes, that old trick
    }

    public boolean equals(Object a) {
	return Lisp.equal(this, a);
    }

    // public int hashCode() {
    //     return car.hashCode();	// yes, I know that's totally losing
    // }

    public String toString() {
	return Lisp.printToString(this);
    }

}


/** Cons enumerations. */

class ConsEnumeration extends LListEnumeration {

    protected LList tail;

    ConsEnumeration(Cons c) {
	tail = c;
    }

    public boolean hasMoreElements() {
	return tail instanceof Cons;
    }

    public Object nextElement() {
	Object elt = ((Cons)tail).car;
	tail = ((Cons)tail).cdr;
	return elt;
    }

}
