# Path: ddsc/config.py
# def get_user_config_filename():
#     user_config_filename = os.environ.get(LOCAL_CONFIG_ENV)
#     if user_config_filename:
#         return user_config_filename
#     else:
#         return LOCAL_CONFIG_FILENAME
# 
# Path: ddsc/versioncheck.py
# APP_NAME = "DukeDSClient"
# 
# def get_internal_version_str():
#     """
#     Returns internal version string.
#     """
#     return pkg_resources.get_distribution(APP_NAME).version
# 
# Path: ddsc/core/retry.py
# class RetrySettings(object):
#     # DukeDS API Retry Settings
#     # Settings for retrying a ConnectionError connecting to the DukeDS API
#     CONNECTION_RETRY_TIMES = 5
#     CONNECTION_RETRY_SECONDS = 1
#     # Settings for how long to sleep when we receive 503 from DukeDS API (Weekly system maintenance typically)
#     SERVICE_DOWN_RETRY_SECONDS = 60
#     # How long to sleep when waiting for DukeDS API to be consistent (waits forever)
#     RESOURCE_NOT_CONSISTENT_RETRY_SECONDS = 2
# 
#     # Backend Store Retry Settings
#     # Settings for retrying when a ConnectionError occurs uploading a file chunk
#     SEND_EXTERNAL_PUT_RETRY_TIMES = 4
#     SEND_EXTERNAL_RETRY_SECONDS = 20
#     # Times to retry after receiving a 403 uploading a file chunk (we recreate the URL before retrying)
#     SEND_EXTERNAL_FORBIDDEN_RETRY_TIMES = 2
#     # Settings for retrying when downloading part of a file
#     FETCH_EXTERNAL_PUT_RETRY_TIMES = 5
#     FETCH_EXTERNAL_RETRY_SECONDS = 20
# 
# Path: ddsc/exceptions.py
# class DDSUserException(Exception):
#     """
#     Exception with an error message to be displayed to the user on the command line.
#     """
#     pass


import json
import requests
import time
import datetime
from ddsc.config import get_user_config_filename
from ddsc.versioncheck import APP_NAME, get_internal_version_str
from ddsc.core.retry import RetrySettings
from ddsc.exceptions import DDSUserException

class UnexpectedPagingReceivedError(Exception):
    MESSAGE = """Received unexpected paging data in single item response.
This may be due to an incompatible DukeDS API change.
Try upgrading ddsclient: pip install --upgrade DukeDSClient
"""

    def __init__(self):
        super(UnexpectedPagingReceivedError, self).__init__(self.MESSAGE)


def retry_until_resource_is_consistent(func, monitor):
    """
    Runs func, if func raises DSResourceNotConsistentError will retry func indefinitely.
    Notifies monitor if we have to wait(only happens if DukeDS API raises DSResourceNotConsistentError.
    :param func: func(): function to run
    :param monitor: object: has start_waiting() and done_waiting() methods when waiting for non-consistent resource
    :return: whatever func returns
    """
    waiting = False
    while True:
        try:
            resp = func()
            if waiting and monitor:
                monitor.done_waiting()
            return resp
        except DSResourceNotConsistentError:
            if not waiting and monitor:
                monitor.start_waiting()
                waiting = True

# Path: ddsc/config.py
# def get_user_config_filename():
#     user_config_filename = os.environ.get(LOCAL_CONFIG_ENV)
#     if user_config_filename:
#         return user_config_filename
#     else:
#         return LOCAL_CONFIG_FILENAME
# 
# Path: ddsc/versioncheck.py
# APP_NAME = "DukeDSClient"
# 
# def get_internal_version_str():
#     """
#     Returns internal version string.
#     """
#     return pkg_resources.get_distribution(APP_NAME).version
# 
# Path: ddsc/core/retry.py
# class RetrySettings(object):
#     # DukeDS API Retry Settings
#     # Settings for retrying a ConnectionError connecting to the DukeDS API
#     CONNECTION_RETRY_TIMES = 5
#     CONNECTION_RETRY_SECONDS = 1
#     # Settings for how long to sleep when we receive 503 from DukeDS API (Weekly system maintenance typically)
#     SERVICE_DOWN_RETRY_SECONDS = 60
#     # How long to sleep when waiting for DukeDS API to be consistent (waits forever)
#     RESOURCE_NOT_CONSISTENT_RETRY_SECONDS = 2
# 
#     # Backend Store Retry Settings
#     # Settings for retrying when a ConnectionError occurs uploading a file chunk
#     SEND_EXTERNAL_PUT_RETRY_TIMES = 4
#     SEND_EXTERNAL_RETRY_SECONDS = 20
#     # Times to retry after receiving a 403 uploading a file chunk (we recreate the URL before retrying)
#     SEND_EXTERNAL_FORBIDDEN_RETRY_TIMES = 2
#     # Settings for retrying when downloading part of a file
#     FETCH_EXTERNAL_PUT_RETRY_TIMES = 5
#     FETCH_EXTERNAL_RETRY_SECONDS = 20
# 
# Path: ddsc/exceptions.py
# class DDSUserException(Exception):
#     """
#     Exception with an error message to be displayed to the user on the command line.
#     """
#     pass


# Path: ddsc/core/ddsapi.py
import json
import requests
import time
import datetime
from ddsc.config import get_user_config_filename
from ddsc.versioncheck import APP_NAME, get_internal_version_str
from ddsc.core.retry import RetrySettings
from ddsc.exceptions import DDSUserException


class UnexpectedPagingReceivedError(Exception):
    MESSAGE = """Received unexpected paging data in single item response.
This may be due to an incompatible DukeDS API change.
Try upgrading ddsclient: pip install --upgrade DukeDSClient
"""

    def __init__(self):
        super(UnexpectedPagingReceivedError, self).__init__(self.MESSAGE)


def retry_until_resource_is_consistent(func, monitor):
    """
    Runs func, if func raises DSResourceNotConsistentError will retry func indefinitely.
    Notifies monitor if we have to wait(only happens if DukeDS API raises DSResourceNotConsistentError.
    :param func: func(): function to run
    :param monitor: object: has start_waiting() and done_waiting() methods when waiting for non-consistent resource
    :return: whatever func returns
    """
    waiting = False
    while True:
        try:
            resp = func()
            if waiting and monitor:
                monitor.done_waiting()
            return resp
        except DSResourceNotConsistentError:
            if not waiting and monitor:
                monitor.start_waiting()
                waiting = True

            time.sleep(RetrySettings.RESOURCE_NOT_CONSISTENT_RETRY_SECONDS)