package com.yeechart.dotMatrix.canvas;

/**
 * 点阵图 绘制 工具类
 */
public class DotMatrixCanvasUtil {


    /**
     * 点阵图 放大
     *
     * @param originalMatrix 原点阵
     * @param scaledColumns  放大后的大小(如果小于当前则返回当前)
     * @return
     */
    public static int[][] scaleDotMatrix(int[][] originalMatrix, int scaledColumns) {

        if (scaledColumns <= originalMatrix[0].length) {
//            System.out.println("字体大小相同或者更小："+scaledColumns);
            return originalMatrix;
        }

        int rows = originalMatrix.length;
        int columns = originalMatrix[0].length;

        int scaledRows = rows * scaledColumns / columns;
        int[][] scaledMatrix = new int[scaledRows][scaledColumns];

        for (int i = 0; i < scaledRows; i++) {
            for (int j = 0; j < scaledColumns; j++) {
                int originalRow = i * rows / scaledRows;
                int originalColumn = j * columns / scaledColumns;
                scaledMatrix[i][j] = originalMatrix[originalRow][originalColumn];
            }
        }

        return scaledMatrix;
    }


    /**
     * 合并点阵图
     *
     * @param matrix1
     * @param matrix2
     * @return
     */
    public static int[][] mergeDotMatrices(int[][] matrix1, int[][] matrix2) {

        int rows1 = matrix1.length;
        int rows2 = matrix2.length;

        int rowsMax = Math.max(rows1, rows2);

        int columns1 = matrix1[0].length;
        int columns2 = matrix2[0].length;

        int offsetRows1 = (rowsMax - rows1) / 2;
        int offsetRows2 = (rowsMax - rows1) / 2;

        int[][] mergedMatrix = new int[rowsMax][columns1 + columns2];

        for (int i = 0; i < rows1; i++) {

            for (int j = 0; j < columns1; j++) {
                mergedMatrix[i + offsetRows1][j] = matrix1[i][j];
            }

            for (int j = 0; j < columns2; j++) {
                mergedMatrix[i + offsetRows2][columns1 + j] = matrix2[i][j];
            }

        }


        return mergedMatrix;
    }


    /**
     * 合并点阵图  会扩充为同样大小的点阵
     *
     * @param matrix1
     * @param matrix2
     * @return
     */
    public static int[][] mergeDotMatrices(int rows, int columns, int[][] matrix1, int[][] matrix2) {

        int rows1 = matrix1.length;
        int columns1 = matrix1[0].length;


        int rows2 = matrix2.length;
        int columns2 = matrix2[0].length;

        //偏移量
        int offsetRows1 = (rows - rows1) / 2;
        int offsetRows2 = (rows - rows2) / 2;

        int offsetColumns1 = (columns - columns1) / 2;
        int offsetColumns2 = (columns - columns2) / 2;

        if (offsetColumns1 < 0) {
            offsetColumns1 = 0;
        }

        if (offsetColumns2 < 0) {
            offsetColumns2 = 0;
        }
        int[][] mergedMatrix = new int[rows][columns1 + columns2];

        //开始合并
        for (int i = 0; i < rows; i++) {

            for (int j = 0; j < columns1; j++) {
                if (rows1 > i) {
                    mergedMatrix[i + offsetRows1][j + offsetColumns1] = matrix1[i][j];
                }

            }

            for (int j = 0; j < columns2; j++) {
                if (rows2 > i) {
                    mergedMatrix[i + offsetRows2]
                            [columns1 + offsetColumns2 + j]
                            = matrix2[i][j];
                }

            }

        }


        return mergedMatrix;
    }


    /**
     * 合并点阵图 维持高度 横向排列
     *
     * @param matrix1
     * @param matrix2
     * @return
     */
    public static int[][] mergeDotMatricesWidth(int rows, int columns, int[][] matrix1, int[][] matrix2, boolean isHorizontal) {

        int rows1 = matrix1.length;
        int columns1 = matrix1[0].length;


        int rows2 = matrix2.length;
        int columns2 = matrix2[0].length;

        //偏移量
        int offsetRows1 = (rows - rows1) / 2;
        int offsetRows2 = (rows - rows2) / 2;

        int offsetColumns1 = (columns - columns1) / 2;
        int offsetColumns2 = (columns - columns2) / 2;


        int x = 0;
        int x1 = 0;
        int x2 = 0;
        int y1 = 0;
        int y2 = 0;

        int[][] mergedMatrix = null;

        if (isHorizontal) {
            mergedMatrix = new int[rows][columns1 + columns2];
            x = rows;
            x1 = rows1;
            x2 = rows2;
            y1 = columns1;
            y2 = columns2;
        } else {
            mergedMatrix = new int[rows1 + rows2][columns];
            x = columns;
            x1 = columns1;
            x2 = columns2;
            y1 = rows1;
            y2 = rows2;

        }


        //开始合并
        for (int i = 0; i < x; i++) {

            for (int j = 0; j < y1; j++) {
                if (x1 > i) {
                    if (isHorizontal) {
                        mergedMatrix[i + offsetRows1][j] = matrix1[i][j];
                    } else {
                        mergedMatrix[j][i + offsetColumns1] = matrix1[j][i];
                    }
                }
            }

            for (int j = 0; j < y2; j++) {
                if (x2 > i) {
                    if (isHorizontal) {
                        mergedMatrix[i + offsetRows2]
                                [y1 + j]
                                = matrix2[i][j];
                    } else {
                        mergedMatrix[y1 + j]
                                [i + offsetColumns2]
                                = matrix2[j][i];
                    }
                }
            }
        }

        return mergedMatrix;
    }


    /**
     * 将 指定左上角位置的点阵数组 添加至 点阵画布数组中
     *
     * @param largeMatrix  点阵画布
     * @param smallMatrix  数据点阵
     * @param startRow     起始行
     * @param startColumn  起始列
     * @param confuseModel 混淆模式:  0 数据点阵完全覆盖点阵画布 ； 1 数据点阵中与点阵画布中有内容重叠的部分时，将透明出该部分
     */
    public static void mergeDotMatricesConfuse(int[][] largeMatrix, int[][] smallMatrix, int startRow, int startColumn, int confuseModel) {
        int smallRows = smallMatrix.length;
        int smallColumns = smallMatrix[0].length;

        for (int i = 0; i < smallRows; i++) {
            for (int j = 0; j < smallColumns; j++) {
                if (startRow + i < largeMatrix.length && startColumn + j < largeMatrix[0].length) {

                    if (confuseModel == 0) {
                        largeMatrix[startRow + i][startColumn + j] = smallMatrix[i][j];
                    } else if (confuseModel == 1) {

                        if (smallMatrix[i][j] == 1) {
                            if (largeMatrix[startRow + i][startColumn + j] == 1) {
                                largeMatrix[startRow + i][startColumn + j] = 0;
                            } else {
                                largeMatrix[startRow + i][startColumn + j] = smallMatrix[i][j];
                            }
                        }

                    }

                } else {
//                    System.out.print("内容超出 画布范围 :" + i+"  "+j);
                }

            }
        }


    }


    /**
     * 将点阵数组进行 指定角度的旋转 需要注意的是旋转之后数组可能会变大
     *
     * @param matrix
     * @param rotationAngle
     * @return
     */
    public static int[][] rotateDotMatrix(int[][] matrix, int rotationAngle) {
        int rows = matrix.length;
        int columns = matrix[0].length;

        // 计算旋转角度的弧度值
        double theta = Math.toRadians(rotationAngle);
        double cosTheta = Math.cos(theta);
        double sinTheta = Math.sin(theta);

        // 计算旋转后的矩阵尺寸
        int rotatedRows = (int) Math.round(rows * Math.abs(cosTheta) + columns * Math.abs(sinTheta));
        int rotatedColumns = (int) Math.round(rows * Math.abs(sinTheta) + columns * Math.abs(cosTheta));

        // 创建旋转后的矩阵
        int[][] rotatedMatrix = new int[rotatedRows][rotatedColumns];

        // 计算旋转中心点
        double centerRow = rows / 2.0;
        double centerColumn = columns / 2.0;
        double rotatedCenterRow = rotatedRows / 2.0;
        double rotatedCenterColumn = rotatedColumns / 2.0;

        // 进行旋转
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                // 计算旋转后的坐标
                double x = (i - centerRow) * cosTheta - (j - centerColumn) * sinTheta + rotatedCenterRow;
                double y = (i - centerRow) * sinTheta + (j - centerColumn) * cosTheta + rotatedCenterColumn;

                // 四舍五入取整
                int rotatedRow = (int) Math.round(x);
                int rotatedColumn = (int) Math.round(y);

                // 将原始点阵的值复制到旋转后的矩阵中
                if (matrix[i][j] == 1) {


                    if (rotatedRow >= 0 &&
                            rotatedRow < rotatedRows &&
                            rotatedColumn >= 0 &&
                            rotatedColumn < rotatedColumns) {

                        if (rotatedMatrix[rotatedRow][rotatedColumn] == 1) {
                            //已经有值了 可能被舍弃掉了 进行加1处理
                            rotatedRow = rotatedRow + 1;
                            rotatedColumn = rotatedColumn + 1;
                            if (rotatedRow < rotatedRows &&
                                    rotatedColumn < rotatedColumns) {
                                rotatedMatrix[rotatedRow][rotatedColumn] = matrix[i][j];
                            }
                        } else {
                            rotatedMatrix[rotatedRow][rotatedColumn] = matrix[i][j];
                        }


                    }
                }

            }
        }

        return rotatedMatrix;
    }


    /**
     * 将 指定左上角位置的点阵数组 添加至 点阵画布数组中
     *
     * @param largeMatrix 点阵画布
     * @param smallMatrix 数据点阵
     * @param startRow    起始行
     * @param startColumn 起始列
     */
    public static void mergeDotMatrices(int[][] largeMatrix, int[][] smallMatrix, int startRow, int startColumn) {

        mergeDotMatricesConfuse(largeMatrix, smallMatrix, startRow, startColumn, 0);
    }

    public static void mergeDotMatrices(int[][] largeMatrix, int[][] smallMatrix, int startRow, int startColumn, int[] type) {

        mergeDotMatricesConfuse(largeMatrix, smallMatrix, startRow, startColumn, 0);
        removeEdgeResidue(largeMatrix, smallMatrix, startRow, startColumn, type);
    }


    public static void removeEdgeResidue(int[][] largeMatrix, int[][] smallMatrix, int startRow, int startColumn, int[] type) {
        removeEdgeResidue(largeMatrix, smallMatrix, startRow, startColumn, type, 1);
    }


    /**
     * 去除 指定点数数组 在 画布数组 中 周边的残影
     *
     * @param largeMatrix
     * @param smallMatrix
     * @param startRow
     * @param startColumn
     * @param type        4位数组,分别为上下左右 new int[]{0,0,0,0},0-为关闭,1-为开启
     */
    public static void removeEdgeResidue(int[][] largeMatrix, int[][] smallMatrix, int startRow, int startColumn, int[] type, int interval) {
        //去除附近的残留
        int startRows = startRow + 1;
        int startColumns = startColumn + 1;

        int endRows = startRow + smallMatrix.length;
        int endColumns = startColumn + smallMatrix[0].length;

        if (endRows > largeMatrix.length) {
            endRows = largeMatrix.length;
        }

        if (endColumns > largeMatrix[0].length) {
            endColumns = largeMatrix[0].length;
        }


        if (type == null) {
            type = new int[4];
        }

        //判断四个方向是否有
        boolean isTop = type[0] == 1;
        boolean isDown = type[1] == 1;
        boolean isLeft = type[2] == 1;
        boolean isRight = type[3] == 1;


        while (isTop || isDown || isLeft || isRight) {

            for (int in = 1; in <= interval; in++) {
                boolean isTopHave = false;
                int i = startRows - in;

                boolean isDownHave = false;
                int i2 = endRows + in;

                //转换为坐标
                i = i - 1;
                i2 = i2 - 1;

                if (i <= 0) {
                    i = 0;
                }

                if (i2 > largeMatrix.length - 1) {
                    i2 = largeMatrix.length - 1;
                }
                if (i > largeMatrix.length - 1) {
                    i = largeMatrix.length - 1;
                }

                for (int j = startColumns - 1; j <= endColumns + 1; j++) {

                    if (j - 1 < 0) {
                        break;
                    }
                    if (j - 1 > largeMatrix[0].length - 1) {
                        break;
                    }

                    if (isTop) {
                        if (largeMatrix[i][j - 1] == 1) {
                            isTopHave = true;
                            largeMatrix[i][j - 1] = 0;
                        }
                    }

                    if (isDown) {
                        if (largeMatrix[i2][j - 1] == 1) {
                            isDownHave = true;
                            largeMatrix[i2][j - 1] = 0;
                        }
                    }

                }

                if (isTopHave && in == interval) {
                    startRows = i + 1;
                }
                isTop = isTopHave;

                if (isDownHave && in == interval) {
                    endRows = i2 + 1;
                }
                isDown = isDownHave;


                boolean isLeftHave = false;
                int j = startColumns - in;

                boolean isRightHave = false;
                int j2 = endColumns + in;


                j = j - 1;
                j2 = j2 - 1;

                if (j < 0) {
                    j = 0;
                }

                if (j2 > largeMatrix[0].length - 1) {
                    j2 = largeMatrix[0].length - 1;
                }
                if (j > largeMatrix[0].length - 1) {
                    j = largeMatrix[0].length - 1;
                }

                for (i = startRows - 1; i <= endRows + 1; i++) {

                    if (i - 1 < 0) {
                        break;
                    }
                    if (i - 1 > largeMatrix.length - 1) {
                        break;
                    }

                    if (isLeft) {
                        if (largeMatrix[i - 1][j] == 1) {
                            isLeftHave = true;
                            largeMatrix[i - 1][j] = 0;
                        }
                    }

                    if (isRight) {
                        if (largeMatrix[i - 1][j2] == 1) {
                            isRightHave = true;
                            largeMatrix[i - 1][j2] = 0;
                        }
                    }
                }

                if (isLeftHave && in == interval) {
                    startColumns = j + 1;
                }
                isLeft = isLeftHave;
                if (isRightHave && in == interval) {
                    endColumns = j2 + 1;
                }
                isRight = isRightHave;
            }
        }


    }

    /**
     * 合并指定大小的画布内容 合并的数组中
     *
     * @param width
     * @param height
     * @param type    0-叠加; 1-后面的覆盖前面的
     * @param canvass
     * @return
     */
    public static int[][] mergeCanvasBitmap(int width, int height, int type, int[][]... canvass) {
        int[][] canvasBitmap = new int[height][width];

        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {

                int a = 0;
                if (type == 0) {
                    //叠加
                    for (int[][] canvas : canvass) {
                        if (canvas.length > i && canvas[0].length > j) {
                            if (canvas[i][j] == 1) {
                                a = 1;
                                break;
                            }
                        }
                    }

                } else if (type == 1) {
                    //后面的覆盖前面的
                    for (int k = canvass.length - 1; k >= 0; k--) {

                        int[][] canvas = canvass[k];
                        if (canvas.length > i && canvas[0].length > j) {
                            a = canvas[i][j];
                            break;
                        }

                    }

                }

                canvasBitmap[i][j] = a;
            }
        }

        return canvasBitmap;
    }

    /**
     * 合并指定大小的画布内容 合并的数组中只要有一个为1 则为1
     *
     * @param width
     * @param height
     * @param canvass
     * @return
     */
    public int[][] mergeCanvasBitmap(int width, int height, int[][]... canvass) {
        int[][] canvasBitmap = new int[height][width];

        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {

                int a = 0;
                for (int[][] canvas : canvass) {
                    if (canvas.length > i && canvas[0].length > j) {
                        if (canvas[i][j] == 1) {
                            a = 1;
                            break;
                        }
                    }
                }
                canvasBitmap[i][j] = a;
            }
        }
        return canvasBitmap;
    }


}
