File size: 5,396 Bytes
96027bb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/**
 * TableRenderer.js
 * Handles drawing and updating the dining tables in the DOM.
 */
export class TableRenderer {
    constructor(containerId) {
        this.containerId = containerId;
        this.availableTables = [];
        this.tableTimers = new Map(); // tableId -> { type: 'countup'|'countdown', startSimTime: 0, limit: 0 }
    }

    /**
     * Clears and redraws the tables based on the simulation config.
     */
    draw(tablesCount) {
        const container = document.getElementById(this.containerId);
        if (!container) return;

        container.innerHTML = '';
        this.availableTables = [];
        this.tableTimers.clear();

        for (let i = 0; i < tablesCount; i++) {
            container.innerHTML += `
                <div class="table" id="table-${i}" data-tooltip="Table is available">
                    <div class="table__badge" id="badge-table-${i}" style="display: none;">[R]</div>
                    <div class="table__status" id="status-table-${i}"></div>
                </div>
            `;
            this.availableTables.push(`table-${i}`);
        }
    }

    /**
     * Updates the UI based on events
     */
    setReserved(tableId, simTime, limit) {
        const tableEl = document.getElementById(`table-${tableId}`);
        const badgeEl = document.getElementById(`badge-table-${tableId}`);
        if (tableEl && badgeEl) {
            tableEl.classList.add('table--reserved');
            badgeEl.style.display = 'block';
            this.tableTimers.set(tableId, { type: 'countdown', startSimTime: simTime, limit: limit });
            this._updateTimerDisplay(tableId, simTime);
        }
    }

    setUnreserved(tableId) {
        const tableEl = document.getElementById(`table-${tableId}`);
        const badgeEl = document.getElementById(`badge-table-${tableId}`);
        const statusEl = document.getElementById(`status-table-${tableId}`);
        if (tableEl && badgeEl && statusEl) {
            tableEl.classList.remove('table--reserved');
            badgeEl.style.display = 'none';
            statusEl.innerHTML = '';
            tableEl.setAttribute('data-tooltip', "Table is available");
            this.tableTimers.delete(tableId);
        }
    }

    setOccupied(tableId, simTime, isReservation, state='waiting') {
        const tableEl = document.getElementById(`table-${tableId}`);
        const badgeEl = document.getElementById(`badge-table-${tableId}`);
        if (tableEl) {
            if (!isReservation && badgeEl) badgeEl.style.display = 'none';
            tableEl.classList.add('table--occupied');
            this.tableTimers.set(tableId, { type: 'countup', startSimTime: simTime, state: state });
            this._updateTimerDisplay(tableId, simTime);
        }
    }

    setEmpty(tableId) {
        const tableEl = document.getElementById(`table-${tableId}`);
        const badgeEl = document.getElementById(`badge-table-${tableId}`);
        const statusEl = document.getElementById(`status-table-${tableId}`);
        if (tableEl && badgeEl && statusEl) {
            tableEl.classList.remove('table--occupied');
            tableEl.classList.remove('table--reserved');
            badgeEl.style.display = 'none';
            statusEl.innerHTML = '';
            tableEl.setAttribute('data-tooltip', "Table is available");
            this.tableTimers.delete(tableId);
        }
    }

    tickTimers(currentSimTime) {
        for (const [tableId, _] of this.tableTimers.entries()) {
            this._updateTimerDisplay(tableId, currentSimTime);
        }
    }

    _updateTimerDisplay(tableId, currentSimTime) {
        const timerData = this.tableTimers.get(tableId);
        if (!timerData) return;

        const statusEl = document.getElementById(`status-table-${tableId}`);
        const tableEl = document.getElementById(`table-${tableId}`);
        if (!statusEl || !tableEl) return;

        let elapsed = currentSimTime - timerData.startSimTime;
        if (elapsed < 0) elapsed = 0;

        if (timerData.type === 'countdown') {
            let remaining = timerData.limit - elapsed;
            if (remaining < 0) remaining = 0;
            const mins = Math.floor(remaining / 60);
            const secs = Math.floor(remaining % 60).toString().padStart(2, '0');
            tableEl.setAttribute('data-tooltip', "Reserved table waiting for customer");
            statusEl.innerHTML = `⏳ <span style="font-family: monospace; font-size: 0.8rem;">${mins}:${secs}</span>`;
            statusEl.style.color = '#f39c12';
        } else if (timerData.type === 'countup') {
            const mins = Math.floor(elapsed / 60);
            const secs = Math.floor(elapsed % 60).toString().padStart(2, '0');
            if (timerData.state === 'waiting') {
                tableEl.setAttribute('data-tooltip', "Customer waiting for order");
                statusEl.innerHTML = `⏳ <span style="font-family: monospace; font-size: 0.8rem;">${mins}:${secs}</span>`;
                statusEl.style.color = '#e94f37';
            } else {
                tableEl.setAttribute('data-tooltip', "Customer dining at table");
                statusEl.innerHTML = `☕ <span style="font-family: monospace; font-size: 0.8rem;">${mins}:${secs}</span>`;
                statusEl.style.color = '#4caf50';
            }
        }
    }
}

export const tableRenderer = new TableRenderer('tables');