# Path: internetarchive/cli/argparser.py
# def get_args_dict(args, query_string=False, header=False):
#     args = [] if not args else args
#     metadata = defaultdict(list)
#     for md in args:
#         if query_string:
#             if (':' in md) and ('=' not in md):
#                 md = md.replace(':', '=')
#                 md = md.replace(';', '&')
#             for key, value in parse_qsl(md):
#                 assert value
#                 metadata[key] = value
#         else:
#             key, value = md.split(':', 1)
#             assert value
#             if value not in metadata[key]:
#                 metadata[key].append(value)
# 
#     for key in metadata:
#         # Flatten single item lists.
#         if len(metadata[key]) <= 1:
#             metadata[key] = metadata[key][0]
# 
#     return metadata
# 
# Path: internetarchive/utils.py
# def get_s3_xml_text(xml_str):
#     def _get_tag_text(tag_name, xml_obj):
#         text = ''
#         elements = xml_obj.getElementsByTagName(tag_name)
#         for e in elements:
#             for node in e.childNodes:
#                 if node.nodeType == node.TEXT_NODE:
#                     text += node.data
#         return text
# 
#     tag_names = ['Message', 'Resource']
#     try:
#         p = parseString(xml_str)
#         _msg = _get_tag_text('Message', p)
#         _resource = _get_tag_text('Resource', p)
#         # Avoid weird Resource text that contains PUT method.
#         if _resource and "'PUT" not in _resource:
#             return f'{_msg} - {_resource.strip()}'
#         else:
#             return _msg
#     except:
#         return str(xml_str)
# 
# def merge_dictionaries(dict0, dict1, keys_to_drop=None):
#     """Merge two dictionaries.
# 
#        Items in `dict0` can optionally be dropped before the merge.
# 
#        If equal keys exist in both dictionaries,
#        entries in`dict0` are overwritten.
# 
#        :type dict0: dict
#        :param dict0: A base dictionary with the bulk of the items.
# 
#        :type dict1: dict
#        :param dict1: Additional items which overwrite the items in `dict0`.
# 
#        :type keys_to_drop: iterable
#        :param keys_to_drop: An iterable of keys to drop from `dict0` before the merge.
# 
#        :rtype: dict
#        :returns: A merged dictionary.
#        """
#     new_dict = dict0.copy()
#     if keys_to_drop is not None:
#         for key in keys_to_drop:
#             new_dict.pop(key, None)
#     # Items from `dict1` take precedence over items from `dict0`.
#     new_dict.update(dict1)
#     return new_dict


import sys
import internetarchive as ia
from urllib.parse import quote
from docopt import docopt, printable_usage
from schema import Schema, Use, Or, And, SchemaError
from internetarchive.cli.argparser import get_args_dict
from internetarchive.utils import get_s3_xml_text, merge_dictionaries

def main(argv, session, cmd='copy'):
    args = docopt(__doc__, argv=argv)
    src_path = args['<src-identifier>/<src-file>']
    dest_path = args['<dest-identifier>/<dest-file>']

    # If src == dest, file gets deleted!
    try:
        assert src_path != dest_path
    except AssertionError:
        print('error: The source and destination files cannot be the same!',
              file=sys.stderr)
        sys.exit(1)

    global SRC_ITEM
    SRC_ITEM = session.get_item(src_path.split('/')[0])

    # Validate args.
    s = Schema({
        str: Use(bool),
        '<src-identifier>/<src-file>': And(str, And(And(str, lambda x: '/' in x,
            error='Destination not formatted correctly. See usage example.'),
            assert_src_file_exists, error=(
            f'https://{session.host}/download/{src_path} does not exist. '
            'Please check the identifier and filepath and retry.'))),
        '<dest-identifier>/<dest-file>': And(str, lambda x: '/' in x,
            error='Destination not formatted correctly. See usage example.'),
        '--metadata': Or(None, And(Use(get_args_dict), dict),
                         error='--metadata must be formatted as --metadata="key:value"'),
        '--replace-metadata': Use(bool),

# Path: internetarchive/cli/argparser.py
# def get_args_dict(args, query_string=False, header=False):
#     args = [] if not args else args
#     metadata = defaultdict(list)
#     for md in args:
#         if query_string:
#             if (':' in md) and ('=' not in md):
#                 md = md.replace(':', '=')
#                 md = md.replace(';', '&')
#             for key, value in parse_qsl(md):
#                 assert value
#                 metadata[key] = value
#         else:
#             key, value = md.split(':', 1)
#             assert value
#             if value not in metadata[key]:
#                 metadata[key].append(value)
# 
#     for key in metadata:
#         # Flatten single item lists.
#         if len(metadata[key]) <= 1:
#             metadata[key] = metadata[key][0]
# 
#     return metadata
# 
# Path: internetarchive/utils.py
# def get_s3_xml_text(xml_str):
#     def _get_tag_text(tag_name, xml_obj):
#         text = ''
#         elements = xml_obj.getElementsByTagName(tag_name)
#         for e in elements:
#             for node in e.childNodes:
#                 if node.nodeType == node.TEXT_NODE:
#                     text += node.data
#         return text
# 
#     tag_names = ['Message', 'Resource']
#     try:
#         p = parseString(xml_str)
#         _msg = _get_tag_text('Message', p)
#         _resource = _get_tag_text('Resource', p)
#         # Avoid weird Resource text that contains PUT method.
#         if _resource and "'PUT" not in _resource:
#             return f'{_msg} - {_resource.strip()}'
#         else:
#             return _msg
#     except:
#         return str(xml_str)
# 
# def merge_dictionaries(dict0, dict1, keys_to_drop=None):
#     """Merge two dictionaries.
# 
#        Items in `dict0` can optionally be dropped before the merge.
# 
#        If equal keys exist in both dictionaries,
#        entries in`dict0` are overwritten.
# 
#        :type dict0: dict
#        :param dict0: A base dictionary with the bulk of the items.
# 
#        :type dict1: dict
#        :param dict1: Additional items which overwrite the items in `dict0`.
# 
#        :type keys_to_drop: iterable
#        :param keys_to_drop: An iterable of keys to drop from `dict0` before the merge.
# 
#        :rtype: dict
#        :returns: A merged dictionary.
#        """
#     new_dict = dict0.copy()
#     if keys_to_drop is not None:
#         for key in keys_to_drop:
#             new_dict.pop(key, None)
#     # Items from `dict1` take precedence over items from `dict0`.
#     new_dict.update(dict1)
#     return new_dict


# Path: internetarchive/cli/ia_copy.py
import sys
import internetarchive as ia
from urllib.parse import quote
from docopt import docopt, printable_usage
from schema import Schema, Use, Or, And, SchemaError
from internetarchive.cli.argparser import get_args_dict
from internetarchive.utils import get_s3_xml_text, merge_dictionaries


def main(argv, session, cmd='copy'):
    args = docopt(__doc__, argv=argv)
    src_path = args['<src-identifier>/<src-file>']
    dest_path = args['<dest-identifier>/<dest-file>']

    # If src == dest, file gets deleted!
    try:
        assert src_path != dest_path
    except AssertionError:
        print('error: The source and destination files cannot be the same!',
              file=sys.stderr)
        sys.exit(1)

    global SRC_ITEM
    SRC_ITEM = session.get_item(src_path.split('/')[0])

    # Validate args.
    s = Schema({
        str: Use(bool),
        '<src-identifier>/<src-file>': And(str, And(And(str, lambda x: '/' in x,
            error='Destination not formatted correctly. See usage example.'),
            assert_src_file_exists, error=(
            f'https://{session.host}/download/{src_path} does not exist. '
            'Please check the identifier and filepath and retry.'))),
        '<dest-identifier>/<dest-file>': And(str, lambda x: '/' in x,
            error='Destination not formatted correctly. See usage example.'),
        '--metadata': Or(None, And(Use(get_args_dict), dict),
                         error='--metadata must be formatted as --metadata="key:value"'),
        '--replace-metadata': Use(bool),

        '--header': Or(None, And(Use(get_args_dict), dict),