"""
Picklify is a function that works similar to memoization; it is meant for
functions that return a dictionary. Often, such functions will parse a file to
generate a dictionary that maps certain keys to values. To save on such
overhead costs, we "picklify" them the first time they are called (save the
dictionary in a pickle file), and then simply load the dictionary from the
saved pickle files the next time around.

"""
import pickle
from pathlib import Path

from .config import PICKLE_PATH


def picklify(dict_generator, *args, **kwargs):
    """
    Given a function that returns an object such as a dictionary (only dict
    fully supported), returns the dictionary generated by the function. The
    function is only called if it has not been "picklified" (passed as an
    argument to this function) before. Otherwise, its cached dictionary is
    returned instead. Thus getting the dicttionary by wrapping this function
    speeds up the dictionary creation overall.

    Note that this function should not be called by two different functions
    with the same name.

    :param dict_generator: the function which generates a dictionary.
    :param *args: Any args to pass to the dictionary
    :param **kwargs: Any keyword args to pass to the dictionary.
    :returns: dictionary returned by dict_generator().

    """
    # Danger! Never call picklify with functions that have the same name!
    pickle_path = f"{PICKLE_PATH}/{dict_generator.__name__}.pickle"

    try:
        with open(pickle_path, "rb") as pickle_handle:
            dict_to_return = pickle.load(pickle_handle)
    except FileNotFoundError:
        dict_to_return = dict_generator(*args, **kwargs)
        Path(pickle_path).parent.mkdir(parents=True, exist_ok=True)
        with open(pickle_path, "wb") as pickle_handle:
            pickle.dump(
                dict_to_return, pickle_handle, protocol=pickle.HIGHEST_PROTOCOL
            )
    return dict_to_return
