class EnvironmentConfig
  @MEMORY_USAGE = "exodus.memoryUsage"
  @MEMORY_USAGE_PERCENTAGE = "exodus.memoryUsagePercentage"
  @LOG_DURABLE_WRITE = "exodus.log.durableWrite"
  @LOG_FILE_SIZE = "exodus.log.fileSize" # in Kb
  @LOG_LOCK_TIMEOUT = "exodus.log.lockTimeout" # in milliseconds
  @LOG_CACHE_PAGE_SIZE = "exodus.log.cache.pageSize" # in bytes
  @LOG_CACHE_OPEN_FILES = "exodus.log.cache.openFilesCount"
  @LOG_CACHE_SHARED = "exodus.log.cache.shared"
  @LOG_CACHE_NON_BLOCKING = "exodus.log.cache.nonBlocking"
  @LOG_CACHE_WRITE_BUFFER_SIZE = "exodus.log.cache.writeBufferSize"
  @ENV_META_TREE_CACHED = "exodus.env.metaTree.cached"
  @ENV_CLOSE_FORCEDLY = "exodus.env.close.forcedly"
  @TREE_MAX_PAGE_SIZE = "exodus.tree.maxPageSize"
  @GC_ENABLED = "exodus.gc.enabled"
  @GC_MIN_UTILIZATION = "exodus.gc.minUtilization"
  @GC_RENAME_FILES = "exodus.gc.renameFiles"
  @GC_USE_EXPIRATION_CHECKER = "exodus.gc.useExpirationChecker"
  # Minimum age of a file to consider it for cleaning.
  @GC_MIN_FILE_AGE = "exodus.gc.fileMinAge"
  # Cleaner checks log utilization and runs if necessary after
  # this many new files are created in the log.
  @GC_CLEANER_FILES_INTERVAL = "exodus.gc.cleaner.filesInterval";
  @GC_UTILIZATION_FROM_SCRATCH = "exodus.gc.utilization.fromScratch";

  # @private
  settings: undefined
  # @private
  balanceStrategy: undefined

  getSetting: (key) ->
    return @settings[key]

  setSetting: (key, value) ->
    @settings[key] = value

  getMemoryUsage: () ->
    @getSetting(EnvironmentConfig.MEMORY_USAGE)

  setMemoryUsage: (maxMemory) ->
    @setSetting(EnvironmentConfig.MEMORY_USAGE, maxMemory)

  getMemoryUsagePercentage: () ->
    return @getSetting(EnvironmentConfig.MEMORY_USAGE_PERCENTAGE)

  setMemoryUsagePercentage: (memoryUsagePercentage) ->
    @setSetting(EnvironmentConfig.MEMORY_USAGE_PERCENTAGE, memoryUsagePercentage)

  getLogDurableWrite: () ->
    return @getSetting(EnvironmentConfig.LOG_DURABLE_WRITE)

  setLogDurableWrite: (durableWrite)->
    @setSetting(EnvironmentConfig.LOG_DURABLE_WRITE, durableWrite)

  getLogFileSize: () ->
    return @getSetting(EnvironmentConfig.LOG_FILE_SIZE)

  setLogFileSize: (kilobytes) ->
    @setSetting(EnvironmentConfig.LOG_FILE_SIZE, kilobytes)

  getLogLockTimeout: () ->
    return @getSetting(EnvironmentConfig.LOG_LOCK_TIMEOUT)

  setLogLockTimeout: (millis) ->
    @setSetting(EnvironmentConfig.LOG_LOCK_TIMEOUT, millis)

  getLogCachePageSize: () ->
    return @getSetting(EnvironmentConfig.LOG_CACHE_PAGE_SIZE)

  setLogCachePageSize: (bytes) ->
    @setSetting(EnvironmentConfig.LOG_CACHE_PAGE_SIZE, bytes)

  getLogCacheOpenFilesCount: () ->
    return @getSetting(EnvironmentConfig.LOG_CACHE_OPEN_FILES)

  setLogCacheOpenFilesCount: (files) ->
    @setSetting(EnvironmentConfig.LOG_CACHE_OPEN_FILES, files)

  isLogCacheShared: () ->
    return @getSetting(EnvironmentConfig.LOG_CACHE_SHARED)

  setLogCacheShared: (shared) ->
    @setSetting(EnvironmentConfig.LOG_CACHE_SHARED, shared)

  isLogCacheNonBlocking: () ->
    return @getSetting(EnvironmentConfig.LOG_CACHE_NON_BLOCKING)

  setLogCacheNonBlocking: (shared) ->
    @setSetting(EnvironmentConfig.LOG_CACHE_NON_BLOCKING, shared)

  getLogCacheWriteBufferSize: () ->
    return @getSetting(EnvironmentConfig.LOG_CACHE_WRITE_BUFFER_SIZE)

  setLogCacheWriteBufferSize: (pagesCount) ->
    @setSetting(EnvironmentConfig.LOG_CACHE_WRITE_BUFFER_SIZE, pagesCount)

  getEnvMetaTreeCached: () ->
    return @getSetting(EnvironmentConfig.ENV_META_TREE_CACHED)

  setEnvMetaTreeCached: (cached) ->
    @setSetting(EnvironmentConfig.ENV_META_TREE_CACHED, cached)

  getEnvCloseForcedly: () ->
    return @getSetting(EnvironmentConfig.ENV_CLOSE_FORCEDLY)

  setEnvCloseForcedly: (closeForcedly) ->
    @setSetting(EnvironmentConfig.ENV_CLOSE_FORCEDLY, closeForcedly)

  getTreeMaxPageSize: () ->
    return @getSetting(EnvironmentConfig.TREE_MAX_PAGE_SIZE)

  setTreeMaxPageSize: (pageSize) ->
    #    if (pageSize < 4 || pageSize > 1024)
    # TODO throw new InvalidSettingException("Invalid tree page size: " + pageSize);
    @setSetting(EnvironmentConfig.TREE_MAX_PAGE_SIZE, pageSize)
    balanceStrategy = null;

  isGcEnabled: () ->
    return @getSetting(EnvironmentConfig.GC_ENABLED)

  setGcEnabled: (enabled) ->
    @setSetting(EnvironmentConfig.GC_ENABLED, enabled)

  getGcMinUtilization: () ->
    return @getSetting(EnvironmentConfig.GC_MIN_UTILIZATION)

  setGcMinUtilization: (percent) ->
    #if (percent < 1 || percent > 90) {
    # TODO throw new InvalidSettingException("Invalid minimum log files utilization: " + percent);
    @setSetting(EnvironmentConfig.GC_MIN_UTILIZATION, percent)

  getGcRenameFiles: () ->
    return @getSetting(EnvironmentConfig.GC_RENAME_FILES)

  setGcRenameFiles: (rename) ->
    @setSetting(EnvironmentConfig.GC_RENAME_FILES, rename)

  getGcUseExpirationChecker: () ->
    return @getSetting(EnvironmentConfig.GC_USE_EXPIRATION_CHECKER)

  setGcUseExpirationChecker: (use) ->
    @setSetting(EnvironmentConfig.GC_USE_EXPIRATION_CHECKER, use)

  getGcFileMinAge: () ->
    return @getSetting(GC_MIN_FILE_AGE)

  setGcFileMinAge: (minAge) ->
    #if (minAge < 1) {
    # TODO throw new InvalidSettingException("Invalid file minimum age: " + minAge);
    @setSetting(EnvironmentConfig.GC_MIN_FILE_AGE, minAge)

  getGcCleanerFilesInterval: () ->
    return @getSetting(EnvironmentConfig.GC_CLEANER_FILES_INTERVAL)

  setGcCleanerFilesInterval: (files) ->
    #if (files < 1) {
    # TODO throw new InvalidSettingException("Invalid number of files: " + files);
    @setSetting(EnvironmentConfig.GC_CLEANER_FILES_INTERVAL, files)

  getGcUtilizationFromScratch: () ->
    return @getSetting(EnvironmentConfig.GC_UTILIZATION_FROM_SCRATCH)

  setGcUtilizationFromScratch: (fromScratch) ->
    @setSetting(EnvironmentConfig.GC_UTILIZATION_FROM_SCRATCH, fromScratch)

  getBalanceStrategy: () ->
    # no actual need to avoid  race condition here
    #TODO if (balanceStrategy == null) {
    #balanceStrategy = new BalanceStrategy(getTreeMaxPageSize());
    return @balanceStrategy;

  #private static boolean getBoolean(@NotNull final String propName, final boolean defaultValue) {
  #  final String value = System.getProperty(propName);
  #  return value == null ? defaultValue : "true".equalsIgnoreCase(value);

  @create: (o) ->
    if !o? then o = new EnvironmentConfig()
    o.settings = new Object()
    o.setMemoryUsagePercentage(60)
    o.setLogDurableWrite(true)
    o.setLogFileSize(8192)
    o.setLogLockTimeout(0)
    o.setLogCachePageSize(16284)
    o.setLogCacheOpenFilesCount(50)
    o.setLogCacheShared(true)
    o.setLogCacheNonBlocking(true)
    o.setLogCacheWriteBufferSize(16)
    o.setEnvMetaTreeCached(true)
    o.setEnvCloseForcedly(false)
    o.setTreeMaxPageSize(128)
    o.setGcEnabled(true)
    o.setGcMinUtilization(50)
    o.setGcRenameFiles(false)
    o.setGcUseExpirationChecker(true)
    o.setGcFileMinAge(2)
    o.setGcCleanerFilesInterval(2)
    o.setGcUtilizationFromScratch(false)
    return o
    #setMemoryUsagePercentage(Integer.getInteger(MEMORY_USAGE_PERCENTAGE, 60));
    #setLogDurableWrite(getBoolean(LOG_DURABLE_WRITE, true));
    #setLogFileSize(Long.getLong(LOG_FILE_SIZE, 8192L));
    #setLogLockTimeout(Long.getLong(LOG_LOCK_TIMEOUT, 0L));
    #setLogCachePageSize(Integer.getInteger(LOG_CACHE_PAGE_SIZE, 16384));
    #setLogCacheOpenFilesCount(Integer.getInteger(LOG_CACHE_OPEN_FILES, 50));
    #setLogCacheShared(getBoolean(LOG_CACHE_SHARED, true));
    #setLogCacheNonBlocking(getBoolean(LOG_CACHE_NON_BLOCKING, true));
    #setLogCacheWriteBufferSize(Integer.getInteger(LOG_CACHE_WRITE_BUFFER_SIZE, 16));
    #setEnvMetaTreeCached(getBoolean(ENV_META_TREE_CACHED, true));
    #setEnvCloseForcedly(getBoolean(ENV_CLOSE_FORCEDLY, false));
    #setTreeMaxPageSize(Integer.getInteger(TREE_MAX_PAGE_SIZE, 128));
    #setGcEnabled(getBoolean(GC_ENABLED, true));
    #setGcMinUtilization(Integer.getInteger(GC_MIN_UTILIZATION, 50));
    #setGcRenameFiles(getBoolean(GC_RENAME_FILES, false));
    #setGcUseExpirationChecker(getBoolean(GC_USE_EXPIRATION_CHECKER, true));
    #setGcFileMinAge(Integer.getInteger(GC_MIN_FILE_AGE, 2));
    #setGcCleanerFilesInterval(Integer.getInteger(GC_CLEANER_FILES_INTERVAL, 2));
    #setGcUtilizationFromScratch(getBoolean(GC_UTILIZATION_FROM_SCRATCH, false));

  @DEFAULT: EnvironmentConfig.create()

exports.EnvironmentConfig = EnvironmentConfig