#!/usr/bin/ruby193-ruby

require 'optparse'
options = {}
defaults = {:foreman_path => File.expand_path("../..", __FILE__),
            :environment => "production",
            :keys => [],
            :key_values => {}}

options.merge!(defaults)
changed_settings = []

def set_options_key_value(options, value)
  unless options.has_key?(:key)
    STDERR.puts("Key has to be specified first")
    exit 2
  end
  options[:keys] << options[:key]
  options[:key_values][options[:key]] = value
  options.delete(:key)
end

parser = OptionParser.new do |opt|
  opt.banner = <<BANNER
Get or set the Foremen settings.

Options:
BANNER
  opt.on("-k",
         "--key KEY",
         "If not specified, all keys are displayed") do |val|
    options[:key] = val
  end

  opt.on("-v",
         "--value VALUE",
         "Set the value. The key must be specified. Complex values (hashes, arrays) are expected to be JSON encoded.") do |val|
    set_options_key_value(options, val)
  end

  opt.on("-u",
         "--unset",
         "Unset the key. The key must be specified") do
    set_options_key_value(options, :unset)
  end

  opt.on("-h", "--help", "Show help and exit") do 
    puts opt
    exit
  end

  opt.on("-p",
         "--path PATH",
         "Path with Foreman source code (default #{defaults[:foreman_path]})") do |val|
    options[:foreman_path] = val
  end

  opt.on("-e",
         "--env ENV",
         "Runtime environment (default #{defaults[:environment]})") do |val|
    options[:environment] = val
  end

  opt.on("-n",
         "--dry-run",
         "Don't change thd configuration. Success if no change is needed.") do
    options[:dry] = true
  end
end

parser.parse!

# suppress warnings (such as some featuer being disabled)
verbosity=$VERBOSE
$VERBOSE=nil

ENV["RAILS_ENV"] = options[:environment]

require File.expand_path("config/boot", options[:foreman_path])
require File.expand_path("config/application", options[:foreman_path])

Rails.application.require_environment!

Foreman::Application.config.logger = Logger.new("#{Rails.root}/log/foreman-config.log")

require 'json'
require 'yaml'

# get verbose level back
$VERBOSE=verbosity

def complex_type?(type)
  ["hash", "array"].include? type
end

# we expect simple values or JSON encoded hashes or arrays (if applicible)
def typecast_value(type, value)
  if complex_type?(type)
    # we used JSON over custom format for input because it's easier to parse
    JSON.parse(value).inspect
  else
    value
  end
end

def format_value(type, value)
  if complex_type?(type)
    value.to_json
  else
    value
  end
end

# show all settings
if options.has_key?(:key)
  setting = Setting.find_by_name(options[:key])
  puts format_value(setting.settings_type, setting.value)
elsif options[:key_values].any?
  options[:keys].each do |key|
    value = options[:key_values][key]
    setting = Setting.find_by_name(key)
    old_value = setting.value
    if value == :unset
      value = nil
    elsif complex_type?(setting.settings_type)
      setting.value = typecast_value(setting.settings_type, value)
    else
      setting.parse_string_value(value)
    end
    if setting.valid? && old_value != setting.value
      setting.save! unless options[:dry]
      changed_settings << setting
    end
    puts format_value(setting.settings_type, setting.value)
  end
else
  Setting.all.each do |setting|
    puts "#{setting.name}: #{format_value(setting.settings_type, setting.value)}"
  end
end

if options[:dry]
  if changed_settings.empty?
    exit 0
  else
    exit 1
  end
end
