/*
 * Copyright 2009 Yuichiro Moriguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.morilib.lisp.nano;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 
 *
 *
 * @author MORIGUCHI, Yuichiro 2009
 */
public final class Cons extends Datum
implements java.io.Serializable {

	//
	private Datum car;
	private Datum cdr;

	/**
	 * 
	 */
	public Cons() {
		this.car = Nil.NIL;
		this.cdr = Nil.NIL;
	}

	/**
	 * 
	 * @param car
	 * @param cdr
	 */
	public Cons(Datum car, Datum cdr) {
		if(car == null) {
			throw new NullPointerException("car is null");
		}
		if(cdr == null) {
			throw new NullPointerException("cdr is null");
		}

		this.car = car;
		this.cdr = cdr;
	}

	/**
	 * @return the car
	 */
	public Datum getCar() {
		return car;
	}

	/**
	 * @param car the car to set
	 */
	/*package*/ void setCar(Datum car) {
		this.car = car;
	}

	/**
	 * @return the cdr
	 */
	public Datum getCdr() {
		return cdr;
	}

	/**
	 * @param cdr the cdr to set
	 */
	/*package*/ void setCdr(Datum cdr) {
		this.cdr = cdr;
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.Datum#isTypeList()
	 */
	public boolean isTypeList() {
		return true;
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.Datum#isDottedList()
	 */
	public boolean isDottedList() {
		return !getDottedDatum().isNil();
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.Datum#getList()
	 */
	public List<Datum> getList() {
		List<Datum> res = new ArrayList<Datum>();
		Datum p = cdr;

		res.add(car);
		while(true) {
			if(p instanceof Cons) {
				Cons p2 = (Cons)p;

				res.add(p2.car);
				p = p2.cdr;
			} else {
				return Collections.unmodifiableList(res);
			}
		}
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.Datum#getDottedDatum()
	 */
	public Datum getDottedDatum() {
		Datum p = cdr;

		while(p instanceof Cons) {
			p = ((Cons)p).cdr;
		}
		return p;
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.Datum#toString()
	 */
	public String toString() {
		return LispUtils.toWrite(this);
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.nano.Datum#toDisplay()
	 */
	@Override
	public String toDisplay() {
		return LispUtils.toDisplay(this);
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.nano.Datum#toDisplay()
	 */
	@Override
	public String toWrite() {
		return LispUtils.toWrite(this);
	}

}
