import { mergeWith } from "lodash";
import { LodashCustomizer } from "../../plot/utils.js";
import { MediaDataService } from "../grid/MediaDataService.js";
export { ServiceDataRequest, GalleryMappingScheme, Duplicate, DataRequestProcessing }
/**
* Request related helper methods for the gallery.
* @author ckraemme <ckraemme@awi.de>
* @author rhess <robin.hess@awi.de>
* @private
*/
class ServiceDataRequest {
/**
* Request multiple JSON objects via url list.
* @param {Object.Array} urlList - List of URLs.
* @return {Promise} Promises to the JSON requests.
*/
static requestMultipleJSONs(urlList) {
let promises = []
urlList.forEach((url) => {
promises.push(ServiceDataRequest.requestJSON(url));
});
return Promise.all(promises)
}
/**
* Create a request to a JSON file and return its data as an object via promise.
* @param {string} url - URL to the JSON file.
* @return {Promise} Promise containing json data when resolved.
*/
static requestJSON(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(response => {
const contentType = response.headers.get("content-type");
if (contentType.includes("application/json") && response.ok)
return response.json().then(json => { resolve(json), (error) => reject(error) })
else {
const errorMessage = `Error in JSON response:
HTTP status ${response.status}
Request: ${url}
Content Type: ${contentType}
Received Data: `.replace(/[ ]+/g, ' ')
return response.text().then(text => { reject(Error(errorMessage + text)) })
}
}).catch((error) => reject(error))
})
}
static requestXML(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(response => {
const contentType = response.headers.get("content-type");
if (["application/xml", "text/xml"].some(mimeType => contentType.includes(mimeType)) && response.ok)
return response.text().then(text => {
return new window.DOMParser().parseFromString(text, "text/xml")
}).then(xml => {
resolve(xml), (error) => reject(error)
})
else {
const errorMessage = `Error in XML response:
HTTP status ${response.status}
Request: ${url}
Content Type: ${contentType}
Received Data: `.replace(/[ ]+/g, ' ')
return response.text().then(text => { reject(Error(errorMessage + text)) })
}
}).catch((error) => reject(error))
})
}
}
/**
* Gallery mapping scheme related class.
* @author ckraemme <ckraemme@awi.de>
* @private
*/
class GalleryMappingScheme {
static findPropertyKeyInMapping(mappingScheme, dataKeyList) {
const findPropertyKey = (obj, value) =>
Object.keys(obj).reduce((acc, curr) => {
if (acc)
return acc
if (typeof obj[curr] !== 'object') {
if (obj[curr] == value)
return curr
}
else
return findPropertyKey(obj[curr], value)
}, null);
const dataKeyListMapped = dataKeyList.reduce((acc, curr) => {
const dataKeyMapped = findPropertyKey(mappingScheme, curr);
return dataKeyMapped ? [...acc, dataKeyMapped] : [...acc]
}, []);
return dataKeyListMapped
}
static getMappingScheme(galleryConfigDictionary) {
return galleryConfigDictionary['mapping'];
}
static apply(data, galleryConfigDictionary) {
const _filterDict = (dict, childKey) => {
return Object.keys(dict).reduce((acc, curr, idx) => {
const collect = {};
collect[curr] = dict[curr][childKey];
return Object.assign({}, collect, acc)
}, {})
}
const _customizer = (objValue, srcValue, key) => {
return LodashCustomizer.overwriteValues(objValue, srcValue, key, patternData)
}
const finalScheme = GalleryMappingScheme.getMappingScheme(galleryConfigDictionary);
const collect = [];
const overwriteData = galleryConfigDictionary['overwrite'] || {};
const constantData = _filterDict(overwriteData, "replacement");
const patternData = _filterDict(overwriteData, "pattern");
data.forEach(data => {
let mappedData = {}
if (data)
mappedData = GalleryMappingScheme._execute(data, finalScheme);
collect.push(mergeWith({}, mappedData, constantData, _customizer))
})
return collect
}
static _execute(data, mappingScheme) {
let dataCopy = structuredClone(data);
const recursiveMapping = (obj, obj_scheme) => {
let stack = {};
if (typeof obj_scheme !== 'object')
console.error('Wrong input data:', obj_scheme, obj);
for (let key in obj_scheme) {
if (typeof obj_scheme[key] !== 'object' && key in obj) {
//required for: {"viewer.media.dash": "videoSrc.1", "viewer.media.video": "videoSrc[0]"}
const keyIsList = obj_scheme[key].match(/(.+)(?:\[|\.)(\d+)\]?$/)
if (keyIsList) {
const keyName = keyIsList[1]
const index = keyIsList[2];
let data = stack[keyName] || [];
data.splice(index, 0, obj[key]);
stack[keyName] = data;
}
else
stack[obj_scheme[key]] = obj[key]
}
else if (key in obj && obj[key])
stack = Object.assign({}, stack, recursiveMapping(obj[key], obj_scheme[key]));
}
return stack
}
return recursiveMapping(dataCopy, mappingScheme);
}
}
/**
* Class that provides static methods for duplicates.
* @author ckraemme <ckraemme@awi.de>
*/
class Duplicate {
/**
* Remove all duplicates of dictionaries in a list of flat dictionaries based on keyMatch, but preserve specific data by merging the values of keyGroup first.
* @param {Array} dataList - List of flat dictionaries.
* @param {String} keyMatch - Key name where algorithm should be applied if found with the same value in an other dictionary.
* @returns Array of filtered dictionaries.
*/
static findAllKeyValuePairs(dataList, keyMatch = 'pid') {
/**
* Find a key value pair in a list of flat dictionaries and return all indices of dictionaries having this combination.
* @param {Array} data
* @param {String} key
* @param {String} value
* @returns Array of indices.
*/
function findKeyValuePair(data, key, value) {
const matchedIndices = data.reduce((acc, curr, index) => {
return curr[key] == value ? [...acc, index] : acc
}, [])
return matchedIndices
}
const collect = [];
dataList.forEach((item) => {
if (!item) {
collect.push(undefined)
return
}
const matchedIndices = dataList.map((mitem, mindex) => {
if (mitem && (mitem[keyMatch] == item[keyMatch]))
return mindex
}).filter(fitem => fitem != null ? true : false)
item['duplicateIndices'] = matchedIndices;
collect.push(item);
})
return collect
}
}
class DataRequestProcessing {
static resizeArray(arr, newSize, defaultValue) {
while (newSize > arr.length)
arr.push(defaultValue);
return arr
}
static mergeData(dataItems, newDataItems, startIndex, count) {
DataRequestProcessing.resizeArray(dataItems, startIndex + count, undefined)
dataItems.splice(startIndex, count, ...newDataItems);
return dataItems
}
static harmonizeData(dataItems, galleryConfigDict) {
const mappedDataItems = GalleryMappingScheme.apply(dataItems, galleryConfigDict);
const unifiedDataItems = MediaDataService.unifyData(mappedDataItems);
return unifiedDataItems
}
static includeSidebarData(dataItems, dataItemsHarmonized) {
const collect = structuredClone(dataItemsHarmonized);
dataItems.forEach((item, idx) => {
collect[idx]['sidebarData'] = item;
})
return collect
}
}