# Copyright (C) 2010-2012 Alex Boisvert and Bizo Inc. / All rights reserved.
#
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
# license agreements.  See the NOTICE file  distributed with this work for
# additional information regarding copyright ownership.  The ASF licenses this
# file to you under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License.  You may obtain a copy of
# the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
# License for the specific language governing permissions and limitations under
# the License.

require 's3cp/utils'

# Parse arguments
options = {}
options[:recursive] = false
options[:include_regex] = nil
options[:exclude_regex] = nil
options[:test]   = false
options[:silent] = false
options[:fail_if_not_exist] = false
options[:batch_size] = 10000

op = OptionParser.new do |opts|
  opts.banner = "s3rm [path]"
  opts.separator ''

  opts.on("-r", "--recursive", "Delete S3 keys matching provided prefix.") do
    options[:recursive] = true
  end

  opts.on("-i REGEX", "--include REGEX", "Delete only S3 objects matching the following regular expression.") do |regex|
    options[:include_regex] = regex
  end

  opts.on("-x REGEX", "--exclude REGEX", "Do not delete any S3 objects matching provided regular expression.") do |regex|
    options[:exclude_regex] = regex
  end

  opts.on("-F", "--fail-if-not-exist", "Fail if no S3 object match provided key, prefix and/or regex") do
    options[:fail_if_not_exist] = true
  end

  opts.on("-t", "--test", "Only display matching keys; do not actually delete anything.") do
    options[:test] = true
  end

  opts.on("--silent", "Do not display keys as they are deleted.") do
    options[:silent] = true
  end

  opts.on("--batch", "Delete batch size.") do |batch|
    options[:batch_size] = batch.to_i
  end

  opts.on("--verbose", "Verbose mode") do
    options[:verbose] = true
  end

  opts.on("--debug", "Debug mode") do
    options[:debug] = true
  end

  opts.on_tail("-h", "--help", "Show this message") do
    puts op
    exit
  end
end
op.parse!(ARGV)

unless ARGV.size > 0
  puts op
  exit(1)
end

if options[:include_regex] && !options[:recursive]
  puts "-i (--include regex) option requires -r (recursive) option."
  exit(1)
end

if options[:exclude_regex] && !options[:recursive]
  puts "-x (--exclude regex) option requires -r (recursive) option."
  exit(1)
end

url = ARGV[0]

if options[:verbose]
  puts "URL: #{url}"
  puts "Options: #{options.inspect}"
end

@bucket, @key = S3CP.bucket_and_key(url)
fail "Your URL looks funny, doesn't it?" unless @bucket

if options[:verbose]
  puts "bucket #{@bucket}"
  puts "key #{@key}"
end

include_regex = options[:include_regex] ? Regexp.new(options[:include_regex]) : nil
exclude_regex = options[:exclude_regex] ? Regexp.new(options[:exclude_regex]) : nil

S3CP.standard_exception_handling(options) do
  S3CP.load_config()

  @s3 = S3CP.connect()

  if options[:recursive]
    matching_keys = []

    @s3.buckets[@bucket].objects.with_prefix(@key).each do |entry|
      key = "s3://#{@bucket}/#{entry.key}"

      matching = true
      matching = false if include_regex && !include_regex.match(entry.key)
      matching = false if exclude_regex && exclude_regex.match(entry.key)

      puts "#{key} => #{matching}" if options[:verbose]

      if matching
        matching_keys << entry.key
        puts key unless options[:silent] || options[:verbose]
      end

      if matching_keys.size > options[:batch_size]
        if options[:verbose]
          puts "Deleting batch..."
        end
        @s3.buckets[@bucket].objects.delete(matching_keys) unless options[:test]
        matching_keys = []
      end
    end

    if options[:fail_if_not_exist] && matching_keys.length == 0
      puts "No matching keys."
      exit(1)
    end

    # if any of the objects failed to delete, a BatchDeleteError will be raised with a summary of the errors
    @s3.buckets[@bucket].objects.delete(matching_keys) unless options[:test]
  else
    # delete a single file; check if it exists
    if options[:fail_if_not_exist] && !@s3.buckets[@bucket].objects[@key].exist?
      key = "s3://#{@bucket}/#{@key}"
      puts "#{key} does not exist."
      exit(1)
    end

    begin
      @s3.buckets[@bucket].objects[@key].delete() unless options[:test]
    rescue => e
      puts e.to_s
      raise e unless e.is_a? AWS::S3::Errors::NoSuchKey
    end
  end
end

