# AUTOGENERATED! DO NOT EDIT! File to edit: nbs/00_core.ipynb (unless otherwise specified).

__all__ = ['create_session', 'create_cached_session', 'get_max_workers', 'load_url_image', 'save_image',
           'download_image', 'parse_box', 'create_iiif_url', 'iiif_df_apply', 'image_extensions', 'bytesto']

# Cell
import math
import mimetypes
import pathlib
from pathlib import Path
import PIL
from PIL import Image  # UnidentifiedImageError
import io
import pandas as pd
import multiprocessing
import requests
import requests_cache
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

from typing import (
    Any,
    Optional,
    Union,
    Dict,
    List,
    Tuple,
    Set,
    Iterable,
)

# Cell
def create_session() -> requests.sessions.Session:
    """returns a requests session"""
    retry_strategy = Retry(total=80)
    adapter = HTTPAdapter(max_retries=retry_strategy)
    session = requests.Session()
    session.mount("https://", adapter)
    session.mount("http://", adapter)
    return session

# Cell
def create_cached_session() -> requests_cache.CachedSession:
    """Creates a session which caches requests"""
    retry_strategy = Retry(total=80)
    adapter = HTTPAdapter(max_retries=retry_strategy)
    session = requests_cache.CachedSession("url_cache")
    session.mount("http://", adapter)
    return session

# Cell
def get_max_workers(data=None) -> int:
    """Returns int to pass to max_workers based on len of `data` if available or `cpu_count()`"""
    if data is not None and hasattr(data, "__len__"):
        return min(multiprocessing.cpu_count(), len(data))
    else:
        return multiprocessing.cpu_count()

# Cell
def load_url_image(url: str, mode="RGB") -> Union[PIL.Image.Image, None]:
    "Attempts to load an image from `url` returns `None` if request times out or no image at `url`"
    im = None
    session = create_session()
    with session.get(url, timeout=(30)) as r:
        if r:
            try:
                im = (Image.open(io.BytesIO(r.content))).convert(mode)
            except:
                pass
        return im

# Cell
def save_image(
    im: PIL.Image.Image, fname: str, out_dir: Union[str, pathlib.Path] = "."
):
    """Saves `im` as `fname` to `out_dir`"""
    out_path = Path(f"{out_dir}/{fname}")
    im.save(out_path)

# Cell
def download_image(
    url: str, fname: str, out_dir: Union[str, pathlib.Path] = "."
) -> None:
    """
    Attempts to load image from `url` and save as `fname` to `out_dir`
    Returns `None` if bad URL or request timesout
    """
    im = load_url_image(url)
    if im:
        save_image(im, fname, out_dir)
    else:
        return None

# Cell
def parse_box(box: Union[Tuple, List]) -> Tuple[float, float, float, float]:
    """Parses the `box` value from Newspaper Navigator data to prepre for IIIF request"""
    box_x1, box_x2, box_y1, box_y2 = box
    x = math.floor(box_x1 * 10000) / 100.0
    y = math.ceil(box_x2 * 10000) / 100.0
    w = math.ceil((box_y1 - box_x1) * 10000) / 100.0
    h = math.ceil((box_y2 - box_x2) * 10000) / 100.0
    return x, y, w, h

# Cell
def create_iiif_url(
    box: Union[Tuple, List],
    url: str,
    original: bool = False,
    pct: int = None,
    size: tuple = None,
    preserve_asp_ratio: bool = True,
) -> Union[str, None]:
    """Returns a IIIF URL from bounding box and URL"""

    x, y, w, h = parse_box(box)
    url_coordinates = "pct:" + str(x) + "," + str(y) + "," + str(w) + "," + str(h)
    url_chronam_path = "%2F".join(url.split("/")[4:10]) + ".jp2"

    url_prefix = "https://chroniclingamerica.loc.gov/iiif/2"
    if original and not size and not pct:
        url_suffix_full = "pct:100/0/default.jpg"
        return "/".join(
            [url_prefix, url_chronam_path, url_coordinates, url_suffix_full]
        )
    if pct:
        pct_downsampled = f"pct:{pct}/0/default.jpg"
        return "/".join(
            [url_prefix, url_chronam_path, url_coordinates, pct_downsampled]
        )
    if size and preserve_asp_ratio:
        return "/".join(
            [
                url_prefix,
                url_chronam_path,
                url_coordinates,
                f"!{size[0]},{size[1]}/0/default.jpg",
            ]
        )
    if size:
        return "/".join(
            [
                url_prefix,
                url_chronam_path,
                url_coordinates,
                f"{size[0]},{size[1]}/0/default.jpg",
            ]
        )

# Cell
def iiif_df_apply(
    row,
    original: bool = False,
    pct: int = 50,
    size: tuple = None,
    preserve_asp_ratio: bool = True,
):
    """Creates IIIF urls from a pandas DataFrame containing newspaper navigator data"""
    return create_iiif_url(
        row["box"],
        row["url"],
        original=original,
        pct=pct,
        size=size,
        preserve_asp_ratio=preserve_asp_ratio,
    )

# Cell
image_extensions = set(
    k for k, v in mimetypes.types_map.items() if v.startswith("image/")
)

# Cell
def bytesto(bytes, to: str, bsize: int = 1024) -> float:
    """Takes bytes and returns value convereted to `to`"""
    a = {"k": 1, "m": 2, "g": 3, "t": 4, "p": 5, "e": 6}
    r = float(bytes)
    return bytes / (bsize ** a[to])