content: package com.acgist.snail.config;
  
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.io.OutputStreamWriter;
  import java.io.Reader;
  import java.io.Writer;
  import java.nio.charset.StandardCharsets;
  import java.util.Map;
  import java.util.Properties;
  
  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 abstract class PropertiesConfig {
      
      private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesConfig.class);
      
      /**
       * 配置信息
       */
      protected final Properties properties;
  
      /**
       * 加载配置文件
       * 
       * @param path 配置文件相对路径
       */
      protected PropertiesConfig(String path) {
          LOGGER.debug("加载配置文件：{}", path);
          this.properties = PropertiesConfig.load(path);
      }
      
      /**
       * 加载配置文件
       * 
       * @param path 配置文件相对路径
       * 
       * @return 配置信息
       * 
       * @see #loadFromUserDir(String)
       * @see #loadFromResource(String)
       */
      private static final Properties load(String path) {
          Properties properties = PropertiesConfig.loadFromUserDir(path);
          if(properties == null) {
              properties = PropertiesConfig.loadFromResource(path);
          }
          if(properties == null) {
              LOGGER.warn("加载配置文件失败：{}", path);
          }
          return properties;
      }
      
      /**
       * 加载用户工作目录配置（UserDir）
       * 
       * @param path 配置文件相对路径
       * 
       * @return 配置信息
       */
      private static final Properties loadFromUserDir(String path) {
          final File file = FileUtils.userDirFile(path);
          if(file == null || !file.exists()) {
              return null;
          }
          Properties properties = null;
          try(final Reader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
              properties = new Properties();
              properties.load(reader);
          } catch (IOException e) {
              LOGGER.error("读取配置文件异常：{}", path, e);
          }
          return properties;
      }
      
      /**
       * 加载默认配置（Resource）
       * 
       * @param path 配置文件相对路径
       * 
       * @return 配置信息
       */
      private static final Properties loadFromResource(String path) {
          if(PropertiesConfig.class.getResource(path) == null) {
              return null;
          }
          Properties properties = null;
          try(final Reader reader = new InputStreamReader(PropertiesConfig.class.getResourceAsStream(path), StandardCharsets.UTF_8)) {
              properties = new Properties();
              properties.load(reader);
          } catch (IOException e) {
              LOGGER.error("读取配置文件异常：{}", path, e);
          }
          return properties;
      }
  
      /**
       * 保存配置文件
       * 
       * @param data 数据
       * @param path 路径
       */
      protected final void persistent(Map<String, String> data, String path) {
          if(data == null || path == null) {
              LOGGER.warn("保存配置文件失败：{} - {}", data, path);
              return;
          }
          final File file = FileUtils.userDirFile(path);
          FileUtils.buildParentFolder(file);
          try(final Writer writer = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
              final Properties properties = new Properties();
              properties.putAll(data);
              properties.store(writer, SystemConfig.getName());
          } catch (IOException e) {
              LOGGER.error("保存配置文件异常：{}", file, e);
          }
      }
      
      /**
       * @param name 配置名称
       * 
       * @return 配置值
       */
      protected final String getString(String name) {
          final String value = this.properties == null ? null : this.properties.getProperty(name);
          if(value == null) {
              LOGGER.debug("配置没有默认设置：{}", name);
          }
          return value;
      }
      
      /**
       * @param name         配置名称
       * @param defaultValue 默认值
       * 
       * @return 配置值
       */
      protected final String getString(String name, String defaultValue) {
          final String value = this.getString(name);
          return value == null ? defaultValue : value;
      }
      
      /**
       * @param name 配置名称
       * 
       * @return 配置值
       */
      protected final Boolean getBoolean(String name) {
          final String value = this.getString(name);
          if(Boolean.TRUE.toString().equalsIgnoreCase(value)) {
              return Boolean.TRUE;
          } else if(Boolean.FALSE.toString().equalsIgnoreCase(value)) {
              return Boolean.FALSE;
          } else {
              return null;
          }
      }
      
      /**
       * @param name         配置名称
       * @param defaultValue 默认值
       * 
       * @return 配置值
       */
      protected final boolean getBoolean(String name, boolean defaultValue) {
          final Boolean value = this.getBoolean(name);
          return value == null ? defaultValue : value;
      }
  
      /**
       * @param name 配置名称
       * 
       * @return 配置值
       */
      protected final Integer getInteger(String name) {
          final String value = this.getString(name);
          if(StringUtils.isNumeric(value)) {
              return Integer.valueOf(value);
          }
          return null;
      }
      
      /**
       * @param name         配置名称
       * @param defaultValue 默认值
       * 
       * @return 配置值
       */
      protected final int getInteger(String name, int defaultValue) {
          final Integer value = this.getInteger(name);
          return value == null ? defaultValue : value;
      }
  
      /**
       * 加载配置
       */
      public void init() {
      }
      
      /**
       * 保存配置
       */
      public void persistent() {
      }
      
      /**
       * 释放配置
       */
      protected final void release() {
          this.properties.clear();
      }
      
  }
  