package cn.edu.whu.boot.common.utils.allocation;

public class PiEncryptUtils {

    private static String pi = null;
    private static final int startNum = 10;//从第几位开始选择圆周率来构建加密矩阵
    private static int[][] matrix = null;

    public static int[] encrypt(int[] origin) {
        if (matrix == null) {
            do {
                matrix = PiEncryptUtils.getMatrix(startNum, origin.length);
            } while (PiEncryptUtils.det(matrix, origin.length - 1) == 0);
        }
        return PiEncryptUtils.multiply(origin, matrix);
    }

    private static double det(int[][] matrix, int N) {
        double num = 0;
        int cha = 0;
        double[][] B = new double[N][N];
        if (N > 0) {
            if (N == 1)
                return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
            for (int t0 = 0; t0 <= N; t0++) {
                for (int t1 = 1; t1 <= N; t1++) {
                    for (int t2 = 0; t2 <= N - 1; t2++) {
                        if (t2 == t0)
                            cha = 1;
                        B[t1 - 1][t2] = matrix[t1][t2 + cha];
                    }//T2循环
                    cha = 0;
                }//T1循环
                num = num + matrix[0][t0] * det(B, N - 1) * Math.pow((-1), t0);
            }//T0循环
            return num;
        } else if (N == 0) {
            return matrix[0][0];
        }
        return 0;
    }

    // 求行列式的值
    private static double det(double[][] matrix, int N) { // 计算n阶行列式（N=n-1）
        double num = 0;
        int cha = 0;
        double[][] B = new double[N][N];
        if (N > 0) {
            if (N == 1)
                return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
            for (int t0 = 0; t0 <= N; t0++) {
                for (int t1 = 1; t1 <= N; t1++) {
                    for (int t2 = 0; t2 <= N - 1; t2++) {
                        if (t2 == t0)
                            cha = 1;
                        B[t1 - 1][t2] = matrix[t1][t2 + cha];
                    }//T2循环
                    cha = 0;
                }//T1循环
                num = num + matrix[0][t0] * det(B, N - 1) * Math.pow((-1), t0);
            }//T0循环
            return num;
        } else if (N == 0) {
            return matrix[0][0];
        }
        return 0;
    }

    private static String getPiValue() {
        int a = 10000;
        int c = 56000;// 最大的精度
        int b = 0, d, e = 0, g;
        StringBuilder ans = new StringBuilder();
        int f[] = new int[c + 1];

        for (; b != c; ) f[b++] = a / 5;
        do {
            d = 0;
            g = c * 2;
            if (g == 0) break;
            b = c;
            do {
                d += f[b] * a;
                f[b] = d % --g;
                d /= g--;
                --b;
                if (b == 0) break;
                d *= b;
            } while (true);
            c -= 14;
            ans.append(e + d / a);
            e = d % a;
        } while (true);
        return ans.toString();
    }

    private static int[][] getMatrix(int startNum, int n) {
        if (pi == null)
            pi = getPiValue();
        String v = pi.substring(startNum, (int) (startNum + Math.pow(n, 2) - 1));
        int[][] result = new int[n][n];
        for (int i = 0; i < v.length(); i++) {
            int r = Integer.parseInt(v.substring(i, i + 1));
            result[i / n][i % n] = r;
        }
        return result;
    }

    private static int[] multiply(int[] origin, int[][] matrix) {
        int n = origin.length;
        int[] result = new int[n];
        for (int i = 0; i < n; i++) {
            int sum = 0;
            for (int j = 0; j < n; j++) {
                sum += origin[j] * matrix[j][i];
            }
            result[i] = sum;
        }
        return result;
    }

    public static double[][] inverse(double[][] Matrix, int N) {
        double[][] MatrixC = new double[N][N];
        double[][] B = new double[N][N];

        double add = 1 / det(Matrix, N);
        for (int T0 = 0; T0 <= N; T0++) {
            for (int T3 = 0; T3 <= N; T3++) {
                int Chay;
                int Chax;
                for (int T1 = 0; T1 <= N - 1; T1++) {
                    if (T1 < T0) {
                        Chax = 0;
                    } else {
                        Chax = 1;
                    }
                    for (int T2 = 0; T2 <= N - 1; T2++) {
                        if (T2 < T3) {
                            Chay = 0;
                        } else {
                            Chay = 1;
                        }
                        B[T1][T2] = Matrix[T1 + Chax][T2 + Chay];
                    }
                    //T2循环
                }//T1循环
                det(B, N - 1);
                MatrixC[T3][T0] = det(B, N - 1) * add * (Math.pow(-1, T0 + T3));
            }
        }
        return MatrixC;
    }
}
