"use strict";
const _ = require("underscore");
const s = require("underscore.string");
const fs = require("fs");
const path = require("path");
/**
* Loads the data related to options and option groups defined in the metadata.
*
* @module services/optionDataLoader
*/
module.exports = optionDataLoader;
/**
* Creates the loader using the passed configuration.
*
* @alias module:services/optionDataLoader
* @param {OptionGroup[]} optionGroups - All option groups
* @param {string} imageDirectory - Image directory to find resources for options
* @param {string} imageExtension - Image filename extension for option resources
* @return {{createOptionGroupsMap: createOptionGroupsMap, createOptionsMap: createOptionsMap, createOptionImagesMap: createOptionImagesMap}}
* @throws {Error} when there is a problem with passed parameters
*/
function optionDataLoader(optionGroups, imageDirectory, imageExtension) {
if (_.isEmpty(optionGroups)) {
throw new Error("No option groups provided");
}
if (s.isBlank(imageDirectory)) {
throw new Error("No image directory provided");
}
if (!fs.existsSync(imageDirectory)) {
throw new Error("Given image directory does not exist : " + imageDirectory);
}
if (s.isBlank(imageExtension)) {
throw new Error("No image extension provided");
}
// prepend dot if passed extension doesn't start with that
if (!s.startsWith(imageExtension, ".")) {
imageExtension = "." + imageExtension;
}
return {
/**
* Creates a map to access option groups by id.
*
* Please note that keys of the returned map are string, not integers.
*
* @function
* @instance
* @return {Object.<string, OptionGroup>}
*/
createOptionGroupsMap: createOptionGroupsMap,
/**
* Creates a map to access options by id.
* @function
* @instance
* @return {Object.<string, Option>}
*/
createOptionsMap: createOptionsMap,
/**
* Creates a map to access images of the options by id.
*
* If option doesn't have any color, then value in the map will be
* the image. Otherwise, fetched value will be again a map. But this
* time a map of <color, image>.
*
* Please note that reading the images into memory for all
* options with their colors are quite a big thing. Don't call
* this method more than once!
*
* @function
* @instance
* @return {Object.<string, OptionImageMapValueItem>}
*/
createOptionImagesMap: createOptionImagesMap
};
function createOptionGroupsMap() {
return _.indexBy(optionGroups, "id");
}
function createOptionsMap() {
const optionsMap = {};
for (let optionGroup of optionGroups) {
for (let option of optionGroup.options) {
optionsMap[option.id] = option;
}
}
return optionsMap;
}
function createOptionImagesMap() {
const optionImagesMap = {};
for (let optionGroup of optionGroups) {
for (let option of optionGroup.options) {
if (option.colors) {
optionImagesMap[option.id] = {};
for (let color of option.colors) {
optionImagesMap[option.id][color] = fs.readFileSync(getFilePath(option, color));
}
}
else {
optionImagesMap[option.id] = fs.readFileSync(getFilePath(option, null));
}
}
}
return optionImagesMap;
}
/**
* Get the file path for the option w/ given optional color.
*
* @private
* @param option
* @param color
* @return {string} the file path
*
* @example
* // returns "/some/path/skin.png"
* getFilePath({resource:"skin"}, color:undefined)
*
* @example
* // returns "/some/path/skin_FF00FF.png"
* getFilePath({resource:"skin"}, color:"FF00FF")
*
*/
function getFilePath(option, color) {
if (!color) {
return path.join(imageDirectory, option.resource + imageExtension);
}
else {
return path.join(imageDirectory, option.resource + "_" + colorName(color) + imageExtension);
}
}
}
function colorName(color) {
return color.replace("#", "hash");
}