import { Component, Input, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SelectionService } from '../selection.service/selection.service'; @Component({ selector: 'app-touch-pad-menu', standalone: true, imports: [CommonModule], templateUrl: './touch-pad-menu.component.html', styleUrls: ['./touch-pad-menu.component.css'] }) export class TouchPadMenuComponent implements OnInit { @Input() ticketingActive: boolean = false; public twoGroupLabels = ['FOR', 'QUI']; public multiLegLabels = ['TRE', 'MJP', 'JKP']; public allowedFieldLabels = ['WIN', 'SHP', 'THP', 'PLC', 'SHW']; labels: string[] = [ 'WIN', 'SHP', 'THP', 'PLC', 'SHW', 'FOR', 'QUI', 'TAN', 'EXA', 'WSP', 'TRE', 'MJP', 'JKP', 'SJP', '.' ]; numbers: number[] = Array.from({ length: 30 }, (_, i) => i + 1); labelRowsFlat: string[] = []; numbersFlat: number[] = []; selectedLabel: string | null = null; selectedNumbers: (number | string)[] = []; padValue: string = ''; canPrint = false; calculatorOpen = false; calcDisplay = ''; maxRowsReached: boolean = false; disabledLabels: string[] = ['SHW', 'SJP', '.']; // ✅ Original TAN logic tanGroupStage = 0; tanGroups: number[][] = [[], [], []]; // ✅ FOR/QUI logic isFirstGroupComplete = false; firstGroup: number[] = []; secondGroup: number[] = []; // ✅ Multi-leg logic (TRE, MJP, JKP) multiLegStage = 0; multiLegGroups: number[][] = [[], [], [], [], []]; isBoxed: boolean = false; // FIELD modal fieldModalOpen = false; fieldInput: string = ''; fieldFEntered = false; constructor(private selectionService: SelectionService) {} ngOnInit() { this.labelRowsFlat = this.labelRows.flat(); this.numbersFlat = this.numberRows.flat(); this.selectionService.selections$.subscribe(selections => { this.maxRowsReached = selections.length >= 5; }); } get labelRows() { return this.chunk(this.labels, 3); } get numberRows() { return this.chunk(this.numbers, 6); } get numericPadEnabled() { return this.selectedLabel !== null && (this.selectedNumbers.length > 0 || this.selectedNumbers.includes('F')); } get showShashEnter(): boolean { const label = this.selectedLabel || ''; const isBoxed = this.isBoxed; if (['FOR', 'QUI', 'TAN'].includes(label) && isBoxed) { return false; } const specialLabels = ['FOR', 'QUI', 'TAN', 'EXA', 'WSP', 'TRE', 'MJP', 'JKP', '.']; return specialLabels.includes(label); } get isShashEnterDisabled(): boolean { if (this.selectedLabel === 'TAN') { // In box mode, shash enter is always disabled if (this.isBoxed) { return true; } return this.tanGroupStage >= 2 || this.tanGroups[this.tanGroupStage].length === 0; } else if (this.multiLegLabels.includes(this.selectedLabel || '')) { const maxLegs = this.getMaxLegs(this.selectedLabel || ''); return this.multiLegStage >= maxLegs - 1 || this.multiLegGroups[this.multiLegStage].length === 0; } else if (this.twoGroupLabels.includes(this.selectedLabel || '')) { return this.isFirstGroupComplete || this.firstGroup.length === 0; } return false; } get showBackspace(): boolean { return this.selectedLabel !== null && (this.selectedNumbers.length > 0 || this.selectedNumbers.includes('F')) && this.padValue.length === 0; } get isBoxToggleDisabled(): boolean { return this.selectedLabel !== null && this.allowedFieldLabels.includes(this.selectedLabel); } private chunk(array: T[], size: number): T[][] { return Array.from({ length: Math.ceil(array.length / size) }, (_, i) => array.slice(i * size, i * size + size) ); } isLabelDisabled(label: string): boolean { return this.disabledLabels.includes(label); } selectLabel(label: string) { this.selectedLabel = label; this.selectedNumbers = []; this.padValue = ''; this.canPrint = false; this.isBoxed = false; // ✅ Reset TAN this.tanGroupStage = 0; this.tanGroups = [[], [], []]; // ✅ Reset FOR/QUI this.isFirstGroupComplete = false; this.firstGroup = []; this.secondGroup = []; // ✅ Reset Multi-leg this.multiLegStage = 0; this.multiLegGroups = [[], [], [], [], []]; this.selectionService.updatePartial({ label }); } selectNumber(number: number) { if (!this.selectedLabel) return; // TAN Box mode: freestyle selection with dash-separated format if (this.selectedLabel === 'TAN' && this.isBoxed) { if (!this.selectedNumbers.includes(number)) { // Extract current numbers (excluding dashes) const currentNumbers = this.selectedNumbers.filter(n => typeof n === 'number') as number[]; const allBoxed = [...currentNumbers, number]; // Split into 3 roughly equal groups for display consistency const groupSize = Math.ceil(allBoxed.length / 3); const group1 = allBoxed.slice(0, groupSize); const group2 = allBoxed.slice(group1.length, group1.length + groupSize); const group3 = allBoxed.slice(group1.length + group2.length); const combined: (number | string)[] = [...group1]; if (group2.length) combined.push('-', ...group2); if (group3.length) combined.push('-', ...group3); this.selectedNumbers = combined; this.selectionService.updatePartial({ numbers: [...this.selectedNumbers], isBoxed: true, label: 'TAN' }); } return; } // Original TAN logic (unboxed) if (this.selectedLabel === 'TAN') { if (!this.tanGroups[this.tanGroupStage].includes(number)) { this.tanGroups[this.tanGroupStage].push(number); const combined: (number | string)[] = [...this.tanGroups[0]]; if (this.tanGroupStage > 0) combined.push('-', ...this.tanGroups[1]); if (this.tanGroupStage > 1) combined.push('-', ...this.tanGroups[2]); this.selectedNumbers = combined; this.selectionService.updatePartial({ numbers: [...this.selectedNumbers] }); } return; } // Multi-leg logic (TRE, MJP, JKP) if (this.multiLegLabels.includes(this.selectedLabel)) { if (!this.multiLegGroups[this.multiLegStage].includes(number)) { this.multiLegGroups[this.multiLegStage].push(number); this.updateMultiLegSelection(); } return; } // FOR/QUI logic if (this.twoGroupLabels.includes(this.selectedLabel || '')) { if (!this.isFirstGroupComplete) { if (!this.firstGroup.includes(number)) { this.firstGroup.push(number); this.selectedNumbers = [...this.firstGroup]; } } else { if (!this.secondGroup.includes(number)) { this.secondGroup.push(number); this.selectedNumbers = [...this.firstGroup, '-', ...this.secondGroup]; } } this.selectionService.updatePartial({ numbers: [...this.selectedNumbers] }); return; } // Default single-number selection (WIN, SHP, THP, etc.) if (!this.selectedNumbers.includes(number)) { this.selectedNumbers.push(number); this.selectionService.updatePartial({ numbers: [...this.selectedNumbers] }); } } private updateMultiLegSelection() { const combined: (number | string)[] = []; for (let i = 0; i <= this.multiLegStage; i++) { if (i > 0) combined.push('/'); combined.push(...this.multiLegGroups[i]); } this.selectedNumbers = combined; this.selectionService.updatePartial({ numbers: [...this.selectedNumbers] }); } isNumberDisabled(number: number): boolean { // For TAN Box mode, allow all numbers to be selectable if (this.selectedLabel === 'TAN' && this.isBoxed) { return false; } if (this.selectedLabel === 'TAN' || this.multiLegLabels.includes(this.selectedLabel || '') || this.twoGroupLabels.includes(this.selectedLabel || '')) { return false; } return this.selectedNumbers.includes(number); } onPadEnter() { if (this.canPrint) { this.print(); } } onShashEnter() { // Disable shash enter for TAN Box mode if (this.selectedLabel === 'TAN' && this.isBoxed) { return; } if (this.selectedLabel === 'TAN') { if (this.tanGroupStage < 2) { this.tanGroupStage++; const combined: (number | string)[] = [...this.tanGroups[0]]; if (this.tanGroupStage > 0) combined.push('-', ...this.tanGroups[1]); if (this.tanGroupStage > 1) combined.push('-', ...this.tanGroups[2]); this.selectedNumbers = combined; this.selectionService.updatePartial({ numbers: [...this.selectedNumbers] }); } return; } if (this.multiLegLabels.includes(this.selectedLabel || '')) { const maxLegs = this.getMaxLegs(this.selectedLabel || ''); if (this.multiLegStage < maxLegs - 1) { this.multiLegStage++; this.updateMultiLegSelection(); } return; } if (this.twoGroupLabels.includes(this.selectedLabel || '')) { if (!this.isFirstGroupComplete && this.firstGroup.length > 0) { this.isFirstGroupComplete = true; this.secondGroup = []; this.selectedNumbers = [...this.firstGroup, '-']; this.selectionService.updatePartial({ numbers: [...this.selectedNumbers] }); } } } enterPadVal(key: string) { if (!this.numericPadEnabled) return; if (key === 'X') { this.padValue = ''; } else if (/[0-9]/.test(key)) { this.padValue += key; } this.updateCanPrint(); const value = parseFloat(this.padValue) || 0; this.selectionService.updatePartial({ value, isBoxed: this.isBoxed, label: this.selectedLabel || '', numbers: [...this.selectedNumbers] }); } updateCanPrint() { this.canPrint = this.padValue.trim().length > 0 && /^[0-9]+$/.test(this.padValue); } print() { this.selectionService.finalizeCurrentRow(); this.resetSelections(); } erase() { this.selectionService.clearSelections(); this.resetSelections(); } resetSelections() { this.selectedLabel = null; this.selectedNumbers = []; this.padValue = ''; this.canPrint = false; this.isBoxed = false; this.tanGroupStage = 0; this.tanGroups = [[], [], []]; this.isFirstGroupComplete = false; this.firstGroup = []; this.secondGroup = []; this.multiLegStage = 0; this.multiLegGroups = [[], [], [], [], []]; this.fieldModalOpen = false; this.fieldInput = ''; this.fieldFEntered = false; } toggleBoxMode() { this.isBoxed = !this.isBoxed; const value = parseFloat(this.padValue) || 0; // For TAN Box mode, reset to freestyle selection if (this.selectedLabel === 'TAN' && this.isBoxed) { this.tanGroupStage = 0; this.tanGroups = [[], [], []]; this.selectedNumbers = []; } this.selectionService.updatePartial({ isBoxed: this.isBoxed, label: this.selectedLabel || '', numbers: [...this.selectedNumbers], value }); this.updateCanPrint(); } removeLastNumber() { if (!this.selectedLabel || (this.selectedNumbers.length === 0 && !this.selectedNumbers.includes('F'))) return; if (this.selectedNumbers.includes('F') && this.allowedFieldLabels.includes(this.selectedLabel || '')) { this.selectedNumbers = []; this.selectionService.updatePartial({ numbers: [], isBoxed: false, label: this.selectedLabel || '' }); return; } if (this.selectedLabel === 'TAN' && this.isBoxed) { const currentNumbers = this.selectedNumbers.filter(n => typeof n === 'number') as number[]; if (currentNumbers.length > 0) { currentNumbers.pop(); // Rebuild dash-separated structure const groupSize = Math.ceil(currentNumbers.length / 3); const group1 = currentNumbers.slice(0, groupSize); const group2 = currentNumbers.slice(group1.length, group1.length + groupSize); const group3 = currentNumbers.slice(group1.length + group2.length); const combined: (number | string)[] = [...group1]; if (group2.length) combined.push('-', ...group2); if (group3.length) combined.push('-', ...group3); this.selectedNumbers = combined; this.selectionService.updatePartial({ numbers: [...this.selectedNumbers], isBoxed: true, label: 'TAN' }); } return; } // Original TAN logic (unboxed) if (this.selectedLabel === 'TAN') { const currentGroup = this.tanGroups[this.tanGroupStage]; if (currentGroup.length > 0) { currentGroup.pop(); let combined: (number | string)[] = [...this.tanGroups[0]]; if (this.tanGroupStage > 0) combined.push('-', ...this.tanGroups[1]); if (this.tanGroupStage > 1) combined.push('-', ...this.tanGroups[2]); this.selectedNumbers = combined; this.selectionService.updatePartial({ numbers: [...this.selectedNumbers] }); } return; } // Multi-leg logic if (this.multiLegLabels.includes(this.selectedLabel)) { const currentGroup = this.multiLegGroups[this.multiLegStage]; if (currentGroup.length > 0) { currentGroup.pop(); this.updateMultiLegSelection(); } return; } // FOR/QUI logic if (this.twoGroupLabels.includes(this.selectedLabel)) { if (!this.isFirstGroupComplete && this.firstGroup.length > 0) { this.firstGroup.pop(); this.selectedNumbers = [...this.firstGroup]; } else if (this.secondGroup.length > 0) { this.secondGroup.pop(); this.selectedNumbers = [...this.firstGroup, '-', ...this.secondGroup]; } this.selectionService.updatePartial({ numbers: [...this.selectedNumbers] }); return; } // Default single-number removal this.selectedNumbers.pop(); this.selectionService.updatePartial({ numbers: [...this.selectedNumbers] }); } private getMaxLegs(label: string): number { switch (label) { case 'TRE': return 3; case 'MJP': return 4; case 'JKP': return 5; default: return 3; } } // Calculator and Field Modal methods (unchanged) openCalculator() { this.calculatorOpen = true; this.calcDisplay = ''; } closeCalculator() { this.calculatorOpen = false; } press(val: string) { if (this.calcDisplay === 'Error') this.calcDisplay = ''; this.calcDisplay += val; } clearDisplay() { this.calcDisplay = ''; } backspace() { this.calcDisplay = this.calcDisplay === 'Error' ? '' : this.calcDisplay.slice(0, -1); } calculate() { try { this.calcDisplay = eval(this.calcDisplay).toString(); } catch { this.calcDisplay = 'Error'; } } canUseField(): boolean { return this.selectedLabel !== null && this.allowedFieldLabels.includes(this.selectedLabel) && this.selectedNumbers.length === 0; } openFieldModal() { this.fieldModalOpen = true; this.fieldInput = ''; this.fieldFEntered = false; } closeFieldModal() { this.fieldModalOpen = false; } handleFieldKey(key: string) { if (key === 'BACK') { this.fieldInput = this.fieldInput.slice(0, -1); if (!this.fieldInput.includes('F')) this.fieldFEntered = false; return; } if (key === 'F') { if (!this.fieldFEntered) { this.fieldFEntered = true; this.fieldInput = 'F'; } } else { this.fieldInput += key; } } confirmFieldEntry() { if (this.fieldFEntered) { this.selectedNumbers = ['F']; this.selectionService.updatePartial({ label: this.selectedLabel!, numbers: ['F'], isBoxed: false, value: 1 }); this.closeFieldModal(); } } }