package sexpression;

import static recursion.TailCalls.done;
import static recursion.TailCalls.tailCall;

import recursion.TailCall;

@DisplayName("list")
public class Cons extends SExpression {

    private SExpression first;
    private SExpression rest;

    public Cons(SExpression first, SExpression rest) {
        this.first = first;
        this.rest = rest;
    }

    public SExpression getFirst() {
        return first;
    }

    public SExpression getRest() {
        return rest;
    }

    public void setFirst(SExpression first) {
        this.first = first;
    }

    public void setRest(SExpression rest) {
        this.rest = rest;
    }

    @Override
    public boolean isCons() {
        return true;
    }

    @Override
    public String toString() {
        return toStringTailRecursive(new StringBuilder("(")).invoke();
    }

    private TailCall<String> toStringTailRecursive(StringBuilder leadingString) {
        leadingString.append(first.toString());

        if (rest.isNull())
            return done(leadingString.append(")").toString());
        else if (rest.isCons()) {
            return tailCall(() -> ((Cons) rest).toStringTailRecursive(leadingString.append(" ")));
        }

        return done(leadingString.append(" . " + rest.toString() + ")").toString());
    }

}
