let timeoutIDs = [];

export const renderIf = condition => component => condition && component;

export const limitEval = (code, fnOnStop, opt_timeoutInMS = 1000) => {
  // Chris West http://cwestblog.com/2016/03/16/javascript-detecting-infinite-loops/

  function clearTimeouts () {
    timeoutIDs.forEach(id => {
      clearTimeout(id);
    });
    timeoutIDs = [];
  }

  let id = Math.random() + 1;
  const blob = new Blob(
    [
      `onmessage = function (message){
        const data = message.data;

        // increment id and send message back to parent process
        // before executing code. This will start the setTimeout
        postMessage({ id: data.id + 1 });

        // if data.code evaluates in time,
        // a new message is sent with the original ID
        // If not, the setTimeout callback will kill the worker
        // TODO: check for syntax errors in data.code
        postMessage({ returnedVal: eval.call(this, data.code) , id:data.id });
      };`
    ],
    { type:'text/javascript' });
  const myWorker = new Worker(URL.createObjectURL(blob));

  // eslint-disable-next-line no-unused-vars
  function onDone(success) {
    clearTimeouts();
    URL.revokeObjectURL(blob);
    fnOnStop.apply(this, arguments);
  }

  myWorker.onmessage = (message) => {
    const data = message.data;
    if (data) {
      if (data.id === id) {
        id = 0;
        onDone(true, data.returnedVal);
      }
      else if (data.id === id + 1) {
        const timeoutID = setTimeout(function killWorker() {
          // if the code successfully ran, id === 0
          if (id) {
            myWorker.terminate();
            onDone(false);
          }
        }, opt_timeoutInMS);
        timeoutIDs.push(timeoutID);
      }
    }
  };

  myWorker.postMessage({ code, id });
};
