package cn.reghao.devops.mgr.util.codelines;

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;

/**
 * 统计代码行数
 *
 * @author reghao
 * @date 2021-08-10 下午4:54
 */
public class LinesOfCode {
    private String projectDir;
    private int totalLines;
    private int totalFiles;
    private Matcher matcher;

    /**
     *
     *
     * @param projectDir 项目路径
     * @param matcher 源代码类型
     * @date 2021-08-10 下午4:55
     */
    public LinesOfCode(String projectDir, Matcher matcher) {
        this.projectDir = projectDir;
        this.matcher = matcher;
        this.totalLines = 0;
        this.totalFiles = 0;
    }

    /**
     * 代码总行数
     *
     * @return 代码总行数
     * @date 2021-08-10 下午4:55
     */
    public int totalLines() {
        return totalLines;
    }

    /**
     * 源文件数量
     *
     * @return 源文件数量
     * @date 2021-08-10 下午4:55
     */
    public int totalFiles() {
        return totalFiles;
    }

    /**
     * 计算代码总行数和源文件数量
     *
     * @date 2021-08-10 下午4:55
     */
    public int calculate() {
        Path path = Paths.get(projectDir);
        try {
            walkDir(path);
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }

        return totalLines;
    }

    /**
     * 遍历目录树并处理文件
     *
     * @param path 目录根路径
     * @date 2021-08-10 下午4:55
     */
    private void walkDir(Path path) throws IOException {
        final String BLANK = "";
        if (path.toString().equals(BLANK)) {
            throw new IOException("CAN NOT specify a BLANK path");
        }

        Files.walkFileTree(path, new FileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                String suffix = fileSuffix(file.toString());
                if (matcher.matchSuffix(suffix)) {
                    totalLines += linesOfFile(file.toFile(), matcher);;
                    totalFiles++;
                }

                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                return FileVisitResult.CONTINUE;
            }
        });
    }

    /**
     * 统计源文件包含多少行代码
     *
     * @param file 源文件
     * @param matcher 匹配器
     * @return 每个源文件包含的代码行数
     * @date 2021-08-10 下午4:55
     */
    private int linesOfFile(File file, Matcher matcher) {
        int count = 0;
        try {
            BufferedReader in =  new BufferedReader(new InputStreamReader(new FileInputStream(file)));
            String line;
            while ((line = in.readLine()) != null) {
                if (!matcher.match(line)) {
                    count++;
                }
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }

        return count;
    }

    /**
     * 获取文件的后缀名
     *
     * @param filePath 文件路径
     * @return 文件后缀名
     * @date 2021-08-10 下午4:55
     */
    private String fileSuffix(String filePath) {
        String[] paths = filePath.split("/");
        String file = paths[paths.length-1];

        if (file.contains(".")) {
            return file.split("\\.")[1];
        } else {
            return "";
        }
    }
}
