from juriscraper.AbstractSite import logger


class DeferringList:
    """This object can be used to do deferred loading of meta data in the case
    that a piece of meta data requires some special work to obtain.

    Note that since this inherits from object (rather than list), it won't be
    sorted by the _date_sort function. As a result, it's vital that the code
    using this object provide the seed data in sorted order. Failure to do so
    will result in mixed up data being sent to the caller -- a bad fate.

    For an example of how this can be used, see
    juriscraper.opinions.united_states.state.tex
    """

    def __init__(self, *args, **kwargs):
        logger.warning(
            "Using DeferringList object which cannot be sorted until "
            "fetched. Note that in usual processing, the fetching "
            "happens before the sorting, so this is OK."
        )
        logger.info(
            f"DeferringList has {len(kwargs['seed'])} entries to fetch."
        )
        self._data = kwargs["seed"]
        self._fetched_items = [False] * len(kwargs["seed"])
        self._fetching_function = kwargs["fetcher"]

    def __iter__(self):
        for item in range(0, len(self._data)):
            if self._fetched_items[item]:
                yield self._data[item]
            else:
                yield self.__getitem__(item)

    def __getitem__(self, item):
        if self._fetched_items[item]:
            return self._data[item]
        else:
            # Go get the item using the fetching function
            logger.info(
                f"Getting deferred value from seed: {self._data[item]}"
            )
            new_val = self._fetching_function(self._data[item])
            self._data[item] = new_val
            self._fetched_items[item] = True
            return new_val

    def __setitem__(self, key, value):
        if self._fetched_items[key]:
            self._data[key] = value
        else:
            raise AttributeError(
                "Cannot set item that has not yet been fetched."
            )

    def __delitem__(self, item):
        del self._data[item]
        del self._fetched_items[item]

    def __len__(self):
        return len(self._data)

    def __str__(self):
        return f"<DeferringList {self.__dict__}>"
