# Path: opendiamond/dataretriever/pyramid.py
# def stat_gigapan(gigapan_id):
#     """Uses the web API to look up width, height, etc. for a given gigapan."""
#     try:
#         api_url = 'http://api.gigapan.org/beta/gigapans/%d.json' % gigapan_id
# 
#         def http_get(url):
#             return urllib.request.urlopen(url).read()
# 
#         api_response = json.loads(http_get(api_url))
#         assert int(api_response.get('id')) == int(gigapan_id)
#         return api_response
#     except Exception:
#         print("Couldn't parse the data returned by %s." % \
#             api_url, file=sys.stderr)
#         raise
# 
# def round_up(x):  # pylint: disable=invalid-name
#     """Returns the smallest integer N such that
#        N is not less than the given.
#     """
#     return int(ceil(x))
# 
# def log_2(x):  # pylint: disable=invalid-name
#     """Returns the smallest integer N such that
#        2**N is not less than the given.
#     """
#     assert x > 0 and int(x) == x
#     n = 0
#     x = x - 1
#     while x > 0:
#         x = x >> 1
#         n = n + 1
#     return n
# 
# def iter_coords(width, height, max_depth=None, tile_size=256):
#     """Yields (level, column, row) coordinates for all levels of the
#        pyramid for an image with the given width and height.
#     """
#     tiles_wide = round_up(width / float(tile_size))
#     tiles_high = round_up(height / float(tile_size))
#     levels_deep = log_2(max(tiles_wide, tiles_high)) + 1
# 
#     def inv(lvl):
#         return levels_deep - lvl - 1
# 
#     def columns_at_level(lvl):
#         return round_up(tiles_wide / float(1 << inv(lvl)))
# 
#     def rows_at_level(lvl):
#         return round_up(tiles_high / float(1 << inv(lvl)))
# 
#     for lvl in range(0, levels_deep):
#         if max_depth:
#             if lvl > int(max_depth):
#                 break
#         ncols = columns_at_level(lvl)
#         nrows = rows_at_level(lvl)
#         # print >> sys.stderr, "Checking level %d: %d columns and %d rows" % (
#         #    lvl, ncols, nrows)
#         for col in range(0, ncols):
#             for row in range(0, nrows):
#                 yield lvl, col, row
# 
# def path_to_tile(level, column, row):
#     """ Computes the path to a tile from the given pyramid coordinates.
#         For example,
# 
#         >>> path_to_tile(level=5, column=5, row=3)
#         'r00/r00123'
#         >>> path_to_tile(5, 5, 5)
#         'r00/r00303'
#     """
#     gc_tile = ['0', '1', '2', '3']
#     fn = 'r'
#     path = ''
#     for n in range(level-1, -1, -1):
#         bit = 1 << n
#         index = 0
#         if (column & bit) != 0:
#             index = 1
#         if (row & bit) != 0:
#             index += 2
#         fn += gc_tile[index]
#     for i in range(0, len(fn) - 3, 3):
#         path += '/' + fn[i:i+3]
#     return (path + '/' + fn + ".jpg").lstrip('/')


from future import standard_library
from builtins import next
from builtins import str
from builtins import range
from builtins import object
from past.utils import old_div
from datetime import datetime, timedelta
from threading import Lock
from urllib.request import urlopen
from io import StringIO
from PIL import Image
from flask import Blueprint, Response, stream_with_context, send_file, url_for
from opendiamond.dataretriever.pyramid import stat_gigapan, round_up, log_2, \
    iter_coords, path_to_tile
from werkzeug.datastructures import Headers


class GigaPanInfoCache(object):
    def __init__(self):
        self._cache = {}
        self._lock = Lock()

    def __getitem__(self, gigapan_id):
        with self._lock:
            if gigapan_id not in self._cache:
                self._cache[gigapan_id] = stat_gigapan(gigapan_id)
            return self._cache[gigapan_id]


_gigapan_info_cache = GigaPanInfoCache()


def tiles_in_gigapan(width, height):
    """Modified from pyramid.iter_coords()."""
    tiles_wide = round_up(width / float(TILE_SIZE))
    tiles_high = round_up(height / float(TILE_SIZE))
    levels_deep = log_2(max(tiles_wide, tiles_high)) + 1

    def inv(lvl):
        return levels_deep - lvl - 1

    def columns_at_level(lvl):
        return round_up(tiles_wide / float(1 << inv(lvl)))

    def rows_at_level(lvl):

# Path: opendiamond/dataretriever/pyramid.py
# def stat_gigapan(gigapan_id):
#     """Uses the web API to look up width, height, etc. for a given gigapan."""
#     try:
#         api_url = 'http://api.gigapan.org/beta/gigapans/%d.json' % gigapan_id
# 
#         def http_get(url):
#             return urllib.request.urlopen(url).read()
# 
#         api_response = json.loads(http_get(api_url))
#         assert int(api_response.get('id')) == int(gigapan_id)
#         return api_response
#     except Exception:
#         print("Couldn't parse the data returned by %s." % \
#             api_url, file=sys.stderr)
#         raise
# 
# def round_up(x):  # pylint: disable=invalid-name
#     """Returns the smallest integer N such that
#        N is not less than the given.
#     """
#     return int(ceil(x))
# 
# def log_2(x):  # pylint: disable=invalid-name
#     """Returns the smallest integer N such that
#        2**N is not less than the given.
#     """
#     assert x > 0 and int(x) == x
#     n = 0
#     x = x - 1
#     while x > 0:
#         x = x >> 1
#         n = n + 1
#     return n
# 
# def iter_coords(width, height, max_depth=None, tile_size=256):
#     """Yields (level, column, row) coordinates for all levels of the
#        pyramid for an image with the given width and height.
#     """
#     tiles_wide = round_up(width / float(tile_size))
#     tiles_high = round_up(height / float(tile_size))
#     levels_deep = log_2(max(tiles_wide, tiles_high)) + 1
# 
#     def inv(lvl):
#         return levels_deep - lvl - 1
# 
#     def columns_at_level(lvl):
#         return round_up(tiles_wide / float(1 << inv(lvl)))
# 
#     def rows_at_level(lvl):
#         return round_up(tiles_high / float(1 << inv(lvl)))
# 
#     for lvl in range(0, levels_deep):
#         if max_depth:
#             if lvl > int(max_depth):
#                 break
#         ncols = columns_at_level(lvl)
#         nrows = rows_at_level(lvl)
#         # print >> sys.stderr, "Checking level %d: %d columns and %d rows" % (
#         #    lvl, ncols, nrows)
#         for col in range(0, ncols):
#             for row in range(0, nrows):
#                 yield lvl, col, row
# 
# def path_to_tile(level, column, row):
#     """ Computes the path to a tile from the given pyramid coordinates.
#         For example,
# 
#         >>> path_to_tile(level=5, column=5, row=3)
#         'r00/r00123'
#         >>> path_to_tile(5, 5, 5)
#         'r00/r00303'
#     """
#     gc_tile = ['0', '1', '2', '3']
#     fn = 'r'
#     path = ''
#     for n in range(level-1, -1, -1):
#         bit = 1 << n
#         index = 0
#         if (column & bit) != 0:
#             index = 1
#         if (row & bit) != 0:
#             index += 2
#         fn += gc_tile[index]
#     for i in range(0, len(fn) - 3, 3):
#         path += '/' + fn[i:i+3]
#     return (path + '/' + fn + ".jpg").lstrip('/')


# Path: opendiamond/dataretriever/gigapan_store.py
from future import standard_library
from builtins import next
from builtins import str
from builtins import range
from builtins import object
from past.utils import old_div
from datetime import datetime, timedelta
from threading import Lock
from urllib.request import urlopen
from io import StringIO
from PIL import Image
from flask import Blueprint, Response, stream_with_context, send_file, url_for
from opendiamond.dataretriever.pyramid import stat_gigapan, round_up, log_2, \
    iter_coords, path_to_tile
from werkzeug.datastructures import Headers



class GigaPanInfoCache(object):
    def __init__(self):
        self._cache = {}
        self._lock = Lock()

    def __getitem__(self, gigapan_id):
        with self._lock:
            if gigapan_id not in self._cache:
                self._cache[gigapan_id] = stat_gigapan(gigapan_id)
            return self._cache[gigapan_id]


_gigapan_info_cache = GigaPanInfoCache()


def tiles_in_gigapan(width, height):
    """Modified from pyramid.iter_coords()."""
    tiles_wide = round_up(width / float(TILE_SIZE))
    tiles_high = round_up(height / float(TILE_SIZE))
    levels_deep = log_2(max(tiles_wide, tiles_high)) + 1

    def inv(lvl):
        return levels_deep - lvl - 1

    def columns_at_level(lvl):
        return round_up(tiles_wide / float(1 << inv(lvl)))

    def rows_at_level(lvl):

        return round_up(tiles_high / float(1 << inv(lvl)))