# 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):
        """
        クライアントオブジェクトを指定されたパラメータで初期化します。

        Parameters
        ----------
        canvas_uri : str
            キャンバスのURI。
        gcv_path : str
            Google Cloud Visionデータへのパス。
        manifest_path : str
            マニフェストデータへのパス。
        output_annolist_path : str
            アノテーションリストの出力パス。
        output_manifest_path : str
            マニフェストの出力パス。
        """

        self.canvas_uri = canvas_uri  # キャンバスのURIを設定
        self.gcv_path = gcv_path  # Google Cloud Visionデータへのパスを設定
        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):
        """
        画像内の単語の位置とサイズを計算します。

        Parameters
        ----------
        word : dict
            バウンディングボックス情報を含む単語の辞書。

        Returns
        -------
        tuple
            位置(x, y)とサイズ(w, h)を表すタプル(x, y, w, h)。

        Examples
        --------
        >>> word = {"boundingBox": {"vertices": [{"x": 5, "y": 10}, {"x": 15, "y": 10}, {"x": 15, "y": 20}, {"x": 5, "y": 20}]}}
        >>> get_xywh(word)
        (5, 10, 10, 10)
        """

        x = word["boundingBox"]["vertices"][0]["x"]  # x座標を取得
        y = word["boundingBox"]["vertices"][0]["y"]  # 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):
        """
        指定されたキャンバスの注釈リストを作成します。

        キャンバスサイズに基づいて、Google Cloud Visionから得られたデータを用いて、
        IIIF注釈リストを作成します。

        Parameters
        ----------
        size : int, optional
            作成する注釈の数。負の場合、すべての注釈が作成されます。デフォルトは-1。

        Raises
        ------
        ValueError
            キャンバスサイズを取得できない場合。

        Examples
        --------
        >>> create_annotation_list(10) # 最初の10個の注釈を作成
        """

        canvas_w, canvas_h = self.get_size()  # キャンバスのサイズを取得

        if canvas_w is None or canvas_h is None:
            raise ValueError("キャンバスのサイズを取得できませんでした。")

        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)

                    # 注釈を作成
                    anno = {
                        "@context": "http://iiif.io/api/presentation/2/context.json",
                        "@type": "oa:Annotation",
                        "motivation": "oa:commenting",
                        "resource": {
                            "@type": "cnt:ContentAsText",
                            "chars": 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):
        """
        与えられた注釈リストURLを含むマニフェストファイルを作成します。

        既存のマニフェストに対して、特定のキャンバスURIに関連付けられた注釈リストのURLを追加します。
        結果のマニフェストは指定された出力パスに保存されます。

        Parameters
        ----------
        annolist_url : str
            注釈リストのURL。

        Examples
        --------
        >>> create_manifest("http://example.com/annotation_list.json")
        """

        # 既存のマニフェストを開きます。
        with open(self.manifest_path, "r") as f:
            manifest = json.load(f)

        # 対象のキャンバスを探して、注釈リストのURLを追加します。
        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)
