package migl.lisp.operator;

import migl.lisp.LispElement;
import migl.lisp.LispError;
import migl.lisp.LispOperator;
import migl.util.ConsList;
import migl.util.ConsListFactory;

public class ConsOperator implements LispOperator {

	@Override
	public LispElement apply(String operator, ConsList<Object> lisp) throws LispError {
		if(lisp.size() != 2) {
			throw new LispError(LispError.ERR_NUM_ARG);
		}
		ConsList<Object> cl;
		if(lisp.cdr().car() instanceof ConsList) {
			//Recup + evaluation de la liste
			cl = this.parseList(LispElement.getElement(lisp.cdr().car()).toString());
			//Ajoute la valeur de gauche devant
			if(lisp.car() instanceof ConsList) {
				//Si la valeur gauche est aussi une liste on evalue sa valaue
				cl = cl.prepend(LispElement.getElement(lisp.car()).value);
			} else {
				cl = cl.prepend(lisp.car());
			}
		} else {
			LispElement le;
			if(lisp.car() instanceof ConsList) {
				//Si l'element est une liste on evalue sa valeur
				le = LispElement.getElement(lisp.car());
			} else {
				le = LispElement.generate(lisp.car());
			}
			cl = ConsListFactory.asList(le + " . " + lisp.cdr().car());
		}
		return LispElement.generate(cl.toString());
	}
	
	/**
	 * Parse une chaine en ConsList
	 * @param expr L'expression à parser
	 * @return
	 */
	public ConsList<Object> parseList(String expr){
		ConsList<Object> list = ConsListFactory.nil();
		//Parse d'une liste simple - ToDO parse toutes sorte de liste
		String[] tmp = expr.trim().split("[ |\t]");
		for(String str : tmp) {
			str = str.replaceAll("[\\(|\\)]", "").trim();
			if(str.length() > 0) {
				list = list.append(str);
			}
		}
		return list;
	}

}
