package migl.lisp.operator;

import java.math.BigInteger;

import migl.lisp.LispElement;
import migl.lisp.LispError;
import migl.lisp.LispEval;
import migl.util.ConsList;

public class MinMaxOperator implements LispOperator {

	@Override
	public LispElement apply(LispEval eval, String operator, ConsList<Object> lisp) throws LispError {
		if(lisp.size() != 2 /* Mettre == 0 Pour nombre infini variable */) {
			throw new LispError(LispError.ERR_NUM_ARG);
		}
		//Initialise avec la 1er valeur
		LispElement elt = eval.getElement(lisp.car());
		lisp = lisp.cdr();
		double result;
		try {
			BigInteger res = elt.toInt();
			//Parcours les elements suivants
			while(!lisp.isEmpty()) {
				elt = eval.getElement(lisp.car());
	            if(elt.getValue().getClass() != BigInteger.class) break;
	            switch(operator) {
					case "max":
						res = res.max(elt.toInt());
						break;
					case "min":
						res = res.min(elt.toInt());
						break;
					default:
						throw new LispError(operator + LispError.ERR_UNKNOW);
				}
	            lisp = lisp.cdr();
			}
			//Si on finit la liste avec que des entier on retourne
	        if(lisp.isEmpty()) return LispElement.generate(res);
	        //Sinon on continue en passant en double
	        result = res.doubleValue();
		} catch (Exception ex) {
			result = elt.toNumber();
		}
        while(!lisp.isEmpty()) {
             double value = eval.getElement(lisp.car()).toNumber();
             switch(operator) {
				case "max":
					result = Math.max(value, result);
					break;
				case "min":
					result = Math.min(value, result);
					break;
				default:
					throw new LispError(operator + LispError.ERR_UNKNOW);
			}
            lisp = lisp.cdr();
        }
        return LispElement.generate(result);
	}

}
