#!/usr/bin/env python

import boto.s3
import sys
import logging

from umobj.bucket import delete_bucket
from umobj.key import delete_key, is_directory
from umobj.utils import umobj_logging, umobj_init, \
    umobj_get_bucket_key_pair_from_string
from umobj.obj import Obj
from umobj.options import umobj_parser, get_logging_level


def ask_yes_no(question):
    """Ask a yes or no question and return True if yes."""
    ans = raw_input('%s [yes/no] ' % question).lower()
    return ans == 'yes' or ans == 'y'


def no_to_question(question):
    """Return True if the answer to the yes/no question is no."""
    return not ask_yes_no(question)


if __name__ == "__main__":
    umobj_init()

    description = 'Remove Bucket(s) and Object(s)'
    parser = umobj_parser(description=description)
    parser.add_recursive()
    parser.add_force()
    parser.add_interactive()
    parser.add_s3path(number='+', help='BUCKET:KEY', name='S3PATH')
    args = parser.parse_args()

    umobj_logging(get_logging_level(args))  # set up logging

    logging.info("Running %s" % sys.argv)

    recursive = args.recursive
    interactive = args.interactive
    force = args.force

    _exit_status = [0]
    _file_existence_error = [False]

    def set_exit_status(status):
        _exit_status[0] = status

    def exit_status():
        return _exit_status[0]

    def flag_file_existence_error():
        _file_existence_error[0] = True

    def file_existence_error():
        return _file_existence_error[0]

    def delete_key_with_status(bucket, key_name, check_exists=False):
        status = delete_key(bucket, key_name, check_exists=check_exists)
        if status is False:
            logging.error("rmobj: cannot remove '%s:%s': No such key" % \
                          (bucket.name, key_name))
            flag_file_existence_error()

    prompt_once = False

    if recursive:
        prompt_once = True
    if interactive:
        prompt_once = False
        # note that force is last since it is King arbiter of whether or not
        # we can be interactive.
    if force:
        interactive = False
        prompt_once = False

    if not Obj.connect(host=args.host,
                       port=args.port,
                       access_key=args.access_key,
                       secret_key=args.secret_key):
        logging.error('Unable to contact object store.')
        sys.exit(1)

    if prompt_once and recursive:
        if len(args.S3PATH) == 1:
            question = 'Remove 1 argument recursively?'
        else:
            question = 'Remove %s arguments recursively?' % len(args.S3PATH)
        if no_to_question(question):
            sys.exit(0)

    for arg in args.S3PATH:
        bucket_name, key_name = umobj_get_bucket_key_pair_from_string(arg)

        try:
            bucket = Obj.conn.get_bucket(bucket_name)
        except boto.exception.S3ResponseError as e:
            if e.status == 404:
                logging.error("Bucket %s does not exist." % bucket_name)
                flag_file_existence_error()
            else:
                logging.error("Insufficient permissions.")
            continue

        logging.info("Working on bucket %s" % bucket_name)

        if recursive:

            # removing all content inside bucket
            if not key_name:
                if interactive:
                    question = " Are you sure you want to remove all the ' + \
                               'contents of the bucket '%s'?" % bucket.name
                    if no_to_question(question):
                        logging.info("Skipping recursive deletion of " +
                                     "bucket %s contents" % bucket_name)
                        continue
                for key in bucket.list():
                    delete_key_with_status(bucket, key.name)

                # removing the bucket itself
                if interactive:
                    question = " Do you want to remove the bucket '%s'?" % \
                        bucket.name
                    if no_to_question(question):
                        logging.info("Not deleting bucket %s" % bucket_name)
                        continue
                delete_bucket(Obj.conn, bucket.name)
                logging.info("Deleting the bucket %s" % bucket_name)
                continue

            # removing a directory or file
            if is_directory(bucket, key_name):
                # ensure trailing slash
                if not key_name.endswith('/'):
                    key_name = key_name + '/'
                was_something_to_list = False
                for key in bucket.list(prefix=key_name):
                    was_something_to_list = True
                    if interactive and no_to_question("rmobj: delete '%s'?" % key.name):
                        continue
                    delete_key_with_status(bucket, key.name)
                if not was_something_to_list and not force:
                    logging.error("rmobj: cannot remove '%s': No such key" % arg)
                    flag_file_existence_error()
            else:  # individal file
                if interactive and no_to_question("rmobj: delete '%s'?" % key_name):
                    continue
                delete_key_with_status(bucket, key_name, check_exists=True)
        else:  # non-recursive
            if key_name is None:
                logging.error('Cannot delete bucket %s, ' % bucket.name +
                              'please use the recursive option.')
                set_exit_status(1)
                continue
            elif is_directory(bucket, key_name):
                logging.error("rmobj: cannot remove '%s': Is a directory" % arg)
                set_exit_status(1)
                continue
            logging.info('Deleting %s...' % arg)
            delete_key_with_status(bucket, key_name, check_exists=True)

    # this can be a little confusing...  If someone used the API wrong, we
    # will ALWAYS exit non-zero regardless of if the force flag was present.
    # Otherwise, we exit non-zero if there were file existence errors  unless
    # the force flag was given.
    if exit_status() != 0:
        sys.exit(exit_status())
    elif force:
        sys.exit(0)
    else:
        if file_existence_error():
            sys.exit(1)
        else:
            sys.exit(0)
