package lab2;

/**
 * class dice lab 2 exercise 6
 * @author martin
Créez une classe De qui fournira une méthode renvoyant un nombre entier entre 1 et 6 tirés au
hasard. On pourra prévoir un constructeur définissant un nombre de faces autre que 6. Pour
effectuer le tirage au hasard, utiliser la fonction Math.random() et les méthodes de la classe Double
de java.lang. Créez une méthode affiche qui affiche le résultat du dés.
 */

public class De {
	/*properties*/
	private final int _nFace;

	/*Constructor*/
	/**
	 * @param n as int num of face
	 */
	private De(int n){
		_nFace = n;
	}

	/*static factory*/
	//it is very likely that the dice will be 6 face
	private static final De _de6 = new De(6);
	/**
	 * build dice from n face
	 * @param n as number of face in int
	 * @return new dice
	 */
	public static De fromNface(int n){
		if (n==6)
			return _de6;
		return new De(n);
	}

	/*on ne peut pas appliquer de operation mathématique sur
	 * des wrapper sans les convertires dabors en type primitif
	 * donc on vas y aller avec le functor*
	 */
	private interface FunctorNumberOP{
		/**
		 * functor eval method with two operand
		 * @param a as Number
		 * @param b as Number
		 * @return new Number
		 */
		public Number eval(Number a, Number b);
	}

	private interface FunctorNumber{
		/**
		 * functor eval methos with no operand
		 * @return new Number
		 */
		public Number eval();
	}
	/*method*/
	/**
	 * roll the dice print the result, return the result
	 * @return result of rolling the dice in the game
	 */
	public int roll(){
		//il n'y a pas de methode qui retourne un wrapper random
		//donc j'y vais avec les functors
		FunctorNumber DoubleRandom = new FunctorNumber(){
			public Number eval(){
				return Double.valueOf(Math.random());
			}
		};
		//les operations mathématiques n'existent pas pour les wrappers
		//mais avec chances je suis en train de lire "A gentle introduction to Lisp" et
		//Clojure programming in java. On va avoir du fun

		//voici le foncteur add pour deux wrapper
		FunctorNumberOP DoubleAdd = new FunctorNumberOP(){
			public Number eval(Number a, Number b){
				return Double.valueOf(a.doubleValue() + b.doubleValue());
			}
		};

		//et le foncteur mul pour deux wrapper
		FunctorNumberOP DoubleMul = new FunctorNumberOP(){
			public Number eval(Number a, Number b){
				return Double.valueOf(a.doubleValue() * b.doubleValue());
			}
		};

		//a des fin de lisibilité, j'ai utilisé la méthode d'indentation
		//de Carole Lamontagne pour les appels de multiple fonction
		//en chaine
		int resultat = DoubleAdd.eval(
				                      DoubleMul.eval(
				                    		         DoubleRandom.eval(),
				                                     Double.valueOf(_nFace)),
				                      Double.valueOf(1)
				       ).intValue();

//		System.out.print("rolled ");
//		System.out.println(resultat);
		return resultat;
	}

	/*main*/
	public static void main(String [ ] args){
		System.out.println("brassé 3 fois un de de 6 faces");

		De de6 = De.fromNface(6);
		for (int i = 0; i<3; i++){
			de6.roll();
		}
	}
}
