#!/usr/bin/env ruby
# CLI client for Trocla.
#
require 'rubygems'
require 'trocla'
require 'optparse'
require 'yaml'

options = { :config_file => nil, :ask_password => true, :trace => false }

OptionParser.new do |opts|
  opts.on("--version", "-V", "Version information") do
    puts Trocla::VERSION::STRING
    exit
  end

  opts.on("--config CONFIG", "-c", "Configuration file") do |v|
    if File.exist?(v)
      options[:config_file] = v
    else
      STDERR.puts "Cannot find config file: #{v}"
      exit 1
    end
  end

  opts.on("--trace", "Show stack trace on failure") do
    options[:trace] = true
  end

  opts.on("--no-random") do
    options['random'] = false
  end

  opts.on("--length LENGTH") do |v|
    options['length'] = v.to_i
  end

  opts.on("--password [PASSWORD]", "-p", "Provide password at command line") do |pass|
    options[:ask_password] = false
    options[:password] = pass
  end

end.parse!

def create(options)
  Trocla.new(options.delete(:config_file)).password(
    options.delete(:trocla_key),
    options.delete(:trocla_format),
    options.merge(YAML.load(options.delete(:other_options).shift.to_s)||{})
  )
end

def get(options)
  Trocla.new(options.delete(:config_file)).get_password(
    options.delete(:trocla_key),
    options.delete(:trocla_format)
  )
end
def set(options)
  if options.delete(:ask_password)
    require 'highline/import'
    password = ask("Enter your password: ") { |q| q.echo = "x" }.to_s
    pwd2 = ask("Repeat password: ") { |q| q.echo = "x" }.to_s
    unless password == pwd2
      STDERR.puts "Passwords did not match, exiting!"
      exit 1
    end
  else
    password = options.delete(:password) || STDIN.read.chomp
  end
  format = options.delete(:trocla_format)
  trocla = Trocla.new(options.delete(:config_file))
  trocla.set_password(
    options.delete(:trocla_key),
    format,
    trocla.formats(format).format(password, options.delete(:other_options).shift.to_s)
  )
  ""
end

def reset(options)
  Trocla.new(options.delete(:config_file)).reset_password(
    options.delete(:trocla_key),
    options.delete(:trocla_format),
    options.merge(YAML.load(options.delete(:other_options).shift.to_s)||{})
  )
end

def delete(options)
  Trocla.new(options.delete(:config_file)).delete_password(
    options.delete(:trocla_key),
    options.delete(:trocla_format)
  )
end

def check_format(format_name)
  if format_name.nil?
    STDERR.puts "Missing format, exiting..."
    exit 1
  elsif !Trocla::Formats.available?(format_name)
    STDERR.puts "Error: The format #{format_name} is not available"
    exit 1
  end
end

actions=['create','get','set','reset','delete']

if !(ARGV.length < 2) && (action=ARGV.shift) && actions.include?(action)
    options[:trocla_key] = ARGV.shift
    options[:trocla_format] = ARGV.shift
    options[:other_options] = ARGV
    check_format(options[:trocla_format]) unless action == 'delete'
    begin
      if result = send(action,options)
        puts result.is_a?(String) ? result : result.inspect
      end
    rescue Exception => e
      unless e.message == 'exit'
        STDERR.puts "Action failed with the following message: #{e.message}"
        STDERR.puts "(See full trace by running task with --trace)"
      end
      raise e if options[:trace]
      exit 1
    end
else
    STDERR.puts "Please supply one of the following actions: #{actions.join(', ')}"
    exit 1
end

