# Path: app/hlds/models.py
# class Location:
#     def __init__(
#         self, id_, *, name, dishes, osm=None, address=None, telephone=None, website=None
#     ):
#         self.id: str = id_
#         self.name: str = name
#         self.osm: Optional[str] = osm
#         self.address: Optional[str] = address
#         self.telephone: Optional[str] = telephone
#         self.website: Optional[str] = website
# 
#         self.dishes: List[Dish] = dishes
# 
#     def dish_by_id(self, dish_id: str) -> Optional[Dish]:
#         return first(filter(lambda d: d.id == dish_id, self.dishes))
# 
#     def __str__(self):
#         return (
#             "============================\n"
#             "{0.id}: {0.name}"
#             "{1}\n"
#             "============================\n"
#             "\n"
#             "{2}"
#         ).format(
#             self,
#             "".join(
#                 "\n\t{} {}".format(k, v)
#                 for k, v in (
#                     ("osm", self.osm),
#                     ("address", self.address),
#                     ("telephone", self.telephone),
#                     ("website", self.website),
#                 )
#                 if v is not None
#             ),
#             "\n".join(map(str, self.dishes)),
#         )
# 
# class Choice:
#     def __init__(self, id_, *, name, description, options):
#         self.id: str = id_
#         self.name: str = name
#         self.description: str = description
# 
#         self.options: List[Option] = options
# 
#     def __str__(self):
#         return "{0.id}: {0.name}{1}\n\t\t{2}".format(
#             self,
#             " -- {}".format(self.description) if self.description else "",
#             "\n\t\t".join(map(str, self.options)),
#         )
# 
#     def option_by_id(self, option_id: str) -> Optional[Option]:
#         return first(filter(lambda o: o.id == option_id, self.options))
# 
# class Option:
#     def __init__(self, id_, *, name, description, price, tags):
#         self.id: str = id_
#         self.name: str = name
#         self.description: str = description
#         self.price: int = price
#         self.tags: List[str] = tags
# 
#     def __str__(self):
#         return "{0.id}: {0.name}{1}{2}{3}".format(
#             self,
#             " -- {}".format(self.description) if self.description else "",
#             _format_tags(self.tags),
#             _format_price(self.price),
#         )
# 
# class Dish:
#     def __init__(self, id_, *, name, description, price, tags, choices):
#         self.id: str = id_
#         self.name: str = name
#         self.description: str = description
#         self.price: int = price
#         self.tags: List[str] = tags
# 
#         # The str in (str, Choice) is the type of choice: single_choice or multi_choice
#         self.choices: List[(str, Choice)] = choices
# 
#     def __str__(self):
#         return "dish {0.id}: {0.name}{1}{2}{3}\n\t{4}".format(
#             self,
#             " -- {}".format(self.description) if self.description else "",
#             _format_tags(self.tags),
#             _format_price(self.price),
#             "\n\t".join(map(_format_type_and_choice, self.choices)),
#         )
# 
#     def price_range(self) -> Tuple[int, int]:
#         return (
#             self.price + self._sum_f_option_prices(min),
#             self.price + self._sum_f_option_prices(max),
#         )
# 
#     def _sum_f_option_prices(self, f):
#         return sum(
#             f(option.price for option in choice.options)
#             for (choice_type, choice) in self.choices
#             if choice_type == "single_choice"
#         )


from glob import glob
from os import path
from copy import deepcopy
from typing import Iterable, List, Union, Tuple
from tatsu import parse as tatsu_parse
from tatsu.ast import AST
from tatsu.exceptions import SemanticError
from .models import Location, Choice, Option, Dish
from utils import first
import itertools
            first_single_choice = first(
                c[1] for c in dish.choices if c[0] == "single_choice"
            )
            price_range = dish.price_range()
            if dish.price and price_range[0] != price_range[1] and first_single_choice:
                for option in first_single_choice.options:
                    option.price += dish.price
                dish.price = 0
        dishes = list(dishes)
        dishes.append(Dish(
            "custom",
            name="Vrije keuze",
            description="Zet wat je wil in comment",
            price=0,
            tags=[],
            choices=[],
        ))

        attributes = {att["key"]: att["value"] for att in ast["attributes"]}

        return Location(
            ast["id"],
            name=ast["name"],
            dishes=dishes,
            osm=attributes.get("osm"),
            address=attributes.get("address"),
            telephone=attributes.get("phone"),
            website=attributes.get("website"),
        )


# Path: app/hlds/models.py
# class Location:
#     def __init__(
#         self, id_, *, name, dishes, osm=None, address=None, telephone=None, website=None
#     ):
#         self.id: str = id_
#         self.name: str = name
#         self.osm: Optional[str] = osm
#         self.address: Optional[str] = address
#         self.telephone: Optional[str] = telephone
#         self.website: Optional[str] = website
# 
#         self.dishes: List[Dish] = dishes
# 
#     def dish_by_id(self, dish_id: str) -> Optional[Dish]:
#         return first(filter(lambda d: d.id == dish_id, self.dishes))
# 
#     def __str__(self):
#         return (
#             "============================\n"
#             "{0.id}: {0.name}"
#             "{1}\n"
#             "============================\n"
#             "\n"
#             "{2}"
#         ).format(
#             self,
#             "".join(
#                 "\n\t{} {}".format(k, v)
#                 for k, v in (
#                     ("osm", self.osm),
#                     ("address", self.address),
#                     ("telephone", self.telephone),
#                     ("website", self.website),
#                 )
#                 if v is not None
#             ),
#             "\n".join(map(str, self.dishes)),
#         )
# 
# class Choice:
#     def __init__(self, id_, *, name, description, options):
#         self.id: str = id_
#         self.name: str = name
#         self.description: str = description
# 
#         self.options: List[Option] = options
# 
#     def __str__(self):
#         return "{0.id}: {0.name}{1}\n\t\t{2}".format(
#             self,
#             " -- {}".format(self.description) if self.description else "",
#             "\n\t\t".join(map(str, self.options)),
#         )
# 
#     def option_by_id(self, option_id: str) -> Optional[Option]:
#         return first(filter(lambda o: o.id == option_id, self.options))
# 
# class Option:
#     def __init__(self, id_, *, name, description, price, tags):
#         self.id: str = id_
#         self.name: str = name
#         self.description: str = description
#         self.price: int = price
#         self.tags: List[str] = tags
# 
#     def __str__(self):
#         return "{0.id}: {0.name}{1}{2}{3}".format(
#             self,
#             " -- {}".format(self.description) if self.description else "",
#             _format_tags(self.tags),
#             _format_price(self.price),
#         )
# 
# class Dish:
#     def __init__(self, id_, *, name, description, price, tags, choices):
#         self.id: str = id_
#         self.name: str = name
#         self.description: str = description
#         self.price: int = price
#         self.tags: List[str] = tags
# 
#         # The str in (str, Choice) is the type of choice: single_choice or multi_choice
#         self.choices: List[(str, Choice)] = choices
# 
#     def __str__(self):
#         return "dish {0.id}: {0.name}{1}{2}{3}\n\t{4}".format(
#             self,
#             " -- {}".format(self.description) if self.description else "",
#             _format_tags(self.tags),
#             _format_price(self.price),
#             "\n\t".join(map(_format_type_and_choice, self.choices)),
#         )
# 
#     def price_range(self) -> Tuple[int, int]:
#         return (
#             self.price + self._sum_f_option_prices(min),
#             self.price + self._sum_f_option_prices(max),
#         )
# 
#     def _sum_f_option_prices(self, f):
#         return sum(
#             f(option.price for option in choice.options)
#             for (choice_type, choice) in self.choices
#             if choice_type == "single_choice"
#         )


# Path: app/hlds/parser.py
from glob import glob
from os import path
from copy import deepcopy
from typing import Iterable, List, Union, Tuple
from tatsu import parse as tatsu_parse
from tatsu.ast import AST
from tatsu.exceptions import SemanticError
from .models import Location, Choice, Option, Dish
from utils import first
import itertools

            first_single_choice = first(
                c[1] for c in dish.choices if c[0] == "single_choice"
            )
            price_range = dish.price_range()
            if dish.price and price_range[0] != price_range[1] and first_single_choice:
                for option in first_single_choice.options:
                    option.price += dish.price
                dish.price = 0
        dishes = list(dishes)
        dishes.append(Dish(
            "custom",
            name="Vrije keuze",
            description="Zet wat je wil in comment",
            price=0,
            tags=[],
            choices=[],
        ))

        attributes = {att["key"]: att["value"] for att in ast["attributes"]}

        return Location(
            ast["id"],
            name=ast["name"],
            dishes=dishes,
            osm=attributes.get("osm"),
            address=attributes.get("address"),
            telephone=attributes.get("phone"),
            website=attributes.get("website"),
        )


    def dish_block(self, ast) -> Dish: