Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/firebird-ng/src/app/services/data-model.service.ts is written in an unsupported language. File is not indexed.

0001 import {Injectable, linkedSignal, signal} from "@angular/core";
0002 import { Event } from "../model/event";
0003 import { HttpClient } from "@angular/common/http";
0004 import { UrlService } from "./url.service";
0005 import { DataExchange } from "../model/data-exchange";
0006 import { fetchTextFile, loadJSONFileEvents, loadZipFileEvents } from "../utils/data-fetching.utils";
0007 
0008 /**
0009  * Service for loading and managing event/entry data in Firebird.
0010  *
0011  * This service encapsulates loading EDM4eic data (converted to DEX),
0012  * as well as loading existing Firebird DEX data from JSON or ZIP.
0013  * It stores a list of entries and the currently selected entry
0014  * as Angular signals.
0015  */
0016 @Injectable({
0017   providedIn: 'root'
0018 })
0019 export class DataModelService {
0020 
0021   /**
0022    * Signal holding the list of loaded entries (events).
0023    * Each Entry corresponds to one event's data in Firebird Dex format.
0024    */
0025   public entries = signal<Event[]>([]);
0026 
0027   /**
0028    * Signal holding the currently selected entry (event).
0029    */
0030   public currentEntry = linkedSignal(() => {
0031     if(this.entries().length > 0 ) {
0032       return this.entries()[0]
0033     }
0034     return null;
0035   });
0036 
0037   /**
0038    * Constructor that injects services needed for resolving URLs and making HTTP requests.
0039    * @param urlService - Service used for building/transforming URLs
0040    * @param http - Angular HttpClient for making network requests (currently not used directly here)
0041    */
0042   constructor(
0043     private urlService: UrlService,
0044     private http: HttpClient
0045   ) {}
0046 
0047   /**
0048    * Checks if an unknown object is valid "Firebird DEX" format by
0049    * verifying if it has a `"type": "firebird-dex-json"` property.
0050    *
0051    * @param obj - The object to inspect.
0052    * @returns True if the object has a `"type"` property equal to `"firebird-dex-json"`, otherwise false.
0053    */
0054   public isFirebirdDex(obj: unknown): boolean {
0055     return (
0056       typeof obj === "object" &&
0057       obj !== null &&
0058       "type" in obj &&
0059       (obj as any)["type"] === "firebird-dex-json"
0060     );
0061   }
0062 
0063   /**
0064    * Loads EDM4eic data from a given URL by calling the Firebird convert endpoint,
0065    * returning it in Firebird DEX format.
0066    *
0067    * @param url - The original location of the EDM4eic ROOT file (or other source).
0068    * @param entryNames - Comma-separated entry indices (default "0"). Passed to the converter service.
0069    * @returns A Promise that resolves to a DataExchange object or null if there's an error.
0070    */
0071   async loadRootData(url: string, entryNames: string = "0"): Promise<DataExchange | null> {
0072     try {
0073       // Early exit if no URL is provided
0074       if (!url) {
0075         console.log("[DataModelService.loadEdm4EicData] No data source specified.");
0076         return null;
0077       }
0078 
0079       // Let urlService build the final convert URL
0080       let finalUrl = this.urlService.resolveConvertUrl(url, "edm4eic", entryNames);
0081       console.log(`[DataModelService.loadDexData] Fetching: ${finalUrl}`);
0082 
0083       // Load the text from that URL
0084       const jsonData = await fetchTextFile(finalUrl);
0085 
0086       // Parse JSON
0087       const dexData = JSON.parse(jsonData);
0088 
0089       // Validate format
0090       if (!this.isFirebirdDex(dexData)) {
0091         console.error("[DataModelService.loadDexData] The JSON does not conform to Firebird DEX JSON format.");
0092         return null;
0093       }
0094 
0095       // Build DataExchange structure
0096       let data = DataExchange.fromDexObj(dexData);
0097       console.log(data);
0098       return data;
0099 
0100     } catch (error) {
0101       // Log errors
0102       console.error(`[DataModelService.loadEdm4EicData] Failed to load data: ${error}`);
0103       console.log("Default config will be used");
0104     } finally {
0105       // No final cleanup needed right now
0106     }
0107     return null;
0108   }
0109 
0110   /**
0111    * Loads a Firebird DEX JSON or ZIP file from a specified URL.
0112    *
0113    * @param url - The URL of the .firebird.json or .zip file.
0114    * @returns A Promise that resolves to a DataExchange object or null if there's an error.
0115    */
0116   async loadDexData(url: string): Promise<DataExchange | null> {
0117     try {
0118       // If no URL is provided, exit.
0119       if (!url) {
0120         console.log("[DataModelService.loadDexData] No data source specified.");
0121         return null;
0122       }
0123 
0124       // Basic extension check (not strictly required)
0125       if (
0126         !url.endsWith("firebird.json") &&
0127         !url.endsWith("firebird.json.zip") &&
0128         !url.endsWith("firebird.zip")
0129       ) {
0130         console.log("[DataModelService.loadDexData] Wrong extension or file type.");
0131       }
0132 
0133       // Resolve local aliases or relative paths
0134       let finalUrl = url;
0135       if (url.startsWith("asset://")) {
0136         // Transform 'asset://' URLs to 'assets/' paths. This removes the leading slash
0137         // intentionally to support deployment in the /firebird subdirectory.
0138         finalUrl = "assets/" + url.substring("asset://".length);
0139       } else if (!url.startsWith("http://") && !url.startsWith("https://")) {
0140         finalUrl = this.urlService.resolveDownloadUrl(url);
0141       }
0142 
0143       let dexData = {};
0144       console.log(`[DataModelService.loadDexData] Loading: ${finalUrl}`);
0145 
0146       // Decide which loader to call based on file extension
0147       if (finalUrl.endsWith("zip")) {
0148         // Load from ZIP
0149         dexData = await loadZipFileEvents(finalUrl);
0150       } else {
0151         // Load from raw JSON
0152         dexData = await loadJSONFileEvents(finalUrl);
0153       }
0154 
0155       // Validate Firebird DEX structure
0156       if (!this.isFirebirdDex(dexData)) {
0157         console.error("[DataModelService.loadDexData] The JSON does not conform to Firebird DEX JSON format.");
0158         return null;
0159       }
0160 
0161       console.log(`[DataModelService.loadDexData] Deserializing from DEX`);
0162       let data = DataExchange.fromDexObj(dexData);
0163       console.log(data);
0164 
0165       // Extract entry names/IDs for debugging or usage
0166       const entryNames = data.events.map((entry) => entry.id);
0167 
0168       // Update service signals with the newly loaded entries
0169       if (dexData) {
0170         this.entries.set(data.events);
0171         if (this.entries().length > 0) {
0172           // If at least one entry is present, automatically set the first as current
0173           this.setCurrentEntry(this.entries()[0]);
0174         }
0175       }
0176 
0177       return data;
0178 
0179     } catch (error) {
0180       console.error(`[DataModelService.loadDexData] Failed to load data: ${error}`);
0181       console.log(`[DataModelService.loadDexData] Default config will be used`);
0182     } finally {
0183       // No final cleanup needed right now
0184     }
0185     return null;
0186   }
0187 
0188   /**
0189    * Sets the currently selected entry (event) to the provided `Entry`.
0190    *
0191    * @param entry - The Entry object to be marked as current.
0192    */
0193   setCurrentEntry(entry: Event): void {
0194     console.log(`[DataModelService.setCurrentEntry] Setting event: ${entry.id}`);
0195     this.currentEntry.set(entry);
0196   }
0197 
0198   /**
0199    * Finds and sets the current entry by its name (i.e. `entry.id`).
0200    *
0201    * @param name - The string name or ID of the entry to set as current.
0202    */
0203   setCurrentEntryByName(name: string): void {
0204     // Look up the first Entry whose 'id' matches the provided name
0205     const found = this.entries().find((entry) => entry.id === name);
0206 
0207     // If found, update currentEntry; otherwise log a warning.
0208     if (found) {
0209       this.setCurrentEntry(found);
0210     } else {
0211       console.warn(`[DataModelService] setCurrentEntryByName: Entry with id='${name}' not found.`);
0212     }
0213   }
0214 }