"use strict"; import {ThreadModel} from "../Models/ThreadModel.ecma.js"; import {Common} from "../Utils/Common.ecma.js"; import {Check} from "../Utils/Checks.ecma.js"; /** * @typedef {import("../Application/AnP.ecma.js").AnP} AnP */ /** * @class ThreadsManager * @constructor * @param {!AnP} anp * @returns {void} * @access private * @static */ export const ThreadsManager = (function(){ /** * @callback simple_callback * @returns {void} */ /** * @callback continue_callback * @param {!boolean} ok * @return {boolean} */ /** * @constructs ThreadsManager * @param {!AnP} anp * @returns {void} * @access private * @static */ const ThreadsManager = function(anp){ /** @type {!AnP} */ const self = this, /** @type {Object.>} */ threads = {}; /** @type {boolean} */ let started = false, /** @type {number} */ thread_i = 0, /** @type {number} */ interval = null, /** @type {string} */ mode = "interval", /** @type {number} */ frames_per_second = 60, /** @type {number} */ timer = 1000 / frames_per_second; /** * @returns {void} * @access private */ const constructor = () => { self.start(); }; /** * @param {?continue_callback} callback * @returns {boolean} * @access public */ this.update = (callback = null) => { mode = anp.settings.get("threads_mode", null, mode); Common.execute(callback); }; /** * @param {?continue_callback} callback * @returns {boolean} * @access public */ this.reset = (callback = null) => { Common.clear_dictionary(threads); mode = "interval"; self.update(callback); }; /** * @param {?continue_callback} callback * @returns {boolean} * @access public */ this.start = (callback = null) => { /** @type {continue_callback} */ const end = ok => Common.execute(callback, ok); if(started){ end(false); return false; }; started = true; self.update(() => { executor(); end(true); }); return true; }; /** * @param {?continue_callback} callback * @returns {boolean} * @access public */ this.close = (callback = null) => { /** @type {continue_callback} */ const end = ok => Common.execute(callback, ok); if(!started){ end(false); return false; }; started = false; end(true); return true; }; /** * @returns {void} * @access private */ const execute = () => { /** @type {number} */ const time = Date.now(); [...Object.entries(threads)].forEach(([i, thread]) => { if(!thread.stopped && ( !thread.frames_per_second || time - thread.last >= thread.timer )){ thread.callback(thread); if(thread.bucle) thread.last = time; else delete threads[i]; }; }); }; /** * @returns {void} * @access private */ const executor = () => { if(!started) return; switch(mode){ case "interval": interval = setInterval(execute, timer); break; case "timeout": setTimeout(() => { execute(); executor(); }, timer); break; case "animation": /** @type {number} */ const time = Date.now(); requestAnimationFrame(() => { execute(); setTimeout(executor, timer - (Date.now() - time)); }); break; case "only_animation": requestAnimationFrame(() => { execute(); executor(); }); break; }; }; /** * @param {?any} inputs * @param {!boolean} [overwrite = false] * @param {?simple_callback} [callback = null] * @return {void} * @access public */ this.add = (callback, inputs = null) => { if(!Check.is_function(callback)) return null; threads[++ thread_i] = new ThreadModel(callback, thread_i, inputs); return thread_i; }; /** * @param {!number} i * @return {void} * @access public */ this.play = i => { threads[i] && threads[i].stopped && (threads[i].stopped = false); }; /** * @param {!number} i * @return {void} * @access public */ this.stop = i => { threads[i] && !threads[i].stopped && (threads[i].stopped = true); }; /** * @param {!number} i * @return {boolean} * @access public */ this.close = i => { if(threads[i]){ delete threads[i]; return true; }; return false; }; constructor(); }; /** @type {Object.} */ ThreadsManager.DEFAULT_SETTINGS = {}; return ThreadsManager; })();