# Path: gogdb/core/dataclsloader.py
# def class_from_json(cls, data):
#     if data is None:
#         return None
#     if dataclasses.is_dataclass(cls):
#         if cls in annotations_cache:
#             annotations = annotations_cache.get(cls)
#         else:
#             annotations = typing.get_type_hints(cls)
#             annotations_cache[cls] = annotations
#         inst = cls()
#         for field_name, field_value in data.items():
#             try:
#                 field_type = annotations[field_name]
#             except KeyError:
#                 raise KeyError("Invalid field {!r} in json. Valid fields for type {}: {!r}".format(
#                     field_name, cls, list(annotations.keys())))
#             try:
#                 field_inst = class_from_json(field_type, field_value)
#             except TypeError:
#                 raise TypeError(f"Failed to parse field {field_name}")
#             setattr(inst, field_name, field_inst)
#         return inst
#     elif get_origin(cls) is list:
#         list_element_type = get_args(cls)[0]
#         return [
#             class_from_json(list_element_type, list_element) for
#             list_element in data]
#     elif cls is datetime.datetime:
#         return datetime.datetime.fromisoformat(data)
#     else:
#         if cls is not typing.Any:
#             if not (type(data) is cls or data is None):
#                 raise TypeError(f"{repr(data)} is of type {type(data)}, {cls} required")
#         return data


import dataclasses
import json
import datetime
import gzip
import os
import pathlib
import itertools
import string
import gogdb.core.model as model
from gogdb.core.dataclsloader import class_from_json


class Storage:
    def __init__(self, storage_path):
        self.storage_path = pathlib.Path(storage_path)

        self.ids = StorageItem(self.path_ids)
        self.token = StorageItem(self.path_token)
        self.product = StorageItem(self.path_product, self.make_product)
        self.repository = StorageItem(self.path_repository)
        self.prices = StorageItem(self.path_prices, self.make_prices)
        self.prices_old = StorageItem(self.path_prices_old, self.make_prices)
        self.changelog = StorageItem(self.path_changelog, self.make_changelog)
        self.manifest_v1 = StorageItem(self.path_manifest_v1, compressed=True)
        self.manifest_v2 = StorageItem(self.path_manifest_v2, compressed=True)

    def __repr__(self):
        return f"Storage({repr(self.storage_path)})"

    def path_ids(self):
        return self.storage_path / "ids.json"

    def path_token(self):
        return self.storage_path / "secret/token.json"

    def path_product(self, product_id):
        return self.storage_path / f"products/{product_id}/product.json"

    @staticmethod
    def make_product(json_data):

# Path: gogdb/core/dataclsloader.py
# def class_from_json(cls, data):
#     if data is None:
#         return None
#     if dataclasses.is_dataclass(cls):
#         if cls in annotations_cache:
#             annotations = annotations_cache.get(cls)
#         else:
#             annotations = typing.get_type_hints(cls)
#             annotations_cache[cls] = annotations
#         inst = cls()
#         for field_name, field_value in data.items():
#             try:
#                 field_type = annotations[field_name]
#             except KeyError:
#                 raise KeyError("Invalid field {!r} in json. Valid fields for type {}: {!r}".format(
#                     field_name, cls, list(annotations.keys())))
#             try:
#                 field_inst = class_from_json(field_type, field_value)
#             except TypeError:
#                 raise TypeError(f"Failed to parse field {field_name}")
#             setattr(inst, field_name, field_inst)
#         return inst
#     elif get_origin(cls) is list:
#         list_element_type = get_args(cls)[0]
#         return [
#             class_from_json(list_element_type, list_element) for
#             list_element in data]
#     elif cls is datetime.datetime:
#         return datetime.datetime.fromisoformat(data)
#     else:
#         if cls is not typing.Any:
#             if not (type(data) is cls or data is None):
#                 raise TypeError(f"{repr(data)} is of type {type(data)}, {cls} required")
#         return data


# Path: gogdb/core/storage.py
import dataclasses
import json
import datetime
import gzip
import os
import pathlib
import itertools
import string
import gogdb.core.model as model
from gogdb.core.dataclsloader import class_from_json



class Storage:
    def __init__(self, storage_path):
        self.storage_path = pathlib.Path(storage_path)

        self.ids = StorageItem(self.path_ids)
        self.token = StorageItem(self.path_token)
        self.product = StorageItem(self.path_product, self.make_product)
        self.repository = StorageItem(self.path_repository)
        self.prices = StorageItem(self.path_prices, self.make_prices)
        self.prices_old = StorageItem(self.path_prices_old, self.make_prices)
        self.changelog = StorageItem(self.path_changelog, self.make_changelog)
        self.manifest_v1 = StorageItem(self.path_manifest_v1, compressed=True)
        self.manifest_v2 = StorageItem(self.path_manifest_v2, compressed=True)

    def __repr__(self):
        return f"Storage({repr(self.storage_path)})"

    def path_ids(self):
        return self.storage_path / "ids.json"

    def path_token(self):
        return self.storage_path / "secret/token.json"

    def path_product(self, product_id):
        return self.storage_path / f"products/{product_id}/product.json"

    @staticmethod
    def make_product(json_data):

        return class_from_json(model.Product, json_data)