"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AssetsGenerationService = void 0;
const Jimp = require("jimp");
const Color = require("color");
const decorators_1 = require("../../common/decorators");
const constants_1 = require("../../constants");
const _ = require("lodash");
const yok_1 = require("../../common/yok");
const os_1 = require("os");
class AssetsGenerationService {
    get propertiesToEnumerate() {
        return {
            icon: ["icons"],
            splash: ["splashBackgrounds", "splashCenterImages", "splashImages"],
        };
    }
    constructor($logger, $projectDataService, $fs, $options) {
        this.$logger = $logger;
        this.$projectDataService = $projectDataService;
        this.$fs = $fs;
        this.$options = $options;
    }
    generateIcons(resourceGenerationData) {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.$options.hostProjectPath) {
                return;
            }
            this.$logger.info("Generating icons ...");
            yield this.generateImagesForDefinitions(resourceGenerationData, this.propertiesToEnumerate.icon);
            this.$logger.info("Icons generation completed.");
        });
    }
    generateSplashScreens(splashesGenerationData) {
        return __awaiter(this, void 0, void 0, function* () {
            this.$logger.info("Generating splash screens ...");
            yield this.generateImagesForDefinitions(splashesGenerationData, this.propertiesToEnumerate.splash);
            this.$logger.info("Splash screens generation completed.");
        });
    }
    generateImagesForDefinitions(generationData, propertiesToEnumerate) {
        var _a, _b, _c, _d, _e, _f;
        return __awaiter(this, void 0, void 0, function* () {
            const background = generationData.background || "white";
            const assetsStructure = yield this.$projectDataService.getAssetsStructure(generationData);
            const assetItems = _(assetsStructure)
                .filter((assetGroup, platform) => !generationData.platform ||
                platform.toLowerCase() === generationData.platform.toLowerCase())
                .map((assetGroup) => _.filter(assetGroup, (assetSubGroup, imageTypeKey) => assetSubGroup && propertiesToEnumerate.indexOf(imageTypeKey) !== -1))
                .flatten()
                .map((assetSubGroup) => assetSubGroup.images)
                .flatten()
                .filter((assetItem) => !!assetItem.filename)
                .value();
            for (const assetItem of assetItems) {
                if (assetItem.operation === "delete") {
                    if (this.$fs.exists(assetItem.path)) {
                        this.$fs.deleteFile(assetItem.path);
                    }
                    continue;
                }
                if (assetItem.operation === "writeXMLColor") {
                    const colorName = (_a = assetItem.data) === null || _a === void 0 ? void 0 : _a.colorName;
                    if (!colorName) {
                        continue;
                    }
                    try {
                        const color = (_e = (_c = generationData[(_b = assetItem.data) === null || _b === void 0 ? void 0 : _b.fromKey]) !== null && _c !== void 0 ? _c : (_d = assetItem.data) === null || _d === void 0 ? void 0 : _d.default) !== null && _e !== void 0 ? _e : "white";
                        const colorHEX = Jimp.cssColorToHex(color);
                        const hex = (_f = colorHEX === null || colorHEX === void 0 ? void 0 : colorHEX.toString(16).substring(0, 6)) !== null && _f !== void 0 ? _f : "FFFFFF";
                        this.$fs.writeFile(assetItem.path, [
                            `<?xml version="1.0" encoding="utf-8"?>`,
                            `<resources>`,
                            `    <color name="${colorName}">#${hex.toUpperCase()}</color>`,
                            `</resources>`,
                        ].join(os_1.EOL));
                    }
                    catch (err) {
                        this.$logger.info(`Failed to write provided color to ${assetItem.path} -> ${colorName}. See --log trace for more info.`);
                        this.$logger.trace(err);
                    }
                    continue;
                }
                const operation = assetItem.resizeOperation || "resize" /* Operations.Resize */;
                let tempScale = null;
                if (assetItem.scale) {
                    if (_.isNumber(assetItem.scale)) {
                        tempScale = assetItem.scale;
                    }
                    else {
                        const splittedElements = `${assetItem.scale}`.split(constants_1.AssetConstants.sizeDelimiter);
                        tempScale =
                            splittedElements &&
                                splittedElements.length &&
                                splittedElements[0] &&
                                +splittedElements[0];
                    }
                }
                const scale = tempScale || constants_1.AssetConstants.defaultScale;
                const outputPath = assetItem.path;
                const width = assetItem.width * scale;
                const height = assetItem.height * scale;
                if (!width || !height) {
                    this.$logger.warn(`Image ${assetItem.filename} is skipped as its width and height are invalid.`);
                    continue;
                }
                let image;
                switch (operation) {
                    case "overlayWith" /* Operations.OverlayWith */:
                        const overlayImageScale = assetItem.overlayImageScale ||
                            constants_1.AssetConstants.defaultOverlayImageScale;
                        const imageResize = Math.round(Math.min(width, height) * overlayImageScale);
                        image = yield this.resize(generationData.imagePath, imageResize, imageResize);
                        image = this.generateImage(background, width, height, outputPath, image);
                        break;
                    case "blank" /* Operations.Blank */:
                        image = this.generateImage(background, width, height, outputPath);
                        break;
                    case "resize" /* Operations.Resize */:
                        image = yield this.resize(generationData.imagePath, width, height);
                        break;
                    case "outerScale" /* Operations.OuterScale */:
                        // Resize image without applying scale
                        image = yield this.resize(generationData.imagePath, assetItem.width, assetItem.height);
                        // The scale will apply to the underlying layer of the generated image
                        image = this.generateImage("#00000000", width, height, outputPath, image);
                        break;
                    default:
                        throw new Error(`Invalid image generation operation: ${operation}`);
                }
                // This code disables the alpha chanel, as some images for the Apple App Store must not have transparency.
                if (assetItem.rgba === false) {
                    //
                    // The original code here became broken at some time and there is an issue posted here..
                    //    https://github.com/oliver-moran/jimp/issues/954
                    // But NathanaelA recommended the below change and it works so maybe that's just what we go with.
                    //
                    // image = image.rgba(false);
                    image = image.colorType(2);
                }
                image.write(outputPath);
            }
        });
    }
    resize(imagePath, width, height) {
        return __awaiter(this, void 0, void 0, function* () {
            const image = yield Jimp.read(imagePath);
            return image.scaleToFit(width, height);
        });
    }
    generateImage(background, width, height, outputPath, overlayImage) {
        // Typescript declarations for Jimp are not updated to define the constructor with backgroundColor so we workaround it by casting it to <any> for this case only.
        const J = Jimp;
        const backgroundColor = this.getRgbaNumber(background);
        let image = new J(width, height, backgroundColor);
        if (overlayImage) {
            const centeredWidth = (width - overlayImage.bitmap.width) / 2;
            const centeredHeight = (height - overlayImage.bitmap.height) / 2;
            image = image.composite(overlayImage, centeredWidth, centeredHeight);
        }
        return image;
    }
    getRgbaNumber(colorString) {
        const color = new Color(colorString);
        const colorRgb = color.rgb();
        const alpha = Math.round(colorRgb.alpha() * 255);
        return Jimp.rgbaToInt(colorRgb.red(), colorRgb.green(), colorRgb.blue(), alpha);
    }
}
__decorate([
    (0, decorators_1.exported)("assetsGenerationService")
], AssetsGenerationService.prototype, "generateIcons", null);
__decorate([
    (0, decorators_1.exported)("assetsGenerationService")
], AssetsGenerationService.prototype, "generateSplashScreens", null);
exports.AssetsGenerationService = AssetsGenerationService;
yok_1.injector.register("assetsGenerationService", AssetsGenerationService);
//# sourceMappingURL=assets-generation-service.js.map