# Copyright 2017 Free Software Foundation, Inc.
# This file is part of GNU Radio
#
# SPDX-License-Identifier: GPL-2.0-or-later
#


from io import open
import json
import logging
import os

from .io import yaml

logger = logging.getLogger(__name__)


class Cache(object):

    def __init__(self, filename):
        self.cache_file = filename
        self.cache = {}
        self.need_cache_write = True
        self._accessed_items = set()
        try:
            os.makedirs(os.path.dirname(filename))
        except OSError:
            pass
        try:
            self._converter_mtime = os.path.getmtime(filename)
        except OSError:
            self._converter_mtime = -1

    def load(self):
        try:
            logger.debug("Loading block cache from: {}".format(self.cache_file))
            with open(self.cache_file, encoding='utf-8') as cache_file:
                self.cache = json.load(cache_file)
            self.need_cache_write = False
        except (IOError, ValueError):
            self.need_cache_write = True

    def get_or_load(self, filename):
        self._accessed_items.add(filename)
        if os.path.getmtime(filename) <= self._converter_mtime:
            try:
                return self.cache[filename]
            except KeyError:
                pass

        with open(filename, encoding='utf-8') as fp:
            data = yaml.safe_load(fp)
        self.cache[filename] = data
        self.need_cache_write = True
        return data

    def save(self):
        if not self.need_cache_write:
            return

        logger.debug('Saving %d entries to json cache', len(self.cache))
        # Dumping to binary file is only supported for Python3 >= 3.6
        with open(self.cache_file, 'w', encoding='utf8') as cache_file:
            cache_file.write(json.dumps(self.cache, ensure_ascii=False))

    def prune(self):
        for filename in (set(self.cache) - self._accessed_items):
            del self.cache[filename]

    def __enter__(self):
        self.load()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.save()


def byteify(data):
    if isinstance(data, dict):
        return {byteify(key): byteify(value) for key, value in data.items()}
    elif isinstance(data, list):
        return [byteify(element) for element in data]
    else:
        return data
