content: package com.acgist.snail.config;
  
  import com.acgist.snail.logger.Logger;
  import com.acgist.snail.logger.LoggerFactory;
  import com.acgist.snail.net.PacketSizeException;
  import com.acgist.snail.utils.NetUtils;
  
  /**
   * 系统配置
   * 
   * @author acgist
   */
  public final class SystemConfig extends PropertiesConfig {
  
      private static final Logger LOGGER = LoggerFactory.getLogger(SystemConfig.class);
      
      /**
       * 配置文件
       */
      public static final String SYSTEM_CONFIG = "/config/system.properties";
      /**
       * 端口占用字节大小
       */
      public static final int PORT_LENGHT = 2;
      /**
       * IPv4占用字节大小
       */
      public static final int IPV4_LENGTH = 4;
      /**
       * IPv6占用字节大小
       */
      public static final int IPV6_LENGTH = 16;
      /**
       * IPv4端口占用字节大小
       */
      public static final int IPV4_PORT_LENGTH = IPV4_LENGTH + PORT_LENGHT;
      /**
       * IPv6端口占用字节大小
       */
      public static final int IPV6_PORT_LENGTH = IPV6_LENGTH + PORT_LENGHT;
      /**
       * 强制关闭程序定时任务时间（单位：秒）
       */
      public static final int SHUTDOWN_FORCE_TIME = 30;
      /**
       * 数据大小比例
       */
      public static final int DATA_SCALE = 1024;
      /**
       * 1KB数据大小
       * 1KB = 1024B
       */
      public static final int ONE_KB = DATA_SCALE;
      /**
       * 1MB数据大小
       * 1MB = 1024KB = 1024 * 1024B
       */
      public static final int ONE_MB = DATA_SCALE * ONE_KB;
      /**
       * TCP消息缓冲大小
       */
      public static final int TCP_BUFFER_LENGTH = 16 * ONE_KB;
      /**
       * UDP消息缓存大小
       */
      public static final int UDP_BUFFER_LENGTH = 2 * ONE_KB;
      /**
       * 最大的网络包大小
       * 校验网络数据大小：防止太长导致内存泄漏
       * 
       * @see PacketSizeException
       */
      public static final int MAX_NET_BUFFER_LENGTH = 4 * ONE_MB;
      /**
       * 最小下载速度（KB）
       */
      public static final int MIN_DOWNLOAD_BUFFER_KB = 16;
      /**
       * 默认数据传输大小
       * 用作默认缓存大小
       * 
       * @see #MIN_DOWNLOAD_BUFFER_KB
       */
      public static final int DEFAULT_EXCHANGE_LENGTH = MIN_DOWNLOAD_BUFFER_KB * ONE_KB;
      /**
       * 时间比例
       */
      public static final int DATE_SCALE = 1000;
      /**
       * 一秒钟（毫秒）
       */
      public static final int ONE_SECOND_MILLIS = DATE_SCALE;
      /**
       * 没有超时时间
       */
      public static final int NONE_TIMEOUT = 0;
      /**
       * 连接超时时间（秒）
       */
      public static final int CONNECT_TIMEOUT = 5;
      /**
       * 连接超时时间（毫秒）
       */
      public static final int CONNECT_TIMEOUT_MILLIS = CONNECT_TIMEOUT * ONE_SECOND_MILLIS;
      /**
       * 接收超时时间（秒）
       */
      public static final int RECEIVE_TIMEOUT = 5;
      /**
       * 接收超时时间（毫秒）
       */
      public static final int RECEIVE_TIMEOUT_MILLIS = RECEIVE_TIMEOUT * ONE_SECOND_MILLIS;
      /**
       * 下载超时时间（秒）
       */
      public static final int DOWNLOAD_TIMEOUT = 30;
      /**
       * 下载超时时间（毫秒）
       */
      public static final int DOWNLOAD_TIMEOUT_MILLIS = DOWNLOAD_TIMEOUT * ONE_SECOND_MILLIS;
      /**
       * 刷新时间（秒）
       * 任务列表、速度统计
       */
      public static final int REFRESH_INTERVAL = 5;
      /**
       * 刷新时间（毫秒）
       */
      public static final int REFRESH_INTERVAL_MILLIS = REFRESH_INTERVAL * ONE_SECOND_MILLIS;
      /**
       * SHA-1散列值长度
       */
      public static final int SHA1_HASH_LENGTH = 20;
      /**
       * GBK编码
       */
      public static final String CHARSET_GBK = "GBK";
      /**
       * UTF-8编码
       */
      public static final String CHARSET_UTF8 = "UTF-8";
      /**
       * ASCII编码
       */
      public static final String CHARSET_ASCII = "ASCII";
      /**
       * ISO-8859-1编码
       */
      public static final String CHARSET_ISO_8859_1 = "ISO-8859-1";
      /**
       * 系统默认编码
       * 启动参数：-D file.encoding=UTF-8
       */
      public static final String DEFAULT_CHARSET = CHARSET_UTF8;
      
      /**
       * 软件名称
       */
      private String name;
      /**
       * 软件名称（英文）
       */
      private String nameEn;
      /**
       * 软件版本
       */
      private String version;
      /**
       * FTP匿名用户
       */
      private String ftpUser;
      /**
       * FTP匿名密码
       */
      private String ftpPassword;
      /**
       * 作者
       */
      private String author;
      /**
       * 官网与源码
       */
      private String source;
      /**
       * 问题与建议
       */
      private String support;
      /**
       * 最新稳定版本
       */
      private String latestRelease;
      /**
       * STUN服务器
       * 地址：host
       * 地址端口：host:port
       * 协议类型地址：stun:host
       * 协议类型地址端口：stun:host:port
       */
      private String stunServer;
      /**
       * 系统服务端口（本地服务：启动检测）
       */
      private int servicePort;
      /**
       * BT服务端口（本地端口：Peer、DHT、UTP、STUN）
       */
      private int torrentPort;
      /**
       * BT服务端口（外网端口：Peer、DHT、UTP、STUN）
       */
      private int torrentPortExt = 0;
      /**
       * 单个任务Peer数量（同时下载）
       */
      private int peerSize;
      /**
       * 单个任务Tracker数量
       */
      private int trackerSize;
      /**
       * 任务即将完成时可以重复下载的Piece数量
       */
      private int pieceRepeatSize;
      /**
       * DHT执行周期（秒）
       */
      private int dhtInterval;
      /**
       * PEX执行周期（秒）
       */
      private int pexInterval;
      /**
       * 本地发现执行周期（秒）
       */
      private int lsdInterval;
      /**
       * Have消息执行周期（秒）
       */
      private int haveInterval;
      /**
       * Stun消息执行周期（秒）
       */
      private int stunInterval;
      /**
       * Tracker执行周期（秒）
       */
      private int trackerInterval;
      /**
       * Peer（连接、接入）优化周期（秒）
       */
      private int peerOptimizeInterval;
      /**
       * 软件信息
       * 
       * @see #nameEn
       * @see #version
       */
      private String nameEnAndVersion;
      /**
       * 外网IP地址
       */
      private String externalIPAddress;
      /**
       * 外网IP地址是否是IPv4
       */
      private boolean externalIPAddressIPv4 = true;
      
      private static final SystemConfig INSTANCE = new SystemConfig();
      
      public static final SystemConfig getInstance() {
          return INSTANCE;
      }
      
      private SystemConfig() {
          super(SYSTEM_CONFIG);
          this.init();
          this.release();
      }
      
      @Override
      public void init() {
          // 加载配置
          this.name                 = this.getString("acgist.system.name");
          this.nameEn               = this.getString("acgist.system.name.en");
          this.version              = this.getString("acgist.system.version");
          this.ftpUser              = this.getString("acgist.system.ftp.user");
          this.ftpPassword          = this.getString("acgist.system.ftp.password");
          this.author               = this.getString("acgist.system.author");
          this.source               = this.getString("acgist.system.source");
          this.support              = this.getString("acgist.system.support");
          this.latestRelease        = this.getString("acgist.system.latest.release");
          this.stunServer           = this.getString("acgist.system.stun.server");
          this.servicePort          = this.getInteger("acgist.system.service.port", 16888);
          this.torrentPort          = this.getInteger("acgist.system.torrent.port", 18888);
          this.peerSize             = this.getInteger("acgist.system.peer.size", 20);
          this.trackerSize          = this.getInteger("acgist.system.tracker.size", 50);
          this.pieceRepeatSize      = this.getInteger("acgist.system.piece.repeat.size", 8);
          this.dhtInterval          = this.getInteger("acgist.system.dht.interval", 120);
          this.pexInterval          = this.getInteger("acgist.system.pex.interval", 120);
          this.lsdInterval          = this.getInteger("acgist.system.lsd.interval", 120);
          this.haveInterval         = this.getInteger("acgist.system.have.interval", 30);
          this.stunInterval         = this.getInteger("acgist.system.stun.interval", 30);
          this.trackerInterval      = this.getInteger("acgist.system.tracker.interval", 120);
          this.peerOptimizeInterval = this.getInteger("acgist.system.peer.optimize.interval", 60);
          this.nameEnAndVersion     = SymbolConfig.Symbol.SPACE.join(this.nameEn, this.version);
          // 记录日志
          LOGGER.debug("软件名称：{}", this.name);
          LOGGER.debug("软件名称（英文）：{}", this.nameEn);
          LOGGER.debug("软件版本：{}", this.version);
          LOGGER.debug("FTP匿名用户：{}", this.ftpUser);
          LOGGER.debug("FTP匿名密码：{}", this.ftpPassword);
          LOGGER.debug("作者：{}", this.author);
          LOGGER.debug("官网与源码：{}", this.source);
          LOGGER.debug("问题与建议：{}", this.support);
          LOGGER.debug("最新稳定版本：{}", this.latestRelease);
          LOGGER.debug("STUN服务器：{}", this.stunServer);
          LOGGER.debug("系统服务端口（本地服务：启动检测）：{}", this.servicePort);
          LOGGER.debug("BT服务端口（本地端口：Peer、DHT、UTP、STUN）：{}", this.torrentPort);
          LOGGER.debug("单个任务Peer数量（同时下载）：{}", this.peerSize);
          LOGGER.debug("单个任务Tracker数量：{}", this.trackerSize);
          LOGGER.debug("任务即将完成时可以重复下载的Piece数量：{}", this.pieceRepeatSize);
          LOGGER.debug("DHT执行周期（秒）：{}", this.dhtInterval);
          LOGGER.debug("PEX执行周期（秒）：{}", this.pexInterval);
          LOGGER.debug("本地发现执行周期（秒）：{}", this.lsdInterval);
          LOGGER.debug("Have消息执行周期（秒）：{}", this.haveInterval);
          LOGGER.debug("Stun消息执行周期（秒）：{}", this.stunInterval);
          LOGGER.debug("Tracker执行周期（秒）：{}", this.trackerInterval);
          LOGGER.debug("Peer（连接、接入）优化周期（秒）：{}", this.peerOptimizeInterval);
          LOGGER.debug("软件信息：{}", this.nameEnAndVersion);
      }
  
      /**
       * @return 软件名称
       */
      public static final String getName() {
          return INSTANCE.name;
      }
  
      /**
       * @return 软件名称（英文）
       */
      public static final String getNameEn() {
          return INSTANCE.nameEn;
      }
  
      /**
       * @return 软件版本
       */
      public static final String getVersion() {
          return INSTANCE.version;
      }
  
      /**
       * @return FTP匿名用户
       */
      public static final String getFtpUser() {
          return INSTANCE.ftpUser;
      }
  
      /**
       * @return FTP匿名密码
       */
      public static final String getFtpPassword() {
          return INSTANCE.ftpPassword;
      }
      
      /**
       * @return 作者
       */
      public static final String getAuthor() {
          return INSTANCE.author;
      }
  
      /**
       * @return 官网与源码
       */
      public static final String getSource() {
          return INSTANCE.source;
      }
  
      /**
       * @return 问题与建议
       */
      public static final String getSupport() {
          return INSTANCE.support;
      }
      
      /**
       * @return 最新稳定版本
       */
      public static final String getLatestRelease() {
          return INSTANCE.latestRelease;
      }
  
      /**
       * @return STUN服务器
       */
      public static final String getStunServer() {
          return INSTANCE.stunServer;
      }
      
      /**
       * @return 系统服务端口（本地服务：启动检测）
       */
      public static final int getServicePort() {
          return INSTANCE.servicePort;
      }
  
      /**
       * @return BT服务端口（本地端口：Peer、DHT、UTP、STUN）
       */
      public static final int getTorrentPort() {
          return INSTANCE.torrentPort;
      }
      
      /**
       * @param torrentPort BT服务端口（本地端口：Peer、DHT、UTP、STUN）
       */
      public static final void setTorrentPort(int torrentPort) {
          INSTANCE.torrentPort = torrentPort;
          
      }
      
      /**
       * @return BT服务端口（外网端口：Peer、DHT、UTP、STUN）
       * 
       * @see #getTorrentPort()
       */
      public static final int getTorrentPortExt() {
          if(INSTANCE.torrentPortExt == 0) {
              return SystemConfig.getTorrentPort();
          }
          return INSTANCE.torrentPortExt;
      }
      
      /**
       * @param torrentPortExt BT服务端口（外网端口：Peer、DHT、UTP、STUN）
       */
      public static final void setTorrentPortExt(int torrentPortExt) {
          LOGGER.debug("设置BT服务端口（外网端口：Peer、DHT、UTP、STUN）：{}", torrentPortExt);
          INSTANCE.torrentPortExt = torrentPortExt;
      }
      
      /**
       * @return BT服务端口（外网端口：Peer、DHT、UTP、STUN）
       */
      public static final short getTorrentPortExtShort() {
          return NetUtils.portToShort(SystemConfig.getTorrentPortExt());
      }
      
      /**
       * @return 单个任务Peer数量（同时下载）
       */
      public static final int getPeerSize() {
          return INSTANCE.peerSize;
      }
      
      /**
       * @return 单个任务Tracker数量
       */
      public static final int getTrackerSize() {
          return INSTANCE.trackerSize;
      }
  
      /**
       * @return 任务即将完成时可以重复下载的Piece数量
       */
      public static final int getPieceRepeatSize() {
          return INSTANCE.pieceRepeatSize;
      }
      
      /**
       * @return DHT执行周期（秒）
       */
      public static final int getDhtInterval() {
          return INSTANCE.dhtInterval;
      }
      
      /**
       * @return PEX执行周期（秒）
       */
      public static final int getPexInterval() {
          return INSTANCE.pexInterval;
      }
      
      /**
       * @return 本地发现执行周期（秒）
       */
      public static final int getLsdInterval() {
          return INSTANCE.lsdInterval;
      }
      
      /**
       * @return Have消息执行周期（秒）
       */
      public static final int getHaveInterval() {
          return INSTANCE.haveInterval;
      }
      
      /**
       * @return Stun消息执行周期（秒）
       */
      public static final int getStunInterval() {
          return INSTANCE.stunInterval;
      }
      
      /**
       * @return Tracker执行周期（秒）
       */
      public static final int getTrackerInterval() {
          return INSTANCE.trackerInterval;
      }
      
      /**
       * @return Peer（连接、接入）优化周期（秒）
       */
      public static final int getPeerOptimizeInterval() {
          return INSTANCE.peerOptimizeInterval;
      }
  
      /**
       * @return 软件信息
       */
      public static final String getNameEnAndVersion() {
          return INSTANCE.nameEnAndVersion;
      }
  
      /**
       * @param externalIPAddress 外网IP地址
       */
      public static final void setExternalIPAddress(String externalIPAddress) {
          LOGGER.debug("设置外网IP地址：{}", externalIPAddress);
          INSTANCE.externalIPAddress     = externalIPAddress;
          INSTANCE.externalIPAddressIPv4 = NetUtils.ipv4(externalIPAddress);
      }
      
      /**
       * @return 外网IP地址
       */
      public static final String getExternalIPAddress() {
          return INSTANCE.externalIPAddress;
      }
      
      /**
       * @return 外网IP地址是否是IPv4
       */
      public static final boolean getExternalIPAddressIPv4() {
          return INSTANCE.externalIPAddressIPv4;
      }
      
  }
  