"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var ig_utilities_1 = require("@intelligentgraphics/ig.utilities");
var Math_1 = require("./Math");
var processContext;
var getContext = function () {
    if (processContext !== undefined) {
        return processContext;
    }
    try {
        var canvas = document.createElement("canvas");
        var ctx = canvas.getContext("2d");
        if (ctx !== null) {
            processContext = {
                canvas: canvas,
                ctx: ctx,
            };
            return processContext;
        }
    }
    catch (e) {
        console.error("IG.GFX.Core: ImageProcessing - no canvas or context", e);
    }
    processContext = null;
    return null;
};
/**
 * function to yield an Uint8Array from an image
 * @param image
 * @param callback processing function
 */
function extractImageData(image) {
    var context = getContext();
    if (context === null) {
        console.warn("IG.GFX.Core: ImageProcessing - image couldn't be processed");
        return null;
    }
    var canvas = context.canvas, ctx = context.ctx;
    canvas.width = image.width;
    canvas.height = image.height;
    ctx.drawImage(image, 0, 0);
    var imageData = ctx.getImageData(0, 0, image.width, image.height);
    return imageData;
}
exports.extractImageData = extractImageData;
/**
 * image processing wrapper function, giving the imageData into a callback
 * @param image
 * @param callback processing function
 */
function processImageData(image, callback) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var context, canvas, ctx, imageDataContainer, result;
        return tslib_1.__generator(this, function (_a) {
            context = getContext();
            if (context === null) {
                console.warn("IG.GFX.Core: ImageProcessing - image couldn't be processed");
                return [2 /*return*/, image];
            }
            canvas = context.canvas, ctx = context.ctx;
            imageDataContainer = extractImageData(image);
            if (ig_utilities_1.isNullOrUndefined(imageDataContainer)) {
                console.warn("IG.GFX.Core: ImageProcessing - imageData couldn't be extracted");
                return [2 /*return*/, image];
            }
            callback(imageDataContainer);
            ctx.putImageData(imageDataContainer, 0, 0);
            result = new Promise(function (resolve, reject) {
                var resultSrc = canvas.toDataURL();
                var img = new Image();
                img.width = image.width;
                img.height = image.height;
                img.onload = function (event) {
                    resolve(img);
                };
                img.src = resultSrc;
            });
            return [2 /*return*/, result];
        });
    });
}
exports.processImageData = processImageData;
function calculateMeanImageColor(image) {
    var imageData = extractImageData(image);
    var dataLength = imageData.data.length;
    var r = 0;
    var g = 0;
    var b = 0;
    for (var i = 0; i < dataLength; i += 4) {
        r += imageData[i] / dataLength; // red
        g += imageData[i + 1] / dataLength; // green
        b += imageData[i + 2] / dataLength; // blue
    }
    var result = Math_1.Vector.CreateVec3(r, g, b);
    return result;
}
exports.calculateMeanImageColor = calculateMeanImageColor;
/**
 * Try to recover height map from normal map
 * @param image
 * @param scale
 */
function convertNormalToHeightMap(image, scale) {
    if (scale === void 0) { scale = -2; }
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var result;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, processImageData(image, function (imageData) {
                        var width = imageData.width;
                        var height = imageData.height;
                        var dataLength = imageData.data.length;
                        var floatData = new Float32Array(4 * width * height);
                        var absoluteData = new Float32Array(4 * width * height);
                        for (var i = 0; i < dataLength; i++) {
                            floatData[i] = (imageData[i] - 128) / 128;
                        }
                        // normalize blue channel
                        var r;
                        var g;
                        var b;
                        var oldR;
                        for (var h = 0; h < width; h++) {
                            var row = h * height * 4;
                            oldR = 0; // red
                            for (var w = 1; w < height; w++) {
                                r = floatData[row + 4 * w]; // red
                                g = floatData[row + 4 * w + 1]; // green
                                b = floatData[row + 4 * w + 2]; // blue
                                b = Math.sqrt(1 - r * r - g * g);
                                r = r / Math.cos(g); // remove influence of y part of the normal
                                absoluteData[row + 4 * w] = (r - oldR) * scale; // red
                                absoluteData[row + 4 * w + 1] = (r - oldR) * scale; // green
                                absoluteData[row + 4 * w + 2] = (r - oldR) * scale; // blue
                                absoluteData[row + 4 * w + 3] = 1; // alpha
                                oldR = r;
                            }
                        }
                        for (var i = 0; i < dataLength; i++) {
                            imageData[i] = absoluteData[i] * 128 + 128;
                        }
                    })];
                case 1:
                    result = _a.sent();
                    return [2 /*return*/, result];
            }
        });
    });
}
exports.convertNormalToHeightMap = convertNormalToHeightMap;
/**
 * Ensure that r*r + g*g + b*b equals 1
 * @param image
 */
function normalizeBlueChannelOfNormalMap(image) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var result;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, processImageData(image, function (imageData) {
                        var dataLength = imageData.data.length;
                        // normalize blue channel
                        var r;
                        var g;
                        var b;
                        for (var i = 0; i < dataLength; i += 4) {
                            r = (imageData[i] - 128) / 128; // red
                            g = (imageData[i + 1] - 128) / 128; // green
                            b = (imageData[i + 2] - 128) / 128; // blue
                            b = Math.sqrt(1 - r * r - g * g);
                            imageData[i + 2] = Math.floor(b * 128) + 128;
                            // ensure alpha channel is full on
                            imageData[i + 3] = 255;
                        }
                    })];
                case 1:
                    result = _a.sent();
                    return [2 /*return*/, result];
            }
        });
    });
}
exports.normalizeBlueChannelOfNormalMap = normalizeBlueChannelOfNormalMap;
/**
 * Turn around all r, b and g values
 * @param image
 */
function invertColors(image) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var result;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, processImageData(image, function (imageData) {
                        var dataLength = imageData.data.length;
                        for (var i = 0; i < dataLength; i += 4) {
                            imageData[i] = 255 - imageData[i];
                            imageData[i + 1] = 255 - imageData[i + 1];
                            imageData[i + 2] = 255 - imageData[i + 2];
                        }
                    })];
                case 1:
                    result = _a.sent();
                    return [2 /*return*/, result];
            }
        });
    });
}
exports.invertColors = invertColors;
/**
 * Conversion function from data array to HTMLImage
 * @param input
 * @param width
 * @param height
 * @param inputHasAlphaChannel determines whether data can be used directly or the alpha channel needs tobe filled with values of 255
 */
function Uint8ArrayToImage(input, width, height, inputHasAlphaChannel) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var context, canvas, ctx, UAC, length_1, i, DAT, result;
        return tslib_1.__generator(this, function (_a) {
            context = getContext();
            if (context === null) {
                throw new Error("Can not generate image from uint8array, because no canvas could be created");
            }
            canvas = context.canvas, ctx = context.ctx;
            canvas.width = width;
            canvas.height = height;
            if (inputHasAlphaChannel) {
                UAC = new Uint8ClampedArray(input);
            }
            else {
                length_1 = width * height;
                UAC = new Uint8ClampedArray(length_1 * 4);
                for (i = 0; i < length_1; i++) {
                    UAC[i * 4] = input[i * 3];
                    UAC[i * 4 + 1] = input[i * 3 + 1];
                    UAC[i * 4 + 2] = input[i * 3 + 2];
                    UAC[i * 4 + 3] = 255;
                }
            }
            DAT = new ImageData(UAC, width, height);
            ctx.putImageData(DAT, 0, 0);
            result = new Promise(function (resolve, reject) {
                var content = canvas.toDataURL();
                var img = new Image();
                img.onload = function (event) {
                    resolve(img);
                };
                img.src = content;
            });
            return [2 /*return*/, result];
        });
    });
}
exports.Uint8ArrayToImage = Uint8ArrayToImage;
/**
 * Convenience function to get base64 data url from image
 * @param image
 * @param type
 * @param quality
 */
function getDataUrlFromImage(image, type, quality) {
    var context = getContext();
    if (context === null) {
        throw new Error("Can not get data url from image, because no canvas context could be created");
    }
    var canvas = context.canvas, ctx = context.ctx;
    canvas.width = image.width;
    canvas.height = image.height;
    ctx.drawImage(image, 0, 0);
    var result = canvas.toDataURL(type, quality);
    return result;
}
exports.getDataUrlFromImage = getDataUrlFromImage;
