# Stack Binding System - Calendar Plantempus

## Oversigt

Dette dokument beskriver hvordan overlappende events er bundet sammen i Calendar Plantempus systemet, specifikt hvordan 2 eller flere events der ligger oven i hinanden (stacked) er forbundet.

## Stack Binding Mekanisme

### SimpleEventOverlapManager

Systemet bruger `SimpleEventOverlapManager` til at håndtere event overlap og stacking. Denne implementation bruger **data-attributes** på DOM elementerne til at holde styr på stack chains.

### Hvordan Stacked Events er Bundet Sammen

Når 2 eller flere events ligger oven i hinanden, oprettes en **linked list struktur** via `data-stack-link` attributter:

#### Eksempel med 2 Events:
```typescript
// Event A (base event):
<swp-event data-stack-link='{"stackLevel":0,"next":"event-B"}'>

// Event B (stacked event):
<swp-event data-stack-link='{"prev":"event-A","stackLevel":1}'>
```

#### Eksempel med 3 Events:

```typescript
// Event A (base event):
<swp-event data-stack-link='{"stackLevel":0,"next":"event-B"}'>

// Event B (middle event): 
<swp-event data-stack-link='{"prev":"event-A","next":"event-C","stackLevel":1}'>

// Event C (top event):
<swp-event data-stack-link='{"prev":"event-B","stackLevel":2}'>
```

### StackLink Interface

```typescript
interface StackLink {
  prev?: string;        // Event ID af forrige event i stacken
  next?: string;        // Event ID af næste event i stacken  
  stackLevel: number;   // 0 = base event, 1 = første stacked, etc
}
```

### Visual Styling

Hvert stacked event får automatisk styling baseret på deres `stackLevel`:

- **Event A (base)**: `margin-left: 0px`, `z-index: 100`
- **Event B (middle)**: `margin-left: 15px`, `z-index: 101` 
- **Event C (top)**: `margin-left: 30px`, `z-index: 102`

**Formel:**
- `margin-left = stackLevel * 15px`
- `z-index = 100 + stackLevel`

### Stack Chain Navigation

Systemet kan traversere stack chains i begge retninger:

```typescript
// Find næste event i stacken
const link = getStackLink(currentElement);
if (link?.next) {
  const nextElement = document.querySelector(`swp-event[data-event-id="${link.next}"]`);
}

// Find forrige event i stacken  
if (link?.prev) {
  const prevElement = document.querySelector(`swp-event[data-event-id="${link.prev}"]`);
}
```

### Automatisk Chain Opdatering

Når events fjernes fra en stack, opdateres chain automatisk:

1. **Middle element fjernet**: Prev og next events linkes direkte sammen
2. **Chain breaking**: Hvis events ikke længere overlapper, brydes chain
3. **Stack level opdatering**: Alle efterfølgende events får opdateret stackLevel

### Overlap Detection

Events klassificeres som **stacking** hvis:
- De overlapper i tid OG
- Start tid forskel > 30 minutter

```typescript
const timeDiffMinutes = Math.abs(
  new Date(event1.start).getTime() - new Date(event2.start).getTime()
) / (1000 * 60);

return timeDiffMinutes > 30 ? OverlapType.STACKING : OverlapType.COLUMN_SHARING;
```

## Eksempler

### 2 Events Stack

```
Event A: 09:00-11:00 (base)     → margin-left: 0px,  z-index: 100
Event B: 09:45-10:30 (stacked)  → margin-left: 15px, z-index: 101
```

**Stack chain:**
```
A ←→ B
```

**Data attributes:**
- A: `{"stackLevel":0,"next":"B"}`
- B: `{"prev":"A","stackLevel":1}`

### 3 Events Stack

```
Event A: 09:00-11:00 (base)     → margin-left: 0px,  z-index: 100
Event B: 09:45-10:30 (middle)   → margin-left: 15px, z-index: 101  
Event C: 10:15-11:15 (top)      → margin-left: 30px, z-index: 102
```

**Stack chain:**
```
A ←→ B ←→ C
```

**Data attributes:**
- A: `{"stackLevel":0,"next":"B"}`
- B: `{"prev":"A","next":"C","stackLevel":1}`  
- C: `{"prev":"B","stackLevel":2}`

## Visual Stack Chain Diagram

```mermaid
graph TD
    A[Event A - Base Event] --> A1[data-stack-link]
    B[Event B - Middle Event] --> B1[data-stack-link]
    C[Event C - Top Event] --> C1[data-stack-link]
    
    A1 --> A2[stackLevel: 0<br/>next: event-B]
    B1 --> B2[prev: event-A<br/>next: event-C<br/>stackLevel: 1]
    C1 --> C2[prev: event-B<br/>stackLevel: 2]
    
    A2 --> A3[margin-left: 0px<br/>z-index: 100]
    B2 --> B3[margin-left: 15px<br/>z-index: 101]
    C2 --> C3[margin-left: 30px<br/>z-index: 102]
    
    subgraph Stack Chain Navigation
        A4[Event A] -.->|next| B4[Event B]
        B4 -.->|next| C4[Event C]
        C4 -.->|prev| B4
        B4 -.->|prev| A4
    end
    
    subgraph Visual Result
        V1[Event A - Full Width]
        V2[Event B - 15px Offset]
        V3[Event C - 30px Offset]
        V1 -.-> V2
        V2 -.-> V3
    end
```

## Stack Chain Operations

```mermaid
sequenceDiagram
    participant DOM as DOM Element
    participant SM as SimpleEventOverlapManager
    participant Chain as Stack Chain
    
    Note over DOM,Chain: Creating Stack Chain
    DOM->>SM: createStackedEvent(eventB, eventA, 1)
    SM->>Chain: Set eventA: {stackLevel:0, next:"eventB"}
    SM->>Chain: Set eventB: {prev:"eventA", stackLevel:1}
    SM->>DOM: Apply margin-left: 15px, z-index: 101
    
    Note over DOM,Chain: Removing from Chain
    DOM->>SM: removeStackedStyling(eventB)
    SM->>Chain: Get eventB links
    SM->>Chain: Link eventA -> eventC directly
    SM->>Chain: Update eventC stackLevel: 1
    SM->>DOM: Update eventC margin-left: 15px
    SM->>Chain: Delete eventB entry
```

## Fordele ved Data-Attribute Approach

1. **Ingen global state** - alt information er på DOM elementerne
2. **Persistent** - overlever DOM manipulationer
3. **Debuggable** - kan inspiceres i browser dev tools
4. **Performant** - ingen in-memory maps at vedligeholde
5. **Robust** - automatisk cleanup når elements fjernes

## Se Også

- [`SimpleEventOverlapManager.ts`](../src/managers/SimpleEventOverlapManager.ts) - Implementation
- [`EventRenderer.ts`](../src/renderers/EventRenderer.ts) - Usage
- [Event Overlap CSS](../wwwroot/css/calendar-events-css.css) - Styling
- [Complexity Comparison](../complexity_comparison.md) - Before/after analysis