/* CindyJS - (C) 2014-2016  The CindyJS Project
 * IFS rendering subcomponent licensed under the Apache License 2.0.
 * See https://github.com/CindyJS/CindyJS/tree/$gitid$/src/js/ifs
 * for corresponding sources.
 */
var nextInit = null;
var asm = null;
var buffer = null;
var imgPtr = null;
var imgData = null;
var width = 0;
var height = 0;
var Module = {};
var generation = null;

// check for imul support, and also for correctness
// ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
if (!Math.imul || Math.imul(0xffffffff, 5) !== -5)
    Math.imul = function imul(a, b) {
        var ah  = a >>> 16;
        var al = a & 0xffff;
        var bh  = b >>> 16;
        var bl = b & 0xffff;
        return (al*bl + ((ah*bl + al*bh) << 16))|0;
    };

onmessage = function(event) {
    var d = event.data;
    if (d.cmd === "init") {
        nextInit = d;
        if (generation === null) {
            next(d);
        }
    }
    if (d.cmd === "next")
        next(d);
}

function link() {
    asm = Module.asm(self, {
        _dbglog: function(i, d) {
            console.log(i, d);
        }
    }, buffer);
}

function init(d) {
    generation = d.generation;
    width = d.width;
    height = d.height;
    var n = d.trafos.length;
    var imgSize = width * height * 4;
    var trafoSize = (112 + 4) * n;
    if (trafoSize % 8) trafoSize += 8 - (trafoSize % 8);
    var bufferSize = 96 + trafoSize + imgSize;
    if (asm === null || buffer.byteLength < bufferSize) {
        buffer = new ArrayBuffer(bufferSize);
        link();
    }
    imgPtr = asm._init(n, width, height);
    if (bufferSize !== imgPtr + imgSize)
        throw Error("Buffer size calculation out of sync.");
    var imgBytes = new Uint8ClampedArray(buffer, imgPtr, imgSize);
    if (typeof imgBytes.fill === "function")
        imgBytes.fill(0); // clear image
    else for (var addr = 0; addr < imgBytes.length; ++addr)
        imgBytes[addr] = 0;
    imgData = new ImageData(imgBytes, width, height);
    for (var i = 0; i < n; ++i) {
        var tr = d.trafos[i];
        if (tr.kind === "Mt") {
            asm._setMoebius(
                i, tr.prob,
                tr.color[0] * 255,
                tr.color[1] * 255,
                tr.color[2] * 255,
                tr.moebius.sign,
                tr.moebius.ar,
                tr.moebius.ai,
                tr.moebius.br,
                tr.moebius.bi,
                tr.moebius.cr,
                tr.moebius.ci,
                tr.moebius.dr,
                tr.moebius.di);
        }
    }
    asm._real(1000, 1);
}

function next(d) {
    if (d.buffer) {
        buffer = d.buffer;
        link();
        imgData = null; // won't be needing this
    }
    if (nextInit) {
        init(nextInit);
        nextInit = null;
    }
    asm._real(1e5, 0);
    if (typeof createImageBitmap === "function") {
        createImageBitmap(imgData).then(function(bmp) {
            postMessage({
                generation: generation,
                img: bmp
            }, [bmp]);
        });
    } else {
        postMessage({
            generation: generation,
            buffer: buffer,
            imgPtr: imgPtr,
            width: width,
            height: height
        }, [buffer]);
    }
}

// Code below was generated by emscripten, see ifs.cc for source code

@@ -1228,24 +1228,48 @@
 fos.length;%0A
+    var fixedSize = 96;%0A
     var imgS
@@ -1294,16 +1294,16 @@
 ht * 4;%0A
-
     var 
@@ -1398,23 +1398,27 @@
 var 
-buffer
+min
 Size = 
-96
+fixedSize
  + t
@@ -1437,16 +1437,105 @@
 mgSize;%0A
+    var bufferSize = 1 %3C%3C 16;%0A    while (bufferSize %3C minSize)%0A        bufferSize %3C%3C= 1;%0A
     if (
@@ -1706,35 +1706,36 @@
 if (
-bufferSize !== imgPtr + img
+imgPtr !== fixedSize + trafo
 Size

Make IFS buffer size a power of two