var createContextBackground = (function() {
    var canvas = document.createElement("canvas")
        ,ctx = canvas.getContext('2d')
        /** @const */
        ,WIDTH = canvas.width = 250
        /** @const */
        ,HEIGHT = canvas.height = 290
        /** @const */
        ,MARGIN = 20
        /** @const */
        ,NB_ITEM = 3
        /** @const */
        ,ITEM_SIZE = (WIDTH -2*MARGIN) / NB_ITEM
        /** @const */
        ,ITEM_SPACING = 0.1 * ITEM_SIZE
        /** @const */
        ,ITEM_INNER_SIZE = Math.floor(ITEM_SIZE -(ITEM_SPACING*2))
        /** @const */
        ,AVATAR_SIZE = ITEM_INNER_SIZE * 0.5
        ,RESULT;

    var drawItem = function(background, avatar, x0, y0) {
        var y0Index = Math.floor(y0)
            ,y1Index = Math.floor(y0 + ITEM_SIZE)
            ,topColor = [
                 background.data[y0Index *WIDTH *4 +0]
                ,background.data[y0Index *WIDTH *4 +1]
                ,background.data[y0Index *WIDTH *4 +2]
            ]
            ,botColor = [
                 background.data[y1Index *WIDTH *4 +0]
                ,background.data[y1Index *WIDTH *4 +1]
                ,background.data[y1Index *WIDTH *4 +2]
            ]
            ,targetPcent = 1.1
            ,targetColor = (((topColor[0] *targetPcent) << 16) |
                ((topColor[1] *targetPcent) << 8) |
                (topColor[2] *targetPcent)).toString(16);

        ctx.fillStyle = '#' +targetColor;
        ctx.beginPath();
        ctx.moveTo(x0 +ITEM_SIZE /2, y0 +ITEM_SPACING);
        ctx.lineTo(x0 -ITEM_SPACING +ITEM_SIZE, y0 +ITEM_SIZE /2);
        ctx.lineTo(x0 +ITEM_SIZE /2, y0 -ITEM_SPACING +ITEM_SIZE);
        ctx.lineTo(x0 +ITEM_SPACING, y0 +ITEM_SIZE /2);
        ctx.closePath();
        ctx.fill();

        ctx.putImageData(
            blend(
                ctx.getImageData(
                    x0 +ITEM_SPACING,
                    y0 +ITEM_SPACING,
                    ITEM_INNER_SIZE,
                    ITEM_INNER_SIZE),
                avatar),
            x0 +ITEM_SPACING,
            y0 +ITEM_SPACING);
    };

    var blend = function(img, img2) {
        var margin = (img.height -img2.height) /2;
        for (var i =0; i < img2.height; i++)
            for (var j =0; j < img2.width; j++) {
                var img2Grey = (img2.data[(i *img2.width +j) *4]) / 255
                    ,iImg = ((i +margin) *img.width +j +margin) *4;

                img.data[iImg] *= img2Grey;
                img.data[iImg +1] *= img2Grey;
                img.data[iImg +2] *= img2Grey;
            }
        return img;
    }

    var drawBackground = function() {
        var grd = ctx.createLinearGradient(0, 0, 0, HEIGHT);
        grd.addColorStop(0, "#4D394B");
        grd.addColorStop(1, "#201820");
        ctx.fillStyle = grd;
        ctx.fillRect(0, 0, WIDTH, HEIGHT);
        return ctx.getImageData(0, 0, WIDTH, HEIGHT)
    };

    var filterImage = function(img) {
        var pixelSum = 0;
        for (var i =0; i < img.width *img.height *4; i +=4) {
            img.data[i] = img.data[i +1] = img.data[i +2] = (img.data[i] +img.data[i +1] +img.data[i +2]) / 3;
            img.data[i +3] = 50;
            pixelSum += img.data[i];
        }

        // Invert colors if image is dark
        if (pixelSum / (img.height * img.width) < 50)
            for (var i =0; i < img.width *img.height *4; i +=4)
                img.data[i] = img.data[i +1] = img.data[i +2] = 255 - img.data[i];

        return img;
    }

    var loadImgFromUrl = function(src, cb) {
        var xhr = new XMLHttpRequest();
        xhr.responseType = 'blob';
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) {
                if (xhr.response) {
                    var img = new Image();
                    img.onload = function() {
                        var imgCanvas = document.createElement("canvas");

                        imgCanvas.height = imgCanvas.width = AVATAR_SIZE;
                        var imgCtx = imgCanvas.getContext('2d');

                        imgCtx.drawImage(img, 0, 0, AVATAR_SIZE, AVATAR_SIZE);
                        cb(filterImage(imgCtx.getImageData(0, 0, AVATAR_SIZE, AVATAR_SIZE)));
                    };
                    img.onerror = function() {
                        cb(null);
                    };
                    img.src = window.URL.createObjectURL(/** @type {Blob!} */ (xhr.response));
                } else {
                    cb(null);
                }
            }
        };
        xhr.open('GET', src, true);
        xhr.send(null);
    };

    var loadImages = function(userImgs, doneImgLoading) {
        for (var i =0, nbImgs = userImgs.length; i < nbImgs; i++) {
            if (userImgs[i].img === undefined) {
                // Do load image
                loadImgFromUrl(userImgs[i].src, function(img) {
                    userImgs[i].img = img;
                    loadImages(userImgs, doneImgLoading);
                });
                return;
            }
        }
        var imgs = [];
        userImgs.forEach(function(i) {
            if (i.img)
                imgs.push(i.img);
        });
        doneImgLoading(imgs);
    };

    var renderAvatars = function(background, imgs) {
        imgs.sort(function(a, b) {
            return Math.random() - 0.5;
        });
        for (var imgIndex =0, i =MARGIN; i < WIDTH -MARGIN*2; i += ITEM_SIZE)
            for (var j =0; j +ITEM_SIZE <= HEIGHT; j += ITEM_SIZE) {
                drawItem(background, imgs[imgIndex], i, j);
                imgIndex++;
                if (imgIndex === imgs.length) {
                    imgs.sort(function(a, b) {
                        if (!a.img)
                            return 1;
                        if (!b.img)
                            return -1;
                        return Math.random() - 0.5;
                    });
                    imgIndex = 0;
                }
            }
    }

    return function(cb) {
        if (RESULT) {
            cb(RESULT);
        } else {
            var background = drawBackground()
                ,userImgs = [];

            for (var userId in SLACK.context.users) {
                if (!SLACK.context.users[userId].deleted)
                    userImgs.push({
                        src: "api/avatar?user=" +userId
                    });
            }

            loadImages(userImgs, function(imgs) {
                renderAvatars(background, imgs);
                RESULT = canvas.toDataURL();
                cb(RESULT);
            });
        }
    }
})();

