#!/usr/bin/env ruby
$: << File.expand_path("#{File.dirname __FILE__}/../lib")
require 'rubygems'
require 'gratan'
require 'optparse'
require 'json'

Version = Gratan::VERSION
DEFAULT_FILENAME = 'Grantfile'

mode = nil
file = DEFAULT_FILENAME
output_file = '-'
split = false

mysql_options = {
  :host     => 'localhost',
  :username => 'root',
}

options = {
  :dry_run    => false,
  :color      => true,
  :debug      => false,
}

ARGV.options do |opt|
  begin
    opt.on(''  , '--host HOST')            {|v| mysql_options[:host]           = v             }
    opt.on(''  , '--port PORT', Integer)   {|v| mysql_options[:port]           = v             }
    opt.on(''  , '--socket SOCKET')        {|v| mysql_options[:socket]         = v             }
    opt.on(''  , '--username USERNAME')    {|v| mysql_options[:username]       = v             }
    opt.on(''  , '--password PASSWORD')    {|v| mysql_options[:password]       = v             }
    opt.on(''  , '--database DATABASE')    {|v| mysql_options[:database]       = v             }
    opt.on('-a', '--apply')                {    mode                           = :apply        }
    opt.on('-f', '--file FILE')            {|v| file                           = v             }
    opt.on(''  , '--dry-run')              {    options[:dry_run]              = true          }
    opt.on('-e', '--export')               {    mode                           = :export       }
    opt.on(''  , '--with-identifier')      {    options[:with_identifier]      = true          }
    opt.on(''  , '--split')                {    split                          = true          }
    opt.on(''  , '--chunk-by-user')        {    options[:chunk_by_user]        = true          }
    opt.on('-o', '--output FILE')          {|v| output_file                    = v             }
    opt.on(''  , '--ignore-user REGEXP')   {|v| options[:ignore_user]          = Regexp.new(v) }
    opt.on(''  , '--target-user REGEXP')   {|v| options[:target_user]          = Regexp.new(v) }
    opt.on(''  , '--ignore-object REGEXP') {|v| options[:ignore_object]        = Regexp.new(v) }
    opt.on(''  , '--enable-expired')       {    options[:enable_expired]       = true          }
    opt.on(''  , '--ignore-not-exist')     {|v| options[:ignore_not_exist]     = true          }
    opt.on(''  , '--skip-disable-log-bin') {    options[:skip_disable_log_bin] = true          }
    opt.on(''  , '--no-color')             {    options[:color]                = false         }
    opt.on(''  , '--debug')                {    options[:debug]                = true          }
    opt.on(''  , '--auto-identify OUTPUT') {|v| options[:identifier] = Gratan::Identifier::Auto.new(v, options) }
    opt.on(''  , '--csv-identify CSV')     {|v| options[:identifier] = Gratan::Identifier::CSV.new(v, options)  }

    opt.on('-h', '--help') do
      puts opt.help
      exit 1
    end

    opt.parse!

    unless mode
      puts opt.help
      exit 1
    end
  rescue => e
    $stderr.puts("[ERROR] #{e.message}")
    exit 1
  end
end

options.update(mysql_options)
String.colorize = options[:color]

begin
  logger = Gratan::Logger.instance
  logger.set_debug(options[:debug])
  client = Gratan::Client.new(options)

  case mode
  when :export
    if split
      logger.info('Export Grants')
      output_file = DEFAULT_FILENAME if output_file == '-'
      requires = []

      client.export do |user, dsl|
        grant_file = File.join(File.dirname(output_file), "#{user}.grant")
        requires << grant_file
        logger.info("  write `#{grant_file}`")

        open(grant_file, 'wb') do |f|
          f.puts dsl
        end
      end

      logger.info("  write `#{output_file}`")

      open(output_file, 'wb') do |f|
        requires.each do |grant_file|
          f.puts "require '#{File.basename grant_file}'"
        end
      end
    else
      if output_file == '-'
        logger.info('# Export Grants')
        puts client.export(options)
      else
        logger.info("Export Grants to `#{output_file}`")
        open(output_file, 'wb') {|f| f.puts client.export(options) }
      end
    end
  when :apply
    unless File.exist?(file)
      raise "No Grantfile found (looking for: #{file})"
    end

    mysql_info = mysql_options.dup
    mysql_info.delete(:password)
    mysql_info = JSON.dump(mysql_info)

    msg = "Apply `#{file}` to #{mysql_info}"
    msg << ' (dry-run)' if options[:dry_run]
    logger.info(msg)

    updated = client.apply(file)

    logger.info('No change'.intense_blue) unless updated
  end
rescue => e
  if options[:debug]
    raise e
  else
    $stderr.puts("[ERROR] #{e.message}".red)
    exit 1
  end
end