(function(){
var jqScreen = $('#screen_problem'),
languageCache = {}, // keyed by language identifier: processed data about languages
translationCache = [], // keys are autogenerated in ta(), a value is a dictionary of translations of a translation key for every language
langs, Nlangs, // constants, set on init
chooseTranslation = function (keyword, lang, currentDict, enDict, translations) {
var tr = currentDict[keyword],
otherLang;
if (tr) return tr; // if there is a translation in the current dictionary: return it
tr = enDict[keyword];
if (tr) { // if there is a translation in the english dictionary: return it
codeq.log.info('Translation for ' + keyword + ' not set for language ' + lang + ', using translation from en');
return tr;
}
for (otherLang in translations) {
if (!translations.hasOwnProperty(otherLang)) continue;
tr = (translations[otherLang] || {})[keyword];
if (tr) { // otherwise: return the first available translation in any language
codeq.log.info('Translation for ' + keyword + ' not set for language ' + lang + ', using translation from ' + otherLang);
return tr;
}
}
return keyword + ' not set for language ' + lang;
},
/**
* convert the input translations (arg0) for given keys (arg1..argN)
* so each keys holds all its translations for ever language
*/
convertTranslations = function () {
var translations = arguments[0] || {},
result = {},
enDict = translations['en'] || {},
lang, dict, i, keyword, l;
// initialize result: one lang-dict per keyword
for (i = arguments.length - 1; i > 0; i--) result[arguments[i]] = {};
// convert translations: one keyword-dict per lang -> one lang-dict per keyword
for (l = Nlangs - 1; l >= 0; l--) {
lang = langs[l];
dict = translations[lang] || {};
for (i = arguments.length - 1; i > 0; i--) {
keyword = arguments[i];
// result[keyword][lang] = dict[keyword] || keyword + ' not set for language ' + lang;
result[keyword][lang] = chooseTranslation(keyword, lang, dict, enDict, translations);
}
}
return result;
},
/**
* Connect the given translations of a key with the DOM, returning
* the string of arguments to use with a HTML tag which will contain
* a translation chosen from the given dictionary.
*/
ta = function (trObj) { // an object of the form: {'en': 'english content', 'sl': 'slovenska vsebina'}
var result = ['data-dict="directory" data-tkey="', translationCache.length, '"'].join('');
translationCache.push(trObj);
return result;
},
/**
* Assemble the display structure and translations from the server's
* language.json for the given language identifier.
*/
createLanguageData = function (data, languageIdentifier) { // data is the content of language.json
var li = languageIdentifier, // a shorthand
groups = data.groups || {},
html = [],
problemReferences = [],
groupIdentifier, group, problems, problemIdentifier, problem;
var langDict = convertTranslations(data.translations, 'name', 'description'), // this will be the resulting dictionary: multi-level keys that lead up to the lang-dict
groupDict, problemDict;
// title: HTML structure for "name" and "desc"
html.push('
');
html.push('');
// content: problem directory
html.push('');
for (groupIdentifier in groups) {
if (!groups.hasOwnProperty(groupIdentifier)) continue;
group = groups[groupIdentifier] || {};
groupDict = convertTranslations(group.translations, 'name', 'description'); // the group-level translations, added will
// group content
html.push('- ');
html.push('');
html.push('
');
// problem content
problems = group.problems || {};
for (problemIdentifier in problems) {
if (!problems.hasOwnProperty(problemIdentifier)) continue;
problem = problems[problemIdentifier] || {};
problemDict = convertTranslations(problem.translations, 'name');
html.push(' ');
problemReferences.push({'g': groupIdentifier, 'p': problemIdentifier});
}
html.push('
');
}
html.push('
');
return {
'language': languageIdentifier,
'html': html.join(''),
'refs': problemReferences,
'hints': {} // TODO: prepare common hints for the language
};
},
/**
* Instantiates the screen from the given processed data.
*/
createDom = function (data) {
var language = data.language;
jqScreen.html(data.html);
codeq.tr.translateDom(jqScreen);
jqScreen.find('a').on('click', function () {
var index = +$(this).attr('class').split(' ')[0].split('-')[1],
ref = data.refs[index];
if (!ref) {
codeq.log.error('Clicked on a problem link having erroneous index: ' + index);
return;
}
// transition
codeq.wait(
codeq.comms.getProblem(language, ref.g, ref.p)
.then(function (data) {
if (data.code !== 0) throw new Error('Failed to obtain problem data, code: ' + data.code + ', message: ' + data.message);
codeq.globalStateMachine.transition(language, data);
})
)
.fail(function (reason) {
codeq.log.error('Failed to obtain the problem definition: ' + reason, reason);
alert('Failed to obtain the problem definition: ' + reason);
})
.done();
});
},
currentLanguage; // the currently active language
// ================================================================================
// Initialization, invoked from the boot sequence
// ================================================================================
codeq.on('init', function () {
codeq.tr.registerDictionary('directory', translationCache);
langs = codeq.availableLangs; // cache for easier access
Nlangs = langs.length;
});
// ================================================================================
// Register with the state machine
// ================================================================================
codeq.globalStateMachine.register('problem', {
'enter': function(language){
var data = null; // language data
$('#navigation-login').css('display', '');
$('#navigation-language').css('display', '');
$("#navigation-problem").addClass("active").css('display', '');
if (!language) language = currentLanguage; // This happens when we hit this with the back button
if (currentLanguage !== language) {
jqScreen.empty();
currentLanguage = language;
data = languageCache[language];
if (data) {
createDom(data);
}
else {
codeq.wait(codeq.comms.getLanguageDef(language).then(function (rawData) {
var data = createLanguageData(rawData, language);
languageCache[language] = data;
createDom(data);
})).done();
}
}
jqScreen.css('display', '');
},
'exit' : function(){
jqScreen.css('display', 'none');
$('#navigation-login').css('display', 'none');
$('#navigation-language').css('display', 'none');
$('#navigation-problem').css('display', 'none').removeClass("active");
}
});
})();