package com.nmgs.util;

import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

public class PropertiesUtil {
    public static String getValue(String key) {
        String path = PathUtil.applicationPath;
        FileInputStream fIn = null;
        InputStreamReader in = null;
        try {
//            File updateFile = new File(path);
            Properties properties = new Properties();
//            BufferedReader bf = new BufferedReader(new  InputStreamReader(new FileInputStream(path), "gb2312"));
            fIn = new FileInputStream(path);
            in = new InputStreamReader(fIn, "UTF-8");
            BufferedReader bf = new BufferedReader(in);
            properties.load(bf);
            return properties.getProperty(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fIn != null) {
                    fIn.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (Exception e) {
            }
        }
        return "";
    }

    //目标文件
    public File file;
    //目标路径
    public String path;
    //默认字符编码
    public String charset = "UTF-8";
    //文件的每一行
    public String[] lines;
    //注释符
    public static final String ANNOTATION_CHAR = "#";


    public PropertiesUtil(File file) throws IOException {
        this.file = file;
        this.lines = getFileLines(file);
    }

    public PropertiesUtil(String path) throws IOException {
        this.path = path;
        this.lines = getFileLines(path);
    }


    /*
     *  根据键获取值
     *
     * @param key  键
     * @return: java.lang.String
     */
    public String get(String key) {
        for (String line : lines) {
            if (hasKey(line, key)) {
                return getLineValue(line);
            }
        }
        return null;
    }


    /**
     * 添加配置
     *
     * @param key          键
     * @param value        值
     * @param descriptions 字段描述，可添加多个描述
     * @return: boolean
     */
    public boolean add(String key, String value, String... descriptions) {
        List<String> lineList = new ArrayList<>(Arrays.asList(lines));
        for (String description : descriptions) {
            lineList.add(ANNOTATION_CHAR + description);
        }
        lineList.add(key.trim() + "=" + value.trim());
        return commit(lineList.toArray(new String[0]));
    }


    /**
     * 设置键值对
     *
     * @param key   键
     * @param value 值
     * @return: boolean
     */
    public boolean set(String key, String value) {
        boolean isHave = false;
        for (int i = 0; i < lines.length; i++) {
            if (hasKey(lines[i], key)) {
                isHave = true;
                lines[i] = key + "=" + value;
            }
        }
        if (!isHave) {
            add(key, value);
        }
        return commit(lines);
    }

    /**
     * 设置键值对
     *
     * @param key   键
     * @param value 值
     * @return: boolean
     */
    public boolean set(String key, String value, String... descriptions) {
        boolean isHave = false;
        for (int i = 0; i < lines.length; i++) {
            if (hasKey(lines[i], key)) {
                isHave = true;
                lines[i] = key + "=" + value;
                List<String> lineList = new ArrayList<>(Arrays.asList(lines));
                for (String description : descriptions) {
                    while (1 == 1) {
                        if (i - 1 >= 0 && lineList.get(i - 1).toString().contains("#")) {
                            lineList.remove(i - 1);
                            i = i - 1;
                        } else {
                            break;
                        }
                    }
                    lineList.add(i, ANNOTATION_CHAR + description);
                }
                lines = lineList.toArray(new String[0]);
                break;
            }
        }
        if (!isHave) {
            add(key, value, descriptions);
        }
        return commit(lines);
    }

    /*
     *  删除键值对
     *
     * @param key  键
     * @return: boolean
     */
    public boolean delete(String key) {
        List<String> lineList = new ArrayList<>(Arrays.asList(lines));
        lineList.removeIf(line -> hasKey(line, key));
        return commit(lineList.toArray(new String[0]));
    }

    /*
     *  保存文件
     *
     * @param lines 文件每一行
     * @return: boolean
     */
    public boolean commit(String[] lines) {
        synchronized (this) {
            this.lines = lines;
            try (BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset))) {
                StringBuilder data = new StringBuilder();
                for (String line : lines) {
                    data.append(line).append('\n');
                }
                bufferedWriter.write(data.toString());
                return true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }


    /*
     *  获取一行中的 key 值
     *
     * @param line  目标行
     * @return: java.lang.String
     */
    public String getLineKey(String line) {
        return line.substring(0, line.indexOf('=')).trim();
    }

    /**
     * 获取一行中的 value 值
     *
     * @param line 目标行
     * @return: java.lang.String
     */

    public String getLineValue(String line) {
        return line.substring(line.indexOf('=') + 1).trim();
    }


    /**
     * 如果是键值对行(不以 # 开头，并且包含 = 符号)，则返回 true ，如果是注释行则返回 false。
     *
     * @return: boolean
     */
    public boolean isValidLine(String line) {
        return !line.trim().startsWith("#") && line.contains("=");
    }

    /**
     * 判断一行中是否有key 键
     *
     * @param line 目标行
     * @param key  目标键
     * @return: boolean
     */
    public boolean hasKey(String line, String key) {
        return isValidLine(line) && key.equals(getLineKey(line));
    }

    public boolean hasKey(String key) {
        List<String> lineList = new ArrayList<>(Arrays.asList(lines));
        for (int i = 0; i < lineList.size(); i++) {
            String line = lineList.get(i);
            if (hasKey(line, key)) {
                return true;
            }
            if (i == lineList.size() - 1) {
                return false;
            }
        }
        return false;
    }

    /**
     * 获取文件的每一行
     *
     * @param file 目标文件
     * @return: java.lang.String[]
     */
    public String[] getFileLines(File file) {

        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charset));) {
            String line;
            List<String> lines = new ArrayList<>();
            while ((line = bufferedReader.readLine()) != null) {
                lines.add(line);
            }
            return lines.toArray(new String[0]);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取文件的每一行，如果路径不存在，则读取 resource 路径下的文件，如果resource路径不存在，则抛出IOException异常
     *
     * @param path 目标路径
     * @return: java.lang.String[]
     */
    public String[] getFileLines(String path) throws IOException {
        File file = new File(path);
        if (file.isFile()) {
            this.file = file;
            return getFileLines(file);
        } else {
            URL url = getClass().getClassLoader().getResource(path);
            if (url == null) {
                throw new FileNotFoundException("resource path is not found");
            }
            file = new File(url.getPath());
            if (file.isFile()) {
                this.file = file;
                return getFileLines(file);
            } else {
                throw new FileNotFoundException("properties file is not found");
            }
        }
    }


    // Type conversion

    public boolean getBoolean(String key) {
        return Boolean.parseBoolean(get(key));
    }

    public int getInt(String key) {
        return Integer.parseInt(get(key));
    }

    public float getFloat(String key) {
        return Float.parseFloat(get(key));
    }

    public double getDouble(String key) {
        return Double.parseDouble(get(key));
    }

    public short getShort(String key) {
        return Short.parseShort(get(key));
    }

    public long getLong(String key) {
        return Long.parseLong(get(key));
    }

    //getter and setter

    public File getFile() {
        return file;
    }

    public void setFile(File file) {
        this.file = file;
    }

    public String getCharset() {
        return charset;
    }

    public void setCharset(String charset) {
        this.charset = charset;
    }

    public String[] getLines() {
        return lines;
    }

    public void setLines(String[] lines) {
        this.lines = lines;
    }

}
