package com.acgist.snail.config;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import com.acgist.snail.context.TaskContext;
import com.acgist.snail.logger.Logger;
import com.acgist.snail.logger.LoggerFactory;
import com.acgist.snail.utils.FileUtils;
import com.acgist.snail.utils.StringUtils;

/**
 * 下载配置
 * 
 * @author acgist
 */
public final class DownloadConfig extends PropertiesConfig {

    private static final Logger LOGGER = LoggerFactory.getLogger(DownloadConfig.class);
    
    /**
     * 下载配置文件
     */
    public static final String DOWNLOAD_CONFIG = "/config/download.properties";
    /**
     * 下载速度和上传速度的比例
     * 比例计算公式 = {@link #downloadBufferByte} / {@link #uploadBufferByte}
     */
    private static final int DOWNLOAD_UPLOAD_SCALE = 4;
    /**
     * 下载目录配置名称
     * 
     * @see #path
     */
    private static final String DOWNLOAD_PATH = "acgist.download.path";
    /**
     * 下载数量配置名称
     * 
     * @see #size
     */
    private static final String DOWNLOAD_SIZE = "acgist.download.size";
    /**
     * 消息提示配置名称
     * 
     * @see #notice
     */
    private static final String DOWNLOAD_NOTICE = "acgist.download.notice";
    /**
     * 删除文件配置名称
     * 
     * @see #delete
     */
    private static final String DOWNLOAD_DELETE = "acgist.download.delete";
    /**
     * 下载速度（单个）（KB）配置名称
     * 
     * @see #buffer
     */
    private static final String DOWNLOAD_BUFFER = "acgist.download.buffer";
    /**
     * 最后一次选择目录配置名称
     * 
     * @see #lastPath
     */
    private static final String DOWNLOAD_LAST_PATH = "acgist.download.last.path";
    /**
     * 磁盘缓存（单个）（MB）配置名称
     * 
     * @see #memoryBuffer
     */
    private static final String DOWNLOAD_MEMORY_BUFFER = "acgist.download.memory.buffer";
    
    /**
     * 下载目录
     */
    private String path;
    /**
     * 下载数量
     */
    private int size;
    /**
     * 消息提示
     */
    private boolean notice;
    /**
     * 删除文件
     */
    private boolean delete;
    /**
     * 下载速度（单个）（KB）
     */
    private int buffer;
    /**
     * 上传速度（单个）（B）
     * 
     * @see #buffer
     */
    private int uploadBufferByte;
    /**
     * 下载速度（单个）（B）
     * 
     * @see #buffer
     */
    private int downloadBufferByte;
    /**
     * 最后一次选择目录
     */
    private String lastPath;
    /**
     * 磁盘缓存（单个）（MB）
     */
    private int memoryBuffer;
    /**
     * 磁盘缓存（单个）（B）
     * 
     * @see #memoryBuffer
     */
    private int memoryBufferByte;
    
    private static final DownloadConfig INSTANCE = new DownloadConfig();
    
    public static final DownloadConfig getInstance() {
        return INSTANCE;
    }
    
    private DownloadConfig() {
        super(DOWNLOAD_CONFIG);
        this.init();
        this.release();
        this.refreshBuffer();
        this.refreshMemoryBuffer();
    }
    
    @Override
    public void init() {
        // 加载配置
        this.path         = this.getString(DOWNLOAD_PATH);
        this.size         = this.getInteger(DOWNLOAD_SIZE, 4);
        this.notice       = this.getBoolean(DOWNLOAD_NOTICE, true);
        this.delete       = this.getBoolean(DOWNLOAD_DELETE, false);
        this.buffer       = this.getInteger(DOWNLOAD_BUFFER, 1024);
        this.lastPath     = this.getString(DOWNLOAD_LAST_PATH);
        this.memoryBuffer = this.getInteger(DOWNLOAD_MEMORY_BUFFER, 8);
        // 记录日志
        LOGGER.debug("下载目录：{}", this.path);
        LOGGER.debug("下载数量：{}", this.size);
        LOGGER.debug("消息提示：{}", this.notice);
        LOGGER.debug("删除文件：{}", this.delete);
        LOGGER.debug("下载速度（单个）（KB）：{}", this.buffer);
        LOGGER.debug("最后一次选择目录：{}", this.lastPath);
        LOGGER.debug("磁盘缓存（单个）（MB）：{}", this.memoryBuffer);
    }
    
    @Override
    public void persistent() {
        final Map<String, String> data = new HashMap<>();
        data.put(DOWNLOAD_PATH, this.path);
        data.put(DOWNLOAD_SIZE, Objects.toString(this.size, "4"));
        data.put(DOWNLOAD_NOTICE, Objects.toString(this.notice, "true"));
        data.put(DOWNLOAD_DELETE, Objects.toString(this.delete, "false"));
        data.put(DOWNLOAD_BUFFER, Objects.toString(this.buffer, "1024"));
        data.put(DOWNLOAD_LAST_PATH, this.lastPath);
        data.put(DOWNLOAD_MEMORY_BUFFER, Objects.toString(this.memoryBuffer, "8"));
        this.persistent(data, DOWNLOAD_CONFIG);
    }
    
    /**
     * @param path 下载目录
     */
    public static final void setPath(String path) {
        if(StringUtils.equals(INSTANCE.path, path)) {
            return;
        }
        INSTANCE.path = path;
        INSTANCE.persistent();
    }
    
    /**
     * 下载目录存在：下载目录
     * 下载目录无效：用户工作目录 + 下载目录
     * 
     * @return 下载目录
     * 
     * @see FileUtils#userDir(String)
     */
    public static final String getPath() {
        final File file = new File(INSTANCE.path);
        if(file.exists() && file.isDirectory()) {
            return INSTANCE.path;
        }
        final String path = FileUtils.userDir(INSTANCE.path);
        FileUtils.buildFolder(path);
        return path;
    }

    /**
     * @param fileName 文件名称
     * 
     * @return 下载目录中的文件路径
     */
    public static final String getPath(String fileName) {
        if(StringUtils.isEmpty(fileName)) {
            throw new IllegalArgumentException("文件名称格式错误：" + fileName);
        }
        return FileUtils.file(DownloadConfig.getPath(), fileName);
    }
    
    /**
     * @param size 下载数量
     */
    public static final void setSize(int size) {
        if(INSTANCE.size == size) {
            return;
        }
        INSTANCE.size = size;
        INSTANCE.persistent();
        TaskContext.getInstance().refresh();
    }

    /**
     * @return 下载数量
     */
    public static final int getSize() {
        return INSTANCE.size;
    }
    
    /**
     * @param notice 是否提示消息
     */
    public static final void setNotice(boolean notice) {
        if(INSTANCE.notice == notice) {
            return;
        }
        INSTANCE.notice = notice;
        INSTANCE.persistent();
    }

    /**
     * @return 是否提示消息
     */
    public static final boolean getNotice() {
        return INSTANCE.notice;
    }
    
    /**
     * @param delete 是否删除文件
     */
    public static final void setDelete(boolean delete) {
        if(INSTANCE.delete == delete) {
            return;
        }
        INSTANCE.delete = delete;
        INSTANCE.persistent();
    }
    
    /**
     * @return 是否删除文件
     */
    public static final boolean getDelete() {
        return INSTANCE.delete;
    }
    
    /**
     * @param buffer 下载速度（单个）（KB）
     */
    public static final void setBuffer(int buffer) {
        if(INSTANCE.buffer == buffer) {
            return;
        }
        INSTANCE.buffer = buffer;
        INSTANCE.persistent();
        INSTANCE.refreshBuffer();
    }
    
    /**
     * 刷新下载速度和上传速度
     */
    private void refreshBuffer() {
        this.downloadBufferByte = this.buffer * SystemConfig.ONE_KB;
        this.uploadBufferByte   = this.downloadBufferByte / DOWNLOAD_UPLOAD_SCALE;
    }
    
    /**
     * @return 下载速度（单个）（KB）
     */
    public static final int getBuffer() {
        return INSTANCE.buffer;
    }
    
    /**
     * @return 上传速度（单个）（B）
     */
    public static final int getUploadBufferByte() {
        return INSTANCE.uploadBufferByte;
    }
    
    /**
     * @return 下载速度（单个）（B）
     */
    public static final int getDownloadBufferByte() {
        return INSTANCE.downloadBufferByte;
    }
    
    /**
     * @param lastPath 最后一次选择目录
     */
    public static final void setLastPath(String lastPath) {
        if(StringUtils.equals(INSTANCE.lastPath, lastPath)) {
            return;
        }
        INSTANCE.lastPath = lastPath;
        INSTANCE.persistent();
    }
    
    /**
     * 如果最后一次选择目录为空返回下载目录
     * 
     * @return 最后一次选择目录
     * 
     * @see #getPath()
     */
    public static final String getLastPath() {
        if(StringUtils.isEmpty(INSTANCE.lastPath)) {
            return DownloadConfig.getPath();
        }
        final File file = new File(INSTANCE.lastPath);
        if(file.exists() && file.isDirectory()) {
            return INSTANCE.lastPath;
        }
        return DownloadConfig.getPath();
    }
    
    /**
     * @return 最后一次选择目录文件
     */
    public static final File getLastPathFile() {
        return new File(DownloadConfig.getLastPath());
    }
    
    /**
     * @param memoryBuffer 磁盘缓存（单个）（MB）
     */
    public static final void setMemoryBuffer(int memoryBuffer) {
        if(INSTANCE.memoryBuffer == memoryBuffer) {
            return;
        }
        INSTANCE.memoryBuffer = memoryBuffer;
        INSTANCE.persistent();
        INSTANCE.refreshMemoryBuffer();
    }

    /**
     * 刷新磁盘缓存
     */
    private void refreshMemoryBuffer() {
        this.memoryBufferByte = this.memoryBuffer * SystemConfig.ONE_MB;
    }
    
    /**
     * @return 磁盘缓存（单个）（MB）
     */
    public static final int getMemoryBuffer() {
        return INSTANCE.memoryBuffer;
    }

    /**
     * @return 磁盘缓存（单个）（B）
     */
    public static final int getMemoryBufferByte() {
        return INSTANCE.memoryBufferByte;
    }
    
    /**
     * @param fileSize 默认文件大小（B）
     * 
     * @return 磁盘缓存（单个）（B）
     */
    public static final int getMemoryBufferByte(final long fileSize) {
        final int bufferSize = DownloadConfig.getMemoryBufferByte();
        if(fileSize > 0L) {
            if(bufferSize > fileSize) {
                // 如果文件大小小于磁盘缓存直接使用文件大小作为缓存大小
                return (int) fileSize;
            } else {
                return bufferSize;
            }
        }
        return bufferSize;
    }
    
}
