package math.kombi;

import math.bigs.BigsUtil;

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

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

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

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

    public static BigInteger recurStir2(BigInteger k, BigInteger n) {
        if (BigsUtil.rowny(n, BigInteger.ZERO)
                && BigsUtil.rowny(k, BigInteger.ZERO)) {
            return BigInteger.ONE;
        } else if (BigsUtil.rowny(n, BigInteger.ZERO)
                && BigsUtil.rowny(k, BigInteger.ONE)) {
            return BigInteger.ZERO;
        } else if (BigsUtil.wiekszy(n, BigInteger.ZERO)) {
            if (BigsUtil.rowny(k, BigInteger.ZERO)) {
                return BigInteger.ZERO;
            } else if (BigsUtil.rowny(k, BigInteger.ONE)) {
                return BigInteger.ONE;
            } else if (BigsUtil.mniejszy(n, k)) {
                return BigInteger.ZERO;
            } else if (BigsUtil.rowny(n, k)) {
                return BigInteger.ONE;
            } else {
                return (recurStir2(k.subtract(BigInteger.ONE),
                        n.subtract(BigInteger.ONE)).add(k.multiply(
                        recurStir2(k, n.subtract(BigInteger.ONE)))));
            }
        } else {
            return new BigInteger("-1");
        }
    }

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

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

}
