text: # -*- coding: utf-8 -*-
  
  import os
  import shelve
  
  from .common import cache_uri_build, sprite_filepath_build
  
  # Cache locations will be set at the end of this file.
  CACHE_DIR = None
  API_CACHE = None
  SPRITE_CACHE = None
  
  
  def save(data, endpoint, resource_id=None, subresource=None):
  
      if data == dict():  # No point in saving empty data.
          return None
  
      if not isinstance(data, (dict, list)):
          raise ValueError("Could not save non-dict data")
  
      uri = cache_uri_build(endpoint, resource_id, subresource)
  
      try:
          with shelve.open(API_CACHE) as cache:
              cache[uri] = data
      except OSError as error:
          if error.errno == 11:  # Cache open by another person/program
              # print('Cache unavailable, skipping save')
              pass
          else:
              raise error
  
      return None
  
  
  def save_sprite(data, sprite_type, sprite_id, **kwargs):
  
      abs_path = data["path"]
  
      # Make intermediate directories; this line removes the file+extension.
      dirs = abs_path.rpartition(os.path.sep)[0]
      safe_make_dirs(dirs)
  
      with open(abs_path, "wb") as img_file:
          img_file.write(data["img_data"])
  
      return None
  
  
  def load(endpoint, resource_id=None, subresource=None):
  
      uri = cache_uri_build(endpoint, resource_id, subresource)
  
      try:
          with shelve.open(API_CACHE) as cache:
              return cache[uri]
      except OSError as error:
          if error.errno == 11:
              # Cache open by another person/program
              # print('Cache unavailable, skipping load')
              raise KeyError("Cache could not be opened.")
          else:
              raise
  
  
  def load_sprite(sprite_type, sprite_id, **kwargs):
      abs_path = get_sprite_path(sprite_type, sprite_id, **kwargs)
  
      with open(abs_path, "rb") as img_file:
          img_data = img_file.read()
  
      return dict(img_data=img_data, path=abs_path)
  
  
  def safe_make_dirs(path, mode=0o777):
      """Create a leaf directory and all intermediate ones in a safe way.
  
      A wrapper to os.makedirs() that handles existing leaf directories while
      avoiding os.path.exists() race conditions.
  
      :param path: relative or absolute directory tree to create
      :param mode: directory permissions in octal
      :return: The newly-created path
      """
      try:
          os.makedirs(path, mode)
      except OSError as error:
          if error.errno != 17:  # File exists
              raise
  
      return path
  
  
  def get_default_cache():
      """Get the default cache location.
  
      Adheres to the XDG Base Directory specification, as described in
      https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
  
      :return: the default cache directory absolute path
      """
  
      xdg_cache_home = os.environ.get("XDG_CACHE_HOME") or os.path.join(
          os.path.expanduser("~"), ".cache"
      )
  
      return os.path.join(xdg_cache_home, "pokebase")
  
  
  def get_sprite_path(sprite_type, sprite_id, **kwargs):
      rel_filepath = sprite_filepath_build(sprite_type, sprite_id, **kwargs)
      abs_path = os.path.join(SPRITE_CACHE, rel_filepath)
  
      return abs_path
  
  
  def set_cache(new_path=None):
      """Simple function to change the cache location.
  
      `new_path` can be an absolute or relative path. If the directory does not
      exist yet, this function will create it. If None it will set the cache to
      the default cache directory.
  
      If you are going to change the cache directory, this function should be
      called at the top of your script, before you make any calls to the API.
      This is to avoid duplicate files and excess API calls.
  
      :param new_path: relative or absolute path to the desired new cache
      directory
      :return: str, str
      """
  
      global CACHE_DIR, API_CACHE, SPRITE_CACHE
  
      if new_path is None:
          new_path = get_default_cache()
  
      CACHE_DIR = safe_make_dirs(os.path.abspath(new_path))
      API_CACHE = os.path.join(CACHE_DIR, "api.cache")
      SPRITE_CACHE = safe_make_dirs(os.path.join(CACHE_DIR, "sprite"))
  
      return CACHE_DIR, API_CACHE, SPRITE_CACHE
  
  
  CACHE_DIR, API_CACHE, SPRITE_CACHE = set_cache()
  