AnP/Public/ecma/Managers/ThreadsManager.ecma.js

258 lines
6.0 KiB
JavaScript

"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.<number, Array.<string>>} */
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.<string, any|null>} */
ThreadsManager.DEFAULT_SETTINGS = {};
return ThreadsManager;
})();