package migl.lisp;

import migl.util.ConsList;
import migl.util.ConsListFactory;

public class LispList{
	
	/**
	 * ConsList pour stocker les elements de la liste
	 */
	private ConsList<Object> list;
	
	/**
	 * Création d'une liste vide
	 */
	private LispList() {
		this.list = ConsListFactory.nil();
	}
	
	/**
	 * Création d'une liste non vide
	 * @param list
	 */
	private LispList(ConsList<Object> list) {
		this.list = list;
	}
	
	/**
	 * Ajoute un element à la fin de la liste
	 * @param elt
	 */
	public LispList append(Object elt) {
		this.list = this.list.append(elt);
		return this;
	}
	
	/**
	 * Ajoute un element au debut de la liste
	 * @param elt
	 */
	public LispList prepend(Object elt) {
		this.list = this.list.prepend(elt);
		return this;
	}
	
	/**
	 * Récupère un element
	 * @param index La position de l'element
	 * @return
	 */
	public Object get(int index) {
		LispList l = this.getSubList(index);
		if(l == null) {
			return null;
		}
		return l.list.car();
	}
	
	/**
	 * Récupére une sous liste
	 * @param index La position de debut de la sous liste
	 * @return
	 */
	public LispList getSubList(int index) {
		if(this.list.size() <= index || index < 0) {
			return null;
		}
		ConsList<Object> cl = this.list;
		for(int i = 0; i < index; i++) {
			cl = cl.cdr();
		}
		return new LispList(cl);
	}
	
	/**
	 * Retourne la taille de la liste
	 * @return
	 */
	public int size() {
		return this.list.size();
	}
	
	/**
	 * Indique si la liste est vide ou non
	 * @return
	 */
	public boolean isEmpty() {
		return this.list.isEmpty();
	}
	
	@Override
	public String toString() {
		return this.list.toString();
	}
	
	@Override
	public boolean equals(Object obj) {
		if(this == obj) {
			return true;
		} else  if(obj == null) {
			return false;
		} else if(obj instanceof LispList) {
			LispList l = (LispList) obj;
			return this.list.equals(l.list);
		}
		return false;
	}
	
	@Override
	public int hashCode() {
		return this.list.hashCode();
	}
	
	/**
	 * Factory pour créer des listes vides
	 * @return
	 */
	public static LispList nil() {
		return new LispList();
	}
	
	/**
	 * Factory pour créer des listes à partir de String (ex : (1 2 3 4))
	 * @param expr
	 * @return
	 */
	public static LispList valueOf(String expr) {
		ConsList<Object> cl = ConsListFactory.nil();
		String[] tmp = expr.trim().split("[ |\t]");
		for(String str : tmp) {
			str = str.replaceAll("[\\(|\\)]", "").trim();
			if(str.length() > 0) {
				cl = cl.append(str);
			}
		}
		return new LispList(cl);
	}

}
