"use strict"; var AppConstants = require('../constants/AppConstants'); var AppDispatcher = require('../dispatcher/AppDispatcher'); var EventEmitter = require('events').EventEmitter; var levelSequences = require('../../levels').levelSequences; var sequenceInfo = require('../../levels').sequenceInfo; var ActionTypes = AppConstants.ActionTypes; var SOLVED_MAP_STORAGE_KEY = 'solvedMap'; var _levelMap = {}; var _solvedMap = {}; var _sequences = []; try { _solvedMap = JSON.parse( localStorage.getItem(SOLVED_MAP_STORAGE_KEY) || '{}' ) || {}; } catch (e) { console.warn('local storage failed', e); } function _syncToStorage() { try { localStorage.setItem(SOLVED_MAP_STORAGE_KEY, JSON.stringify(_solvedMap)); } catch (e) { console.warn('local storage failed on set', e); } } var validateLevel = function(level) { level = level || {}; var requiredFields = [ 'name', 'goalTreeString', //'description', 'solutionCommand' ]; requiredFields.forEach(function(field) { if (level[field] === undefined) { console.log(level); throw new Error('I need this field for a level: ' + field); } }); }; /** * Unpack the level sequences. */ Object.keys(levelSequences).forEach(function(levelSequenceName) { var levels = levelSequences[levelSequenceName]; _sequences.push(levelSequenceName); if (!levels || !levels.length) { throw new Error('no empty sequences allowed'); } // for this particular sequence... levels.forEach(function(level, index) { validateLevel(level); var id = levelSequenceName + String(index + 1); var compiledLevel = Object.assign( {}, level, { index: index, id: id, sequenceName: levelSequenceName } ); // update our internal data _levelMap[id] = compiledLevel; levelSequences[levelSequenceName][index] = compiledLevel; }); }); var LevelStore = Object.assign( {}, EventEmitter.prototype, AppConstants.StoreSubscribePrototype, { getSequenceToLevels: function() { return levelSequences; }, getSequences: function() { return Object.keys(levelSequences); }, getLevelsInSequence: function(sequenceName) { if (!levelSequences[sequenceName]) { throw new Error('that sequecne name ' + sequenceName + 'does not exist'); } return levelSequences[sequenceName]; }, getSequenceInfo: function(sequenceName) { return sequenceInfo[sequenceName]; }, getLevel: function(id) { return _levelMap[id]; }, getNextLevel: function(id) { if (!_levelMap[id]) { console.warn('that level doesn\'t exist!!!'); return null; } // meh, this method could be better. It's a trade-off between // having the sequence structure be really simple JSON // and having no connectivity information between levels, which means // you have to build that up yourself on every query var level = _levelMap[id]; var sequenceName = level.sequenceName; var sequence = levelSequences[sequenceName]; var nextIndex = level.index + 1; if (nextIndex < sequence.length) { return sequence[nextIndex]; } var nextSequenceIndex = _sequences.indexOf(sequenceName) + 1; if (nextSequenceIndex < _sequences.length) { var nextSequenceName = _sequences[nextSequenceIndex]; return levelSequences[nextSequenceName][0]; } // they finished the last level! return null; }, isLevelSolved: function(levelID) { if (!_levelMap[levelID]) { throw new Error('that level doesn\'t exist!'); } return !!_solvedMap[levelID]; }, dispatchToken: AppDispatcher.register(function(payload) { var action = payload.action; var shouldInform = false; switch (action.type) { case ActionTypes.RESET_LEVELS_SOLVED: _solvedMap = {}; _syncToStorage(); shouldInform = true; break; case ActionTypes.SET_LEVEL_SOLVED: _solvedMap[action.levelID] = true; _syncToStorage(); shouldInform = true; break; } if (shouldInform) { LevelStore.emit(AppConstants.CHANGE_EVENT); } }) }); module.exports = LevelStore;