from __future__ import annotations import csv import os import json from typing import Optional, Dict from flask import current_app # Cache: "name in lowercase" -> type_id _BP_NAME2ID: Dict[str, int] = {} # Cache: product type id -> (product name) _ID2NAME: Dict[int, str] = {} # Optional benutzerdefinierte Überschreibungen # Format: { "Structure Market Network": 123456, ... } _USER_MAP: Dict[str, int] = {} def _data_path(filename: str) -> str: return os.path.join(current_app.root_path, "data", filename) def _ensure_loaded() -> None: """Liest typeIDs.csv einmalig ein und baut schnelle Nachschlage-Maps auf.""" global _BP_NAME2ID, _ID2NAME, _USER_MAP if _BP_NAME2ID and _ID2NAME: return # Benutzer-Overrides (optional) try: override = _data_path("blueprints.json") if os.path.isfile(override): with open(override, "r", encoding="utf-8") as f: _USER_MAP = json.load(f) or {} except Exception: _USER_MAP = {} csv_path = _data_path("typeIDs.csv") if not os.path.isfile(csv_path): return try: with open(csv_path, "r", encoding="utf-8", newline="") as f: # Datei ist ;-separiert: id;name;group_id;iconID;graphicID reader = csv.reader(f, delimiter=";") header = next(reader, None) # "id;name;group_id;iconID;graphicID" for row in reader: if not row or len(row) < 2: continue try: tid = int(row[0]) except Exception: continue name = (row[1] or "").strip() if not name: continue _ID2NAME[tid] = name key = name.lower() # Merke auch die Blaupause separat (Name endet exakt auf " Blueprint") if key.endswith(" blueprint"): _BP_NAME2ID[key] = tid except Exception: # Map bleibt ggf. leer; Aufrufer bekommen dann None zurück pass def product_name_by_id(type_id: int) -> Optional[str]: """Gibt den Produktnamen zur TypeID zurück (aus typeIDs.csv).""" _ensure_loaded() return _ID2NAME.get(type_id) def resolve_blueprint_id(product_name: str) -> Optional[int]: """ Ermittelt die Blueprint-TypeID zu einem *Produktnamen*. Regeln: 1) Benutzer-Override (blueprints.json) 2) Exakter Treffer " Blueprint" in typeIDs.csv 3) Weicher Treffer (enthält Produktname & 'blueprint') """ if not product_name: return None _ensure_loaded() # 1) User-Override if product_name in _USER_MAP: return int(_USER_MAP[product_name]) wanted_exact = f"{product_name} Blueprint".lower() # 2) Exakter Treffer if wanted_exact in _BP_NAME2ID: return _BP_NAME2ID[wanted_exact] # 3) Weiche Suche prod_l = product_name.lower() for k, tid in _BP_NAME2ID.items(): if prod_l in k and "blueprint" in k: return tid return None def resolve_blueprint_id_by_product_id(product_type_id: int) -> Optional[int]: """Ermittelt die Blueprint-TypeID aus der *Produkt*-TypeID.""" name = product_name_by_id(int(product_type_id)) if not name: return None return resolve_blueprint_id(name)