/** * Auto-detect furniture interaction capabilities from classname/name. * Determines: canSit, canLay, canStand, interactionType, clickLimit */ export interface AutoInteractionResult { canSit: boolean; canLay: boolean; canStand: boolean; interactionType: string; clickLimit: number; interactionModesCount: number; reason: string; } const SIT_KEYWORDS = [ "bench", "bank", "sofa", "couch", "chair", "stool", "seat", "armchair", "loveseat", "settee", "ottoman", "pouf", "beanbag", "bean_bag", "rocking", "swing", "hammock", "throne", "wheelchair", "toilet", "potty", ]; const LAY_KEYWORDS = [ "bed", "mattress", "futon", "bunk", "cot", "hammock", "sleeping", "bedroll", "blanket", "pillow", "cushion", "lounger", "sunbed", "daybed", "divan", "waterbed", ]; const STAND_KEYWORDS = [ "table", "desk", "counter", "bar", "shelf", "cabinet", "wardrobe", "dresser", "bookcase", "rack", "stand", "pedestal", "platform", "stage", "floor", "tile", "carpet", "rug", "path", "road", "grass", "dirt", "sand", "snow", "ice", "water", "pool", "fountain", ]; const INTERACTION_TYPE_MAP: Record = { bench: "bench", bank: "bench", sofa: "sofa", couch: "sofa", chair: "chair", stool: "stool", seat: "chair", armchair: "armchair", loveseat: "sofa", settee: "sofa", ottoman: "ottoman", pouf: "ottoman", beanbag: "beanbag", rocking: "rocking_chair", swing: "swing", hammock: "hammock", throne: "throne", wheelchair: "wheelchair", toilet: "toilet", potty: "toilet", bed: "bed", mattress: "bed", futon: "bed", bunk: "bunkbed", cot: "bed", sleeping: "bed", bedroll: "bed", blanket: "bed", pillow: "bed", cushion: "bed", lounger: "lounger", sunbed: "sunbed", daybed: "daybed", divan: "divan", waterbed: "waterbed", table: "table", desk: "desk", counter: "counter", bar: "bar", shelf: "shelf", cabinet: "cabinet", wardrobe: "wardrobe", dresser: "dresser", bookcase: "bookcase", rack: "rack", stand: "stand", pedestal: "pedestal", platform: "platform", stage: "stage", }; const INTERACTION_MODES: Record = { bench: 1, bank: 1, sofa: 1, couch: 1, chair: 1, stool: 1, seat: 1, armchair: 1, loveseat: 1, settee: 1, ottoman: 1, pouf: 1, beanbag: 1, rocking: 1, swing: 1, hammock: 1, throne: 1, wheelchair: 1, toilet: 1, potty: 1, bed: 1, mattress: 1, futon: 1, bunk: 1, cot: 1, sleeping: 1, bedroll: 1, blanket: 1, pillow: 1, cushion: 1, lounger: 1, sunbed: 1, daybed: 1, divan: 1, waterbed: 1, table: 0, desk: 0, counter: 0, bar: 0, shelf: 0, cabinet: 0, wardrobe: 0, dresser: 0, bookcase: 0, rack: 0, stand: 0, pedestal: 0, platform: 0, stage: 0, floor: 0, tile: 0, carpet: 0, rug: 0, path: 0, road: 0, grass: 0, dirt: 0, sand: 0, snow: 0, ice: 0, water: 0, pool: 0, fountain: 0, }; const CLICK_LIMITS: Record = { bench: 1, bank: 1, sofa: 1, couch: 1, chair: 1, stool: 1, seat: 1, armchair: 1, loveseat: 1, settee: 1, ottoman: 1, pouf: 1, beanbag: 1, rocking: 1, swing: 1, hammock: 1, throne: 1, wheelchair: 1, toilet: 1, potty: 1, bed: 1, mattress: 1, futon: 1, bunk: 1, cot: 1, sleeping: 1, bedroll: 1, blanket: 1, pillow: 1, cushion: 1, lounger: 1, sunbed: 1, daybed: 1, divan: 1, waterbed: 1, table: 0, desk: 0, counter: 0, bar: 0, shelf: 0, cabinet: 0, wardrobe: 0, dresser: 0, bookcase: 0, rack: 0, stand: 0, pedestal: 0, platform: 0, stage: 0, floor: 0, tile: 0, carpet: 0, rug: 0, path: 0, road: 0, grass: 0, dirt: 0, sand: 0, snow: 0, ice: 0, water: 0, pool: 0, fountain: 0, }; function normalizeString(str: string): string { return str.toLowerCase().replace(/[^a-z0-9_]/g, "_"); } function findMatch(normalized: string, keywords: string[]): string | null { for (const kw of keywords) { if (normalized.includes(kw)) { return kw; } } return null; } export function autoDetectInteraction( classname: string, name?: string, ): AutoInteractionResult { const normalizedClassname = normalizeString(classname); const normalizedName = name ? normalizeString(name) : ""; const searchText = `${normalizedClassname} ${normalizedName}`; const sitMatch = findMatch(searchText, SIT_KEYWORDS); const layMatch = findMatch(searchText, LAY_KEYWORDS); const standMatch = findMatch(searchText, STAND_KEYWORDS); let canSit = false; let canLay = false; let canStand = false; let matchedKeyword: string | null = null; let interactionType = "default"; let clickLimit = 0; let interactionModesCount = 0; if (layMatch) { canLay = true; canSit = true; matchedKeyword = layMatch; interactionType = INTERACTION_TYPE_MAP[layMatch] || "bed"; clickLimit = CLICK_LIMITS[layMatch] ?? 1; interactionModesCount = INTERACTION_MODES[layMatch] ?? 1; } else if (sitMatch) { canSit = true; matchedKeyword = sitMatch; interactionType = INTERACTION_TYPE_MAP[sitMatch] || "chair"; clickLimit = CLICK_LIMITS[sitMatch] ?? 1; interactionModesCount = INTERACTION_MODES[sitMatch] ?? 1; } else if (standMatch) { canStand = true; matchedKeyword = standMatch; interactionType = INTERACTION_TYPE_MAP[standMatch] || "default"; clickLimit = CLICK_LIMITS[standMatch] ?? 0; interactionModesCount = INTERACTION_MODES[standMatch] ?? 0; } const reasonParts: string[] = []; if (matchedKeyword) { reasonParts.push(`Matched "${matchedKeyword}"`); } if (canSit) reasonParts.push("can sit"); if (canLay) reasonParts.push("can lay"); if (canStand) reasonParts.push("can stand"); if (!matchedKeyword) { reasonParts.push("No keywords matched - default"); } return { canSit, canLay, canStand, interactionType, clickLimit, interactionModesCount, reason: reasonParts.join(" ยท "), }; } export function getInteractionTypeLabel(type: string): string { const labels: Record = { bench: "Bench / Bank", sofa: "Sofa / Couch", chair: "Chair", stool: "Stool", armchair: "Armchair", ottoman: "Ottoman / Pouf", beanbag: "Bean Bag", rocking_chair: "Rocking Chair", swing: "Swing", hammock: "Hammock", throne: "Throne", wheelchair: "Wheelchair", toilet: "Toilet", bed: "Bed", bunkbed: "Bunk Bed", lounger: "Lounger / Sunbed", daybed: "Daybed", divan: "Divan", waterbed: "Waterbed", table: "Table", desk: "Desk", counter: "Counter", bar: "Bar", shelf: "Shelf", cabinet: "Cabinet", wardrobe: "Wardrobe", dresser: "Dresser", bookcase: "Bookcase", rack: "Rack", stand: "Stand", pedestal: "Pedestal", platform: "Platform", stage: "Stage", default: "Default (no interaction)", }; return labels[type] || type; }