/**
* @author Wolfgang Kowarschick <kowa@hs-augsburg.de>
* @copyright 2017-2018
* @license CC-BY-NC-SA-4.0
*/
/**
* @deprecated use <code>{@link module:wk/config/concretize}</code> instead
*/
/**
* @module wk/util/concretize
*/
import stringToHex from '/wk_pixi/util/stringToHex';
/** @private */
const C_EMPTY = Object.freeze({});
/**
* @function
* @static
*
* @description
* Computes a concrete value, if a template value is passed.
* Otherwise the original value is returned.
*
* Templates are:
* <ul>
* <li>
* An array with at least two elements
* whose first element is <code>"@some"</code>.
* For such an array some of its other elements
* is returned randomly.
* </li>
* <li>
* An object that contains two special attributes
* named <code>"@min"</code> and <code>"@max"</code>.
* The values of those attributes have to be numbers.
* Returned is a random value within the interval
* defined by <code>"@min"</code> and <code>"@max"</code>.
*
* There are further attributes that affect the computation
* of the random value:
*
* <ul>
* <li><code>"@integer": true/false</code>:
* If true, an integer value is computed within the interval
* [@min, @max]. If false, a float value is computed
* within the interval [@min, @max[.
* </li>
* <li><code>"@positive": value</code>:
* The value has to be a number greater or equal 0 and less or equal 1.
* The randomly computed number is with a probability of
* <code>value</code> a member of [@min, @max] or [@min, @max[ resp.
* and with a probability of <code>1-value</code>
* a member of [-@max, -@min] or [-@max, -@min[.
* </li>
* <li><code>"@relative": "name" (a string value)</code>:
* The computed value is multiplied with the environment value
* <code>p_environment[name]</code>, if that value exists.
* </li>
* </ul>
* </li>
* <li><code>{"@stringToHeX": "#AFFE00"}</code>:
* A six byte color key is converted into the corresponding
* integer code of that color. This is needed by PixiJS, as that library
* can only deal with integer color codes instead of string color codes.
* Hex values, such as 0xAFFE00 which are accepted by PixiJS,
* on the other sides, cannot be stored in JSON-Files....
* </li>
* <li><code>"@@NAME"</code>:
* Two @-symbols at the beginning of a key name (including
* <code>"@@some"</code>) are replace by one. So, those keys are
* not concretized by the first invocation of this function
* but by the second. If the key name starts with more then
* two @-symbols, <code>concretize</code> must applied correspondingly often to
* concretize the value associated.
* </li>
* </ul>
*
* @param {Object} p_config
* An object which may contain a @-values that have to be replaced
* by concrete values.
* @param {Object} p_environment
* An object containing base values which can be referred by @-values.
* If such a value is a function, it is called to compute the base
* value. The current element in the array and its position are passed
* to that function.
* @param {Array.<String>} p_specials
* If not null, only those specials are expanded that are member of the
* array <code>p_specials</code>.
* @param {?number} p_level
* The number of levels that shall be concretized recursively.
* @param {?object} p_info = null
* (used internally only; see <code>p_environment</code>)
* @return {*}
* The computed value if one has been computed,
* <code>p_config</code> otherwise.
*/
function concretize({config: p_config,
environment: p_environment = C_EMPTY,
specials: p_specials = null,
level: p_level = null,
info: p_info = C_EMPTY
})
{ const
f_is_special = p_name => p_specials == null || p_specials.includes(p_name);
let l_level = Number.isFinite(p_level) ? p_level-1 : p_level;
if (Number.isFinite(p_level) && p_level <= 0)
{ return p_config; }
if (typeof p_config === 'string' || p_config instanceof String)
{ return(p_config.charAt(0) === '@' && f_is_special(p_config))
? (p_config.charAt(1) !== '@')
? (typeof p_environment[p_config] === 'function'
? p_environment[p_config](p_info)
: p_environment[p_config]
)
: p_config.substr(1)
: p_config;
}
if (p_config instanceof Array)
{ let l_first = p_config[0];
if ( (typeof l_first === 'string' || l_first instanceof String)
&& (l_first.charAt(1) === '@' && l_first.charAt(0) === '@')
&& f_is_special(l_first)
)
{ return [l_first.substr(1), ...[...p_config].shift()];}
if (l_first === '@some' && f_is_special('@some'))
{ return concretize
({config: p_config[Math.floor(Math.random()*(p_config.length-1))+1],
environment: p_environment,
specials: p_specials,
level: l_level,
info: p_info
});
}
const c_result = [];
for (let i = 0, n = p_config.length; i < n; i++)
{ let
l_element = p_config[i],
l_number = 1;
if ( f_is_special('@number')
&& l_element instanceof Object
&& Number.isFinite(l_element['@number'])
)
{ l_number = l_element['@number'];
l_element = {...l_element};
delete l_element['@number'];
}
for (let j = 0; j < l_number; j++)
{ c_result.push(concretize({config: l_element,
environment: p_environment,
specials: p_specials,
level: l_level,
info: { element: l_element,
number: l_number,
pos: j,
posSource: i,
posResult: i*l_number+j
}
})
);
}
}
return c_result;
}
if (p_config instanceof Object)
{ if (p_config['@stringToHex'] != null && f_is_special('@stringToHex'))
{ const
c_stringToHex = concretize({config: p_config['@stringToHex'],
environment: p_environment,
specials: p_specials,
level: l_level,
info: p_info
});
if ( typeof c_stringToHex === 'string' || c_stringToHex instanceof String
|| (Number.isFinite(c_stringToHex) && c_stringToHex >= 0)
)
return stringToHex(c_stringToHex);
}
if (f_is_special('@min') || f_is_special('@max'))
{ const
c_min = concretize({config: p_config['@min'],
environment: p_environment,
specials: p_specials,
level: l_level,
info: p_info
}),
c_max = concretize({config: p_config['@max'],
environment: p_environment,
specials: p_specials,
level: l_level,
info: p_info
});
if (Number.isFinite(c_min) && Number.isFinite(c_max))
{ const
c_is_int = (p_config['@integer'] === true),
c_is_relative = p_config['@relative'],
c_positive = p_config['@positive'];
let
l_result;
if (c_is_int)
l_result = Math.floor(c_min + Math.random() * (c_max + 1 - c_min));
else
l_result = c_min + Math.random() * (c_max - c_min);
if (Number.isFinite(c_positive))
l_result *= (Math.random() >= c_positive) ? 1 : -1;
if ( c_is_relative
&& p_environment !== null
&& p_environment[c_is_relative] !== null
)
{ return l_result * (p_environment[c_is_relative]); }
else
{ return l_result; }
}
}
const c_result = {};
for (let l_key of Object.keys(p_config))
if ( l_key.charAt(0) !== '@' ||
(l_key.charAt(1) === '@' && f_is_special(l_key))
)
c_result[l_key.charAt(1) === '@' ? l_key.substring(1) : l_key]
= concretize({config: p_config[l_key],
environment: p_environment,
specials: p_specials,
level: l_level,
info: p_info
});
return c_result;
}
return p_config;
}
export {concretize};
export default concretize;