# Path: ddsc/core/localstore.py
# class HashUtil(object):
#     HASH_NAME = "md5"
#     """
#     Utility to create hash pair (name, hash) for a file or chunk.
#     """
#     def __init__(self):
#         self.hash = hashlib.md5()
# 
#     def add_file(self, filename, block_size=4096):
#         """
#         Add an entire file to this hash.
#         :param filename: str filename of the file to hash
#         :param block_size: int size of chunks when reading the file
#         """
#         with open(filename, "rb") as f:
#             for chunk in iter(lambda: f.read(block_size), b""):
#                 self.hash.update(chunk)
# 
#     def add_chunk(self, chunk):
#         """
#         Add a single block of memory to the hash.
#         :param chunk: str data to hash
#         :return:
#         """
#         self.hash.update(chunk)
# 
#     def hexdigest(self):
#         """
#         return a hash pair
#         :return: (str,str) -> (algorithm,value)
#         """
#         return HashUtil.HASH_NAME, self.hash.hexdigest()
# 
# Path: ddsc/core/ddsapi.py
# DDS_TOTAL_HEADER = 'x-total'
# 
# Path: ddsc/core/util.py
# def humanize_bytes(num_bytes):
#     """
#     Convert a number of bytes to human version
#     :param num_bytes: int: bytes to be converted to
#     :return: str
#     """
#     val = num_bytes
#     suffix = "B"
#     factor = 1000
#     if val >= factor:
#         val = val / factor
#         suffix = "KB"
#     if val >= factor:
#         val = val / factor
#         suffix = "MB"
#     if val >= factor:
#         val = val / factor
#         suffix = "GB"
#     val = "{:0.1f} {}".format(val, suffix)
#     return val.replace(".0", "")
# 
# def transfer_speed_str(current_time, start_time, transferred_bytes):
#     """
#     Return transfer speed str based
#     :param current_time: float: current time
#     :param start_time: float: starting time
#     :param transferred_bytes: int: bytes transferred
#     :return: str: end user str
#     """
#     elapsed_seconds = current_time - start_time
#     if elapsed_seconds > 0 and transferred_bytes > 0:
#         bytes_per_second = float(transferred_bytes) / (elapsed_seconds + 0.5)
#         return '@ {}/s'.format(humanize_bytes(bytes_per_second))
#     return ''


import sys
import requests
import os
import multiprocessing
import time
import queue
from requests.exceptions import HTTPError
from ddsc.core.localstore import HashUtil
from ddsc.core.ddsapi import DDS_TOTAL_HEADER
from ddsc.core.util import humanize_bytes, transfer_speed_str

SWIFT_EXPIRED_STATUS_CODE = 401
S3_EXPIRED_STATUS_CODE = 403
MISMATCHED_FILE_HASH_WARNING = """
NOTICE: Data Service reports multiple hashes for {}.
The downloaded files have been verified and confirmed to match one of these hashes.
You do not need to retry the download.

# Path: ddsc/core/localstore.py
# class HashUtil(object):
#     HASH_NAME = "md5"
#     """
#     Utility to create hash pair (name, hash) for a file or chunk.
#     """
#     def __init__(self):
#         self.hash = hashlib.md5()
# 
#     def add_file(self, filename, block_size=4096):
#         """
#         Add an entire file to this hash.
#         :param filename: str filename of the file to hash
#         :param block_size: int size of chunks when reading the file
#         """
#         with open(filename, "rb") as f:
#             for chunk in iter(lambda: f.read(block_size), b""):
#                 self.hash.update(chunk)
# 
#     def add_chunk(self, chunk):
#         """
#         Add a single block of memory to the hash.
#         :param chunk: str data to hash
#         :return:
#         """
#         self.hash.update(chunk)
# 
#     def hexdigest(self):
#         """
#         return a hash pair
#         :return: (str,str) -> (algorithm,value)
#         """
#         return HashUtil.HASH_NAME, self.hash.hexdigest()
# 
# Path: ddsc/core/ddsapi.py
# DDS_TOTAL_HEADER = 'x-total'
# 
# Path: ddsc/core/util.py
# def humanize_bytes(num_bytes):
#     """
#     Convert a number of bytes to human version
#     :param num_bytes: int: bytes to be converted to
#     :return: str
#     """
#     val = num_bytes
#     suffix = "B"
#     factor = 1000
#     if val >= factor:
#         val = val / factor
#         suffix = "KB"
#     if val >= factor:
#         val = val / factor
#         suffix = "MB"
#     if val >= factor:
#         val = val / factor
#         suffix = "GB"
#     val = "{:0.1f} {}".format(val, suffix)
#     return val.replace(".0", "")
# 
# def transfer_speed_str(current_time, start_time, transferred_bytes):
#     """
#     Return transfer speed str based
#     :param current_time: float: current time
#     :param start_time: float: starting time
#     :param transferred_bytes: int: bytes transferred
#     :return: str: end user str
#     """
#     elapsed_seconds = current_time - start_time
#     if elapsed_seconds > 0 and transferred_bytes > 0:
#         bytes_per_second = float(transferred_bytes) / (elapsed_seconds + 0.5)
#         return '@ {}/s'.format(humanize_bytes(bytes_per_second))
#     return ''


# Path: ddsc/core/download.py
import sys
import requests
import os
import multiprocessing
import time
import queue
from requests.exceptions import HTTPError
from ddsc.core.localstore import HashUtil
from ddsc.core.ddsapi import DDS_TOTAL_HEADER
from ddsc.core.util import humanize_bytes, transfer_speed_str


SWIFT_EXPIRED_STATUS_CODE = 401
S3_EXPIRED_STATUS_CODE = 403
MISMATCHED_FILE_HASH_WARNING = """
NOTICE: Data Service reports multiple hashes for {}.
The downloaded files have been verified and confirmed to match one of these hashes.
You do not need to retry the download.

For more information, visit https://github.com/Duke-GCB/DukeDSClient/wiki/MD5-Hash-Conflicts.