# Path: crosscompute/constants.py
# FUNCTION_BY_NAME = {
#     'slug': format_slug,
#     'title': str.title,
# }
# 
# MAXIMUM_FILE_CACHE_LENGTH = 256
# 
# VARIABLE_ID_PATTERN = re.compile(r'{\s*([^}]+?)\s*}')
# 
# Path: crosscompute/exceptions.py
# class CrossComputeConfigurationError(CrossComputeError):
#     pass
# 
# class CrossComputeDataError(CrossComputeError):
#     pass
# 
# Path: crosscompute/macros/disk.py
# class FileCache(LRUDict):
# 
#     def __init__(self, *args, load_file_data, maximum_length: int, **kwargs):
#         super().__init__(*args, maximum_length=maximum_length, **kwargs)
#         self._load_file_data = load_file_data
# 
#     def __getitem__(self, path):
#         if path in self:
#             file_time, file_data = super().__getitem__(path)
#             if getmtime(path) == file_time:
#                 return file_data
#         file_data = self._load_file_data(path)
#         self.__setitem__(path, file_data)
#         return file_data
# 
#     def __setitem__(self, path, data):
#         value = (getmtime(path), data)
#         super().__setitem__(path, value)
# 
# Path: crosscompute/macros/package.py
# def import_attribute(attribute_string):
#     module_string, attribute_name = attribute_string.rsplit('.', maxsplit=1)
#     return getattr(import_module(module_string), attribute_name)
# 
# Path: crosscompute/macros/web.py
# def get_html_from_markdown(text):
#     html = markdown(text)
#     if '</p>\n<p>' not in html:
#         html = html.removeprefix('<p>')
#         html = html.removesuffix('</p>')
#     return html
# 
# Path: crosscompute/routines/interface.py
# class Batch(ABC):
# 
#     def get_data(self, variable_definition):
#         '''
#         Get the data of the variable in one of the following formats:
#         {}
#         {'value': 1}
#         {'path': '/a/b/c.png'}
#         {'uri': 'upload:xyz'}
#         {'error': 'message'}
#         '''
#         return {}
# 
#     def get_data_uri(self, variable_definition):
#         'Get the resolved variable data uri'
#         return ''
# 
#     def get_data_configuration(self, variable_definition):
#         'Get the resolved variable configuration'
#         return {}


import csv
import json
import shutil
from dataclasses import dataclass
from importlib_metadata import entry_points
from invisibleroads_macros_log import format_path
from logging import getLogger
from os.path import basename, exists
from string import Template
from ..constants import (
    FUNCTION_BY_NAME,
    MAXIMUM_FILE_CACHE_LENGTH,
    VARIABLE_ID_PATTERN)
from ..exceptions import (
    CrossComputeConfigurationError,
    CrossComputeDataError)
from ..macros.disk import FileCache
from ..macros.package import import_attribute
from ..macros.web import get_html_from_markdown
from .interface import Batch

def get_data_by_id_from_folder(folder, variable_definitions):
    data_by_id = {}
    for variable_definition in variable_definitions:
        variable_id = variable_definition.id
        variable_path = variable_definition.path
        variable_data = load_variable_data(folder / variable_path, variable_id)
        data_by_id[variable_id] = variable_data
    return data_by_id


def yield_data_by_id_from_csv(path, variable_definitions):
    try:
        with path.open('rt') as f:
            csv_reader = csv.reader(f)
            keys = [_.strip() for _ in next(csv_reader)]
            for values in csv_reader:
                data_by_id = {k: {'value': v} for k, v in zip(keys, values)}
                data_by_id = parse_data_by_id(data_by_id, variable_definitions)
                if data_by_id.get('#') == '#':
                    continue
                yield data_by_id
    except OSError as e:
        raise CrossComputeConfigurationError(e)
    except StopIteration:
        pass


def yield_data_by_id_from_txt(path, variable_definitions):
    if len(variable_definitions) > 1:

# Path: crosscompute/constants.py
# FUNCTION_BY_NAME = {
#     'slug': format_slug,
#     'title': str.title,
# }
# 
# MAXIMUM_FILE_CACHE_LENGTH = 256
# 
# VARIABLE_ID_PATTERN = re.compile(r'{\s*([^}]+?)\s*}')
# 
# Path: crosscompute/exceptions.py
# class CrossComputeConfigurationError(CrossComputeError):
#     pass
# 
# class CrossComputeDataError(CrossComputeError):
#     pass
# 
# Path: crosscompute/macros/disk.py
# class FileCache(LRUDict):
# 
#     def __init__(self, *args, load_file_data, maximum_length: int, **kwargs):
#         super().__init__(*args, maximum_length=maximum_length, **kwargs)
#         self._load_file_data = load_file_data
# 
#     def __getitem__(self, path):
#         if path in self:
#             file_time, file_data = super().__getitem__(path)
#             if getmtime(path) == file_time:
#                 return file_data
#         file_data = self._load_file_data(path)
#         self.__setitem__(path, file_data)
#         return file_data
# 
#     def __setitem__(self, path, data):
#         value = (getmtime(path), data)
#         super().__setitem__(path, value)
# 
# Path: crosscompute/macros/package.py
# def import_attribute(attribute_string):
#     module_string, attribute_name = attribute_string.rsplit('.', maxsplit=1)
#     return getattr(import_module(module_string), attribute_name)
# 
# Path: crosscompute/macros/web.py
# def get_html_from_markdown(text):
#     html = markdown(text)
#     if '</p>\n<p>' not in html:
#         html = html.removeprefix('<p>')
#         html = html.removesuffix('</p>')
#     return html
# 
# Path: crosscompute/routines/interface.py
# class Batch(ABC):
# 
#     def get_data(self, variable_definition):
#         '''
#         Get the data of the variable in one of the following formats:
#         {}
#         {'value': 1}
#         {'path': '/a/b/c.png'}
#         {'uri': 'upload:xyz'}
#         {'error': 'message'}
#         '''
#         return {}
# 
#     def get_data_uri(self, variable_definition):
#         'Get the resolved variable data uri'
#         return ''
# 
#     def get_data_configuration(self, variable_definition):
#         'Get the resolved variable configuration'
#         return {}


# Path: crosscompute/routines/variable.py
import csv
import json
import shutil
from dataclasses import dataclass
from importlib_metadata import entry_points
from invisibleroads_macros_log import format_path
from logging import getLogger
from os.path import basename, exists
from string import Template
from ..constants import (
    FUNCTION_BY_NAME,
    MAXIMUM_FILE_CACHE_LENGTH,
    VARIABLE_ID_PATTERN)
from ..exceptions import (
    CrossComputeConfigurationError,
    CrossComputeDataError)
from ..macros.disk import FileCache
from ..macros.package import import_attribute
from ..macros.web import get_html_from_markdown
from .interface import Batch


def get_data_by_id_from_folder(folder, variable_definitions):
    data_by_id = {}
    for variable_definition in variable_definitions:
        variable_id = variable_definition.id
        variable_path = variable_definition.path
        variable_data = load_variable_data(folder / variable_path, variable_id)
        data_by_id[variable_id] = variable_data
    return data_by_id


def yield_data_by_id_from_csv(path, variable_definitions):
    try:
        with path.open('rt') as f:
            csv_reader = csv.reader(f)
            keys = [_.strip() for _ in next(csv_reader)]
            for values in csv_reader:
                data_by_id = {k: {'value': v} for k, v in zip(keys, values)}
                data_by_id = parse_data_by_id(data_by_id, variable_definitions)
                if data_by_id.get('#') == '#':
                    continue
                yield data_by_id
    except OSError as e:
        raise CrossComputeConfigurationError(e)
    except StopIteration:
        pass


def yield_data_by_id_from_txt(path, variable_definitions):
    if len(variable_definitions) > 1:

        raise CrossComputeConfigurationError(