function normalizeText(value) { return String(value || '').trim().toLowerCase().replace(/\s+/g, ' ') } function normalizeTeamFilterKey(value) { const normalized = normalizeText(value).replace(/\s+/g, '_') if (!normalized) return '' if (normalized === 'all' || normalized === 'erwachsene' || normalized === 'nachwuchs') return normalized if (normalized === 'jugendmannschaft') return 'jugendmannschaft' const erwachseneMatch = normalized.match(/^erwachsene_(\d+)$/) if (erwachseneMatch) { return `erwachsene_${erwachseneMatch[1]}` } return normalized } const MANNSCHAFT_MAPPING = { erwachsene_1: ['harheimer tc'], erwachsene_2: ['harheimer tc ii'], erwachsene_3: ['harheimer tc iii'], erwachsene_4: ['harheimer tc iv'], erwachsene_5: ['harheimer tc v'], jugendmannschaft: ['harheimer tc'] } function matchMappedVariant(mannschaft, variant) { if (variant === 'harheimer tc') { return mannschaft === 'harheimer tc' || (mannschaft.startsWith('harheimer tc ') && !mannschaft.match(/harheimer tc\s+[ivx]+/i)) } return mannschaft === variant || mannschaft.startsWith(`${variant} `) } function isErwachsenenTeam(teamKey) { return teamKey === 'erwachsene' || teamKey.startsWith('erwachsene_') } function romanToNumber(value) { const roman = String(value || '').toUpperCase() if (!/^[IVX]+$/.test(roman)) return null const values = { I: 1, V: 5, X: 10 } let total = 0 for (let index = 0; index < roman.length; index += 1) { const current = values[roman[index]] || 0 const next = values[roman[index + 1]] || 0 total += current < next ? -current : current } return total || null } function parseJugendTeamKey(teamKey) { const match = String(teamKey || '').match(/^jugend(?:mannschaft)?_?j?(\d{1,2})(?:_([ivx]+|\d+))?$/i) if (!match) return null const teamNumber = match[2] ? (Number(match[2]) || romanToNumber(match[2])) : null return { age: match[1], teamNumber: teamNumber ? String(teamNumber) : '' } } function sideMatchesJugendTeam({ isHarheimer, ageClass, teamNumber }, team) { if (!isHarheimer) return false const ageMatch = String(ageClass || '').match(/(?:jugend\s*|j)(\d{1,2})\b/i) if (!ageMatch || ageMatch[1] !== team.age) return false return !team.teamNumber || String(teamNumber || '').trim() === team.teamNumber } export function rowMatchesWettbewerbFilter(row, rawWettbewerb) { const wettbewerb = normalizeText(rawWettbewerb || 'punktrunde') const runde = normalizeText(row?.Runde) const staffel = normalizeText(row?.Staffel) const liga = normalizeText(row?.Liga) const isPokal = runde.includes('pokal') || staffel.includes('pokal') || liga.includes('pokal') if (wettbewerb === 'alle') return true if (wettbewerb === 'pokal') return isPokal return !isPokal } export function rowMatchesTeamFilter(row, rawTeam) { const teamKey = normalizeTeamFilterKey(rawTeam) if (!teamKey || teamKey === 'all') return true const heimMannschaft = normalizeText(row?.HeimMannschaft) const gastMannschaft = normalizeText(row?.GastMannschaft) const heimAltersklasse = normalizeText(row?.HeimMannschaftAltersklasse) const gastAltersklasse = normalizeText(row?.GastMannschaftAltersklasse) const isHarheimerHeim = heimMannschaft.includes('harheimer tc') const isHarheimerGast = gastMannschaft.includes('harheimer tc') if (!isHarheimerHeim && !isHarheimerGast) { return false } if (teamKey === 'erwachsene') { const isErwachsenenHeim = isHarheimerHeim && heimAltersklasse.includes('erwachsene') && !heimAltersklasse.includes('jugend') const isErwachsenenGast = isHarheimerGast && gastAltersklasse.includes('erwachsene') && !gastAltersklasse.includes('jugend') return isErwachsenenHeim || isErwachsenenGast } if (teamKey === 'nachwuchs' || teamKey === 'jugendmannschaft') { const isJugendHeim = isHarheimerHeim && (heimAltersklasse.includes('jugend') || heimMannschaft.includes('jugend')) const isJugendGast = isHarheimerGast && (gastAltersklasse.includes('jugend') || gastMannschaft.includes('jugend')) return isJugendHeim || isJugendGast } const jugendTeam = parseJugendTeamKey(teamKey) if (jugendTeam) { return sideMatchesJugendTeam({ isHarheimer: isHarheimerHeim, ageClass: heimAltersklasse, teamNumber: row?.HeimMannschaftNr }, jugendTeam) || sideMatchesJugendTeam({ isHarheimer: isHarheimerGast, ageClass: gastAltersklasse, teamNumber: row?.GastMannschaftNr }, jugendTeam) } const csvVariants = MANNSCHAFT_MAPPING[teamKey] || [] if (csvVariants.length === 0) { return false } const mannschaftMatch = csvVariants.some((variant) => { if (isHarheimerHeim && matchMappedVariant(heimMannschaft, variant)) return true if (isHarheimerGast && matchMappedVariant(gastMannschaft, variant)) return true return false }) if (!mannschaftMatch) { return false } if (isErwachsenenTeam(teamKey)) { const isErwachsenenHeim = isHarheimerHeim && heimAltersklasse.includes('erwachsene') && !heimAltersklasse.includes('jugend') const isErwachsenenGast = isHarheimerGast && gastAltersklasse.includes('erwachsene') && !gastAltersklasse.includes('jugend') return isErwachsenenHeim || isErwachsenenGast } return true } export function filterSpielplanRows(rows, options = {}) { const sourceRows = Array.isArray(rows) ? rows : [] const team = options.team || 'all' const wettbewerb = options.wettbewerb || 'punktrunde' return sourceRows.filter((row) => rowMatchesTeamFilter(row, team) && rowMatchesWettbewerbFilter(row, wettbewerb)) } export function toApiTeamParam(filterValue) { const teamKey = normalizeTeamFilterKey(filterValue) if (teamKey === 'all' || teamKey === 'erwachsene' || teamKey === 'nachwuchs' || teamKey === 'jugendmannschaft') { return teamKey } if (teamKey.match(/^erwachsene_\d+$/)) { return teamKey } return String(filterValue || '').trim().replace(/\s+/g, '_').toLowerCase() }