/**
 *
 * Gif parser by @gtk2k
 * https://github.com/gtk2k/gtk2k.github.io/tree/master/animation_gif
 *
 */

const parseGIF = function(gif, successCB, errorCB) {
  let pos = 0;
  const delayTimes = [];
  let graphicControl = null;
  const frames = [];
  const disposals = [];
  let loopCnt = 0;
  if (
    gif[0] === 0x47 &&
    gif[1] === 0x49 &&
    gif[2] === 0x46 && // 'GIF'
    gif[3] === 0x38 &&
    gif[4] === 0x39 &&
    gif[5] === 0x61
  ) {
    // '89a'
    pos += 13 + +!!(gif[10] & 0x80) * Math.pow(2, (gif[10] & 0x07) + 1) * 3;
    const gifHeader = gif.subarray(0, pos);
    while (gif[pos] && gif[pos] !== 0x3b) {
      const offset = pos,
        blockId = gif[pos];
      if (blockId === 0x21) {
        const label = gif[++pos];
        if ([0x01, 0xfe, 0xf9, 0xff].indexOf(label) !== -1) {
          label === 0xf9 && delayTimes.push((gif[pos + 3] + (gif[pos + 4] << 8)) * 10);
          label === 0xff && (loopCnt = gif[pos + 15] + (gif[pos + 16] << 8));
          while (gif[++pos]) pos += gif[pos];
          if (label === 0xf9) {
            graphicControl = gif.subarray(offset, pos + 1);
            disposals.push((graphicControl[3] >> 2) & 0x07);
          }
        } else {
          errorCB && errorCB("parseGIF: unknown label");
          break;
        }
      } else if (blockId === 0x2c) {
        pos += 9;
        pos += 1 + +!!(gif[pos] & 0x80) * (Math.pow(2, (gif[pos] & 0x07) + 1) * 3);
        while (gif[++pos]) pos += gif[pos];
        const imageData = gif.subarray(offset, pos + 1);
        frames.push(URL.createObjectURL(new Blob([gifHeader, graphicControl, imageData])));
      } else {
        errorCB && errorCB("parseGIF: unknown blockId");
        break;
      }
      pos++;
    }
  } else {
    errorCB && errorCB("parseGIF: no GIF89a");
  }
  successCB && successCB(delayTimes, loopCnt, frames, disposals);
};

self.onmessage = e => {
  parseGIF(
    new Uint8Array(e.data),
    (delays, loopcnt, frames, disposals) => {
      self.postMessage([true, frames, delays, disposals]);
      delete self.onmessage;
    },
    err => {
      console.error("Error in gif parsing worker", err);
      self.postMessage([false, err]);
      delete self.onmessage;
    }
  );
};