File size: 6,191 Bytes
5a81b95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/**
 * Widget Registry
 * 
 * Central registry der håndterer widget discovery, queries og relationship management.
 * Gør det muligt for widgets at finde hinanden og etablere dataflow.
 */

import { 
  WidgetMetadata, 
  WidgetQuery, 
  WidgetRegistry, 
  DataType,
  securityWidgetSchemas,
  calendarScheduleWidgetSchemas
} from '@/types/WidgetSchema';

class WidgetRegistryImpl implements WidgetRegistry {
  widgets: Map<string, WidgetMetadata> = new Map();

  constructor() {
    // Initialize with security widget schemas
    Object.values(securityWidgetSchemas).forEach(widget => {
      this.register(widget);
    });
    // Initialize with calendar/schedule widget schemas
    Object.values(calendarScheduleWidgetSchemas).forEach(widget => {
      this.register(widget);
    });
  }

  register(widget: WidgetMetadata): void {
    this.widgets.set(widget.id, widget);
  }

  unregister(widgetId: string): void {
    this.widgets.delete(widgetId);
  }

  get(widgetId: string): WidgetMetadata | undefined {
    return this.widgets.get(widgetId);
  }

  // Find widgets that provide a specific data type
  findByCapability(type: DataType): WidgetMetadata[] {
    return Array.from(this.widgets.values()).filter(widget =>
      widget.provides.some(cap => cap.outputType === type)
    );
  }

  // Find widgets that require a specific data type
  findByRequirement(type: DataType): WidgetMetadata[] {
    return Array.from(this.widgets.values()).filter(widget =>
      widget.requires.some(req => req.type === type)
    );
  }

  // Find widgets that can connect to a given widget
  findCompatible(widgetId: string): WidgetMetadata[] {
    const widget = this.widgets.get(widgetId);
    if (!widget) return [];

    const compatible: Set<WidgetMetadata> = new Set();

    // Find widgets that can provide what this widget requires
    widget.requires.forEach(req => {
      this.findByCapability(req.type).forEach(provider => {
        if (provider.id !== widgetId) {
          compatible.add(provider);
        }
      });
    });

    // Find widgets that require what this widget provides
    widget.provides.forEach(cap => {
      this.findByRequirement(cap.outputType).forEach(consumer => {
        if (consumer.id !== widgetId) {
          compatible.add(consumer);
        }
      });
    });

    return Array.from(compatible);
  }

  // Advanced query for widget discovery
  query(query: WidgetQuery): WidgetMetadata[] {
    return Array.from(this.widgets.values()).filter(widget => {
      // Filter by provided type
      if (query.providesType && 
          !widget.provides.some(cap => cap.outputType === query.providesType)) {
        return false;
      }

      // Filter by specific capability
      if (query.providesCapability &&
          !widget.provides.some(cap => cap.id === query.providesCapability)) {
        return false;
      }

      // Filter by required type
      if (query.requiresType &&
          !widget.requires.some(req => req.type === query.requiresType)) {
        return false;
      }

      // Filter by required source
      if (query.requiresSource &&
          !widget.requires.some(req => req.source === query.requiresSource)) {
        return false;
      }

      // Filter by category
      if (query.category && widget.category !== query.category) {
        return false;
      }

      // Filter by tags
      if (query.tags && !query.tags.some(tag => widget.tags.includes(tag))) {
        return false;
      }

      // Filter by priority
      if (query.priority && widget.priority !== query.priority) {
        return false;
      }

      return true;
    });
  }

  // Get widgets that provide data to the given widget
  getProviders(widgetId: string): WidgetMetadata[] {
    const widget = this.widgets.get(widgetId);
    if (!widget) return [];

    return widget.relations
      .filter(rel => rel.type === 'depends_on')
      .map(rel => this.widgets.get(rel.targetWidgetId))
      .filter((w): w is WidgetMetadata => w !== undefined);
  }

  // Get widgets that consume data from the given widget
  getConsumers(widgetId: string): WidgetMetadata[] {
    const widget = this.widgets.get(widgetId);
    if (!widget) return [];

    return widget.relations
      .filter(rel => rel.type === 'provides_to')
      .map(rel => this.widgets.get(rel.targetWidgetId))
      .filter((w): w is WidgetMetadata => w !== undefined);
  }

  // Build complete dependency graph
  getDependencyGraph(): Map<string, string[]> {
    const graph = new Map<string, string[]>();

    this.widgets.forEach((widget, id) => {
      const dependencies = widget.relations
        .filter(rel => rel.type === 'depends_on')
        .map(rel => rel.targetWidgetId);
      graph.set(id, dependencies);
    });

    return graph;
  }

  // Get widget's introduction/description for ecosystem
  describeWidget(widgetId: string): string {
    const widget = this.widgets.get(widgetId);
    if (!widget) return 'Widget ikke fundet';

    const requires = widget.requires.map(r => `  - ${r.name} (${r.type}): ${r.description}`).join('\n');
    const provides = widget.provides.map(p => `  - ${p.name} (${p.outputType}): ${p.description}`).join('\n');
    const configs = widget.config.map(c => `  - ${c.name}: ${c.description}`).join('\n');

    return `
## ${widget.name} (v${widget.version})
${widget.description}

**Kategori:** ${widget.category}
**Tags:** ${widget.tags.join(', ')}
**Prioritet:** ${widget.priority || 'medium'}

### Kræver Data:
${requires || '  Ingen data-afhængigheder'}

### Leverer Data:
${provides || '  Ingen outputs'}

### Konfiguration:
${configs || '  Ingen konfigurerbare indstillinger'}

${widget.documentation ? `### Dokumentation:\n${widget.documentation}` : ''}
    `.trim();
  }

  // Export registry state for persistence or debugging
  export(): Record<string, WidgetMetadata> {
    const result: Record<string, WidgetMetadata> = {};
    this.widgets.forEach((widget, id) => {
      result[id] = widget;
    });
    return result;
  }
}

// Singleton instance
export const widgetRegistry = new WidgetRegistryImpl();

// React hook for widget discovery
export function useWidgetRegistry() {
  return widgetRegistry;
}