package math.kombi;

import math.bigs.BigsUtil;

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

public class RecurStir1 implements Callable<BigInteger> {
    private final BigInteger k;
    private final BigInteger n;

    public RecurStir1(BigInteger k, BigInteger n) {
        this.k = k;
        this.n = n;
    }

    @Override
    public BigInteger call() {
        return recurStir1(this.k, this.n);
    }

    //oblicza liczbe Stirlinga II rodzaju (dla podzbiorow)
    //czyli k podzbiorow n
    public static int recurStir1(int k, int n) {
        if (n == 0 && k == 0) {
            return 1;
        } else if ((n > 0) && (k == 0) || (n < k)) {
            return 0;
        } else {
            return recurStir1(k - 1, n - 1) - (n - 1) * recurStir1(k, n - 1);
        }
    }

    public static long recurStir1(long k, long n) {
        if (n == 0 && k == 0) {
            return 1;
        } else if ((n > 0) && (k == 0) || (n < k)) {
            return 0;
        } else {
            return recurStir1(k - 1, n - 1) - (n - 1) * recurStir1(k, n - 1);
        }
    }

    public static BigInteger recurStir1(BigInteger k, BigInteger n) {
        if (BigsUtil.rowny(n, BigInteger.ZERO)
                && BigsUtil.rowny(k, BigInteger.ZERO)) {
            return BigInteger.ONE;
        } else if ((BigsUtil.wiekszy(n, BigInteger.ZERO)
                && BigsUtil.rowny(k, BigInteger.ZERO)
                || BigsUtil.mniejszy(n, k))) {
            return BigInteger.ZERO;
        } else {
            return recurStir1(k.subtract(BigInteger.ONE),
                    n.subtract(BigInteger.ONE)).subtract(
                    (n.subtract(BigInteger.ONE).multiply(recurStir1(k,
                            n.subtract(BigInteger.ONE)))));
        }
    }

}
