/**
* AngularJS Service for loading and storing game data and locale information.
*
* @module gameDataService
* @see https://docs.angularjs.org/api/ng/type/angular.Module#service
*
* @requires APIService
* @requires debugService
* @requires domainService
* @requires URLParamsService
*/
angular.module('tgaApp').service('gameDataService', [
'$log',
'$document',
'APIService',
'debugService',
'domainService',
'URLParamsService',
'$translate',
'envService',
'languageData',
function gameDataService(
$log,
$document,
APIService,
debugService,
domainService,
URLParamsService,
$translate,
envService,
languageData,
) {
/**
* @private
* @member {?Object} gameData
*/
let gameData = null;
const { domain } = domainService;
/**
* Returns the game data from {@link module:gameDataService~gameData}
*
* @returns {?Object}
*/
this.get = () => gameData;
/**
* Returns a deep copy of the game data from {@link module:gameDataService~gameData}
*
* @returns {?Object}
*/
this.getCopy = () => {
const dataStr = angular.toJson(gameData);
return angular.fromJson(dataStr);
};
/**
* Load game data.
*
* @param {Object} params
* @param {number} params.game_id
* @param {number} params.language_id
* @param {Function} [params.callback]
*/
this.load = ({ language_id, game_id, callback }) => {
const { slug, token } = URLParamsService.getSiteParams();
if (debugService.enabled() && debugService.use('gameData')) {
APIService.getGameFile(debugService.get('gameData'),
(game) => {
gameData = game;
$log.debug('debug game file loaded', game);
if (callback) {
callback(game);
}
});
} else {
APIService.getGame({
...(token && { token }),
...(language_id && { language_id }),
...(game_id && { game_id }),
domain,
slug,
// eslint-disable-next-line no-use-before-define
}, (game) => loaded(game, callback));
}
};
/**
* Return the leaderboard fields that will be in used in the game
*
*/
this.getLeaderboardFields = () => {
if (gameData) {
const defaultFields = gameData.registration.fields.filter((f) => f.show_in_leaderboard);
const customFields = Object.values(gameData.registration.custom_fields).filter((f) => f.show_in_leaderboard);
const leaderboardFields = [
...defaultFields,
...customFields,
];
return leaderboardFields;
}
return [];
};
/**
* Set locale by code (aka `en_us`) and load game data.
*
* @param {string} code
* @param {Function} [callback]
*/
this.setLocale = (code, callback) => {
const { available_translations, language_id, game_id } = gameData;
const t = available_translations.find((tr) => tr.code === code);
if (t && t.language_id !== language_id) {
this.load({ language_id: t.language_id, game_id, callback });
}
};
/**
* Search the available translations by a specific key/value.
*
* @example <caption>Both return the "English (US)" language description, if it exists:</caption>
* findLanguageBy(0, 'language_id'); // searches by numeric ID.
* findLanguageBy('en_us', 'code'); // searches by locale code.
*
* @param {string|number} search_value - The value to search for in the provided key.
* @param {string} search_key - The name of the key to search.
* @param {string} use_fallback_data - Use data array stored in wrapper as fallback
* @return {?Object} The language description object, if found.
*/
this.findLanguageBy = (search_value, search_key, use_fallback_data) => {
const { available_translations } = gameData;
const hasTranslations = angular.isArray(available_translations) && available_translations.length > 0;
if (!hasTranslations) {
// eslint-disable-next-line max-len
$log.debug(`gameDataService: trying to find a language but available translations is empty. ${use_fallback_data ? 'Using fallback data.' : ''}`);
}
const langArray = use_fallback_data && !hasTranslations ? languageData : available_translations;
for (let i = 0; i < langArray.length; i++) {
const t = langArray[i];
// loose comparsion in case int checked against string
// eslint-disable-next-line eqeqeq
if (t[search_key] == search_value) {
return t;
}
}
return null;
};
/**
* Callback used by {@link module:gameDataService.load} to handle a
* successful response from {@link module:APIService.getGame}.
*
* @private
* @method loaded
* @param {Object} game
* @param {Function} [callback]
*/
const loaded = (game, callback) => {
// filter out custom fields with a 'disabled' status
// eslint-disable-next-line no-param-reassign
game.registration.custom_fields = game.registration.custom_fields.filter((f) => f.condition !== 'disabled');
gameData = game;
APIService.setGameId(game.game_id);
if (envService.get() !== 'production') {
$log.debug('game loaded', game);
}
const { language_id } = game;
const currentLanguage = this.findLanguageBy(language_id, 'language_id', true);
$translate.use(currentLanguage.code);
angular.element($document[0].querySelector('body')).addClass(currentLanguage.code);
const { language } = URLParamsService.getUserParams();
if (language) {
const l = this.findLanguageBy(language, 'code', true);
if (l) {
this.setLocale(l, callback);
return;
}
}
if (callback) {
callback(game);
}
};
},
]);