module NSWTopo::Config

def self.method_missing(symbol, *args, &block)

def self.method_missing(symbol, *args, &block)
  extend(self).init
  singleton_class.remove_method :method_missing
  send symbol, *args, &block
end

def delete(*entries, key)

def delete(*entries, key)
  delete_recursive @config, *entries, key
end

def delete_recursive(config, *entries, key)

def delete_recursive(config, *entries, key)
  case
  when entry = entries.shift
    raise "no such entry: %s" % entry unless Hash === config[entry]
    delete_recursive config[entry], *entries, key
    config.delete entry if config[entry].empty?
  when config.key?(key)
    config.delete key
  else
    raise "no such entry: %s" % key
  end
end

def init

def init
  candidates = []
  %w[XDG_CONFIG_HOME APPDATA].each do |key|
    candidates << [ENV.fetch(key), "nswtopo"]
  rescue KeyError
  end
  candidates << [Dir.home, "Library", "Application Support", "com.nswtopo"]
  candidates << [Dir.home, ".config", "nswtopo"]
  candidates << [Dir.home, ".nswtopo"]
  @path = candidates.map do |base, *parts|
    Pathname(base).join(*parts)
  end.first do |dir|
    dir.parent.directory?
  end.join("nswtopo.cfg")
  @config, extra = [@path, @extra_path].map do |path|
    next Hash[] unless path&.file?
    config = YAML.load(path.read)
    Hash === config ? config : raise
  rescue YAML::Exception, RuntimeError
    log_warn "couldn't parse #{path} - ignoring"
    Hash[]
  end
  @merged = @config.deep_merge extra
end

def save

def save
  @path.parent.mkpath
  @path.write @config.to_yaml
end

def store(*entries, key, value)

def store(*entries, key, value)
  entries.inject(@config) do |config, entry|
    config[entry] ||= {}
    Hash === config[entry] ? config[entry] : raise("entry already taken: %s" % entry)
  end.store key, value
end