# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_core.ipynb.

# %% auto 0
__all__ = ['Client']

# %% ../nbs/00_core.ipynb 3
import json
import math
import os

# %% ../nbs/00_core.ipynb 4
class Client:
    """
    A class to represent a client for managing canvas information.
    """
    def __init__(self, canvas_uri, gcv_path, manifest_path, output_annolist_path, output_manifest_path):
        """
        Initialize the Client object with the given parameters.

        Args:
            canvas_uri (str): The canvas URI.
            gcv_path (str): The path to the Google Cloud Vision data.
            manifest_path (str): The path to the manifest data.
            output_annolist_path (str): The output path for the annotation list.
            output_manifest_path (str): The output path for the manifest.
        """
        self.canvas_uri = canvas_uri
        self.gcv_path = gcv_path
        self.manifest_path = manifest_path
        self.output_annolist_path = output_annolist_path
        self.output_manifest_path = output_manifest_path

    def get_size(self):
        """
        Retrieve the size of the canvas.

        Returns:
            Tuple containing the width and height of the canvas, or (None, None) if not found.
        """
        with open(self.manifest_path, "r") as f:
            manifest = json.load(f)

        for canvas in manifest["sequences"][0]["canvases"]:
            if canvas["@id"] == self.canvas_uri:
                return canvas["width"], canvas["height"]

        return None, None

    @staticmethod
    def get_xywh(word):
        """
        Calculate the position and size of a word in an image.

        Args:
            word (dict): A word dictionary containing bounding box information.

        Returns:
            A tuple (x, y, w, h) representing the position (x, y) and size (w, h).
        """
        x = word["boundingBox"]["vertices"][0]["x"]
        y = word["boundingBox"]["vertices"][0]["y"]
        w = word["boundingBox"]["vertices"][1]["x"] - x
        h = word["boundingBox"]["vertices"][2]["y"] - y
        return x,y,w,h

    def create_annotation_list(self, size=-1):
        """
        Create an annotation list for the given canvas.

        Args:
            size (int, optional): The number of annotations to create. If negative, all annotations are created.
        """
        canvas_w, canvas_h = self.get_size()

        if canvas_w is None or canvas_h is None:
            raise ValueError("Failed to retrieve canvas size.")

        with open(self.gcv_path, "r") as f:
            test = json.load(f)

        full_text_annotation = test["fullTextAnnotation"]
        page = full_text_annotation["pages"][0]
        page_w = page["width"]
        page_h = page["height"]
        blocks = page["blocks"]
        annotations = []

        for block in blocks:
            for paragraph in block["paragraphs"]:
                for word in paragraph["words"]:
                    word_str = "".join([symbol["text"] for symbol in word["symbols"]])
                    x,y,w,h = self.get_xywh(word)

                    x = math.ceil(x / page_w * canvas_w)
                    y = math.ceil(y / page_h * canvas_h)
                    w = math.ceil(w / page_w * canvas_w)
                    h = math.ceil(h / page_h * canvas_h)

                    aid = f"a-{x}-{y}-{w}-{h}"

                    anno = {
                        "@context": "http://iiif.io/api/presentation/2/context.json",
                        "@type": "oa:Annotation",
                        "motivation": "oa:commenting",
                        "resource": {
                            "@type": "cnt:ContentAsText",
                            "chars": f"{aid}: {word_str}",
                            "format": "text/plain"
                        },
                        "on": f"{self.canvas_uri}#xywh={x},{y},{w},{h}",
                        "@id": f"{self.canvas_uri}/annotation/p{x},{y},{w},{h}"
                    }

                    annotations.append(anno)

        if size > 0:
            annotations = annotations[:size]

        anno_list = {
            "@context": "http://iiif.io/api/presentation/2/context.json",
            "@type": "sc:AnnotationList",
            "resources": annotations
        }

        os.makedirs(os.path.dirname(self.output_annolist_path), exist_ok=True)

        with open(self.output_annolist_path, "w") as f:
            json.dump(anno_list, f, ensure_ascii=False, indent=4)

    def create_manifest(self, annolist_url):
        """
        Create a manifest file containing the given annotation list URL.

        Args:
            annolist_url (str): The URL of the annotation list.
        """
        with open(self.manifest_path, "r") as f:
            manifest = json.load(f)

        for canvas in manifest["sequences"][0]["canvases"]:
            if canvas["@id"] == self.canvas_uri:
                canvas["otherContent"] = [
                    {
                        "@id": annolist_url,
                        "@type": "sc:AnnotationList"
                    }
                ]
                break

        with open(self.output_manifest_path, "w") as f:
            json.dump(manifest, f, ensure_ascii=False, indent=4)
