package math.kombi;

import math.bigs.BigsUtil;

import java.math.BigInteger;
import java.util.concurrent.Callable;

/**
 * Klasa do obliczeń n! w wątku
 *
 * @author Jacek Piechota
 */
public class Factorial implements Callable<BigInteger> {
    private final BigInteger n;

    public Factorial(BigInteger n) {
        this.n = n;
    }

    @Override
    public BigInteger call() {
        return factorial(this.n);
    }

    /**
     * Oblicza silnię n! dla podanej liczby całkowitej
     *
     * @param n - liczba całkowita
     * @return - zwraca n!
     */
    public static long factorial(int n) {
        if (n == 0) {
            return 1;
        }
        long sum = 1;
        for (int i = 1; i < n + 1; i++) {
            sum *= i;
        }
        return sum;
    }

    /**
     * Oblicza silnię n! dla podanej liczby całkowitej
     *
     * @param n - liczba całkowita
     * @return - zwraca n!
     */
    public static BigInteger factorial(long n) {
        if (n == 0) {
            return BigInteger.ONE;
        }
        BigInteger sum = new BigInteger("1");
        for (long i = 1; i < n + 1; i++) {
            sum = sum.multiply(BigInteger.valueOf(i));
        }
        return sum;
    }

    /**
     * Oblicza silnię n! dla podanej liczby całkowitej
     *
     * @param n - liczba całkowita
     * @return - zwraca n!
     */
    public static BigInteger factorial(BigInteger n) {
        if (BigsUtil.rowny(n, BigInteger.ZERO)) {
            return BigInteger.ONE;
        }
        BigInteger sum = new BigInteger("1");
        BigInteger i = new BigInteger("1");
        while (BigsUtil.mniejszy(i, n.add(BigInteger.ONE))) {
            sum = sum.multiply(i);
            i = i.add(BigInteger.ONE);
        }
        return sum;
    }
}
