"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) {
    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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const chalk = require("chalk");
const cli_utils_1 = require("@ionic/cli-utils");
const setup_1 = require("../lib/utils/setup");
const configXmlUtils_1 = require("../lib/utils/configXmlUtils");
const resources_1 = require("../lib/resources");
/*
const RESOURCES_SUMMARY =
`Automatically create icon and splash screen resources.
Put your images in the ./resources directory, named splash or icon.
Accepted file types are .png, .ai, and .psd.
Icons should be 192x192 px without rounded corners.
Splashscreens should be 2732x2732 px, with the image centered in the middle.
`;
*/
const AVAILABLE_RESOURCE_TYPES = ['icon', 'splash'];
let ResourcesCommand = class ResourcesCommand extends cli_utils_1.Command {
    preRun(inputs, options) {
        return __awaiter(this, void 0, void 0, function* () {
            const isLoggedIn = yield this.env.session.isLoggedIn();
            if (!isLoggedIn) {
                this.env.log.msg(`You need to be logged into your Ionic account in order to run the ${chalk.bold(`cordova:resources`)} command.\n`);
                yield cli_utils_1.promptToLogin(this.env.log, this.env.session);
            }
        });
    }
    run(inputs, options) {
        return __awaiter(this, void 0, void 0, function* () {
            // if no resource filters are passed as arguments assume to use all.
            let resourceTypes = AVAILABLE_RESOURCE_TYPES.filter((type, index, array) => options[type]);
            resourceTypes = (resourceTypes.length) ? resourceTypes : AVAILABLE_RESOURCE_TYPES;
            const resourceDir = path.join(this.env.project.directory, 'resources');
            let configFileContents;
            var tasks = new cli_utils_1.TaskChain();
            tasks.next(`Collecting resource configuration and source images`);
            /**
             * check that config file config.xml exists
             */
            try {
                configFileContents = yield configXmlUtils_1.parseConfigXmlToJson(this.env.project.directory);
            }
            catch (e) {
                throw e;
            }
            const resourceJsonStructure = yield resources_1.getResourceConfigJson();
            this.env.log.debug(`resourceJsonStructure=${Object.keys(resourceJsonStructure).length}`);
            /**
             * check that at least one platform has been installed
             */
            const platformDirContents = yield setup_1.getProjectPlatforms(this.env.project.directory);
            const buildPlatforms = Object.keys(resourceJsonStructure)
                .filter(platform => platformDirContents.includes(platform));
            if (buildPlatforms.length === 0) {
                throw `No platforms have been added. Please run: ${chalk.green('ionic cordova:platform add')}`;
            }
            this.env.log.debug(`${chalk.green('getProjectPlatforms')} completed - length=${buildPlatforms.length}`);
            /**
             * Convert the resource structure to a flat array then filter the array
             * so that it only has img resources that we need. Finally add src path to the
             * items that remain.
             */
            let imgResources = resources_1.flattenResourceJsonStructure(resourceJsonStructure)
                .filter((img) => buildPlatforms.includes(img.platform))
                .filter((img) => resourceTypes.includes(img.resType))
                .map((img) => (Object.assign({}, img, { dest: path.join(resourceDir, img.platform, img.resType, img.name) })));
            this.env.log.debug(`imgResources=${imgResources.length}`);
            /**
             * Create the resource directories that are needed for the images we will create
             */
            try {
                const buildDirResponses = yield resources_1.createImgDestinationDirectories(imgResources);
                this.env.log.debug(`${chalk.green('createImgDestinationDirectories')} completed - length=${buildDirResponses.length}`);
            }
            catch (e) {
                throw e;
            }
            /**
             * Check /resources and /resources/<platform> directories for src files
             * Update imgResources to have their src attributes to equal the most speficic src img found
             */
            let srcImagesAvailable = [];
            try {
                srcImagesAvailable = yield resources_1.getSourceImages(buildPlatforms, resourceTypes, resourceDir);
                this.env.log.debug(`${chalk.green('getSourceImages')} completed - ${srcImagesAvailable.length}`);
            }
            catch (e) {
            }
            imgResources = imgResources.map((imageResource) => {
                const mostSpecificImageAvailable = resources_1.findMostSpecificImage(imageResource, srcImagesAvailable);
                return Object.assign({}, imageResource, { imageId: mostSpecificImageAvailable ? mostSpecificImageAvailable.imageId : null });
            });
            /**
             * If there are any imgResources that have missing images then end processing and inform the user
             */
            const missingSrcImages = imgResources.filter((imageResource) => imageResource.imageId === null);
            if (missingSrcImages.length > 0) {
                const missingImageText = missingSrcImages
                    .reduce((list, img) => {
                    let str = `${img.resType}/${img.platform}`;
                    if (list.includes(str)) {
                        list.push(str);
                    }
                    return list;
                }, [])
                    .join('\n');
                throw new Error(`Source image files were not found for the following platforms/types: \n${missingImageText}`);
            }
            tasks.next(`Uploading source images to prepare for transformations`);
            /**
             * Upload images to service to prepare for resource transformations
             */
            let imageUploadResponses;
            try {
                imageUploadResponses = yield resources_1.uploadSourceImages(srcImagesAvailable);
                this.env.log.debug(`${chalk.green('uploadSourceImages')} completed - responses=${JSON.stringify(imageUploadResponses, null, 2)}`);
            }
            catch (e) {
                throw e;
            }
            srcImagesAvailable = srcImagesAvailable.map((img, index) => {
                return Object.assign({}, img, { width: imageUploadResponses[index].Width, height: imageUploadResponses[index].Height, vector: imageUploadResponses[index].Vector });
            });
            /**
             * If any images are asking to be generated but are not of the correct size inform the user and continue on.
             */
            const imagesTooLargeForSource = imgResources.filter((imageResource) => {
                const resourceSourceImage = srcImagesAvailable.find(srcImage => srcImage.imageId === imageResource.imageId);
                if (resourceSourceImage === undefined) {
                    return true;
                }
                return !resourceSourceImage.vector &&
                    (imageResource.width > resourceSourceImage.width || imageResource.height > resourceSourceImage.height);
            });
            /**
             * Remove all images too large for transformations
             */
            imgResources = imgResources.filter(imageResource => {
                return !imagesTooLargeForSource.find(tooLargeForSourceImage => imageResource.name === tooLargeForSourceImage.name);
            });
            /**
             * Call the transform service and output images to appropriate destination
             */
            tasks.next(`Generating platform resources`);
            let count = 0;
            const promiseList = imgResources.map((img, index) => {
                return resources_1.transformResourceImage(img).then(() => {
                    count += 1;
                    tasks.updateMsg(`Generating platform resources: ${chalk.bold(`${count} / ${imgResources.length}`)} complete`);
                });
            });
            try {
                const generateImageResponses = yield Promise.all(promiseList);
                tasks.updateMsg(`Generating platform resources: ${chalk.bold(`${imgResources.length} / ${imgResources.length}`)} complete`);
                this.env.log.debug(`${chalk.green('generateResourceImage')} completed - responses=${JSON.stringify(generateImageResponses, null, 2)}`);
            }
            catch (e) {
                throw e;
            }
            // TODO: UPDATE CONFIG.XML DATA
            tasks.next(`Modifying config.xml to add new image resources`);
            const imageResourcesForConfig = imgResources.reduce((rc, img) => {
                if (!rc[img.platform]) {
                    rc[img.platform] = {
                        [img.resType]: {
                            images: [],
                            nodeName: '',
                            nodeAttributes: []
                        }
                    };
                }
                if (!rc[img.platform][img.resType]) {
                    rc[img.platform][img.resType] = {
                        images: [],
                        nodeName: '',
                        nodeAttributes: []
                    };
                }
                rc[img.platform][img.resType].images.push({
                    name: img.name,
                    width: img.width,
                    height: img.height,
                    density: img.density || null
                });
                rc[img.platform][img.resType].nodeName = img.nodeName;
                rc[img.platform][img.resType].nodeAttributes = img.nodeAttributes;
                return rc;
            }, {});
            const platformList = Object
                .keys(imageResourcesForConfig)
                .map(pn => pn);
            try {
                yield resources_1.addResourcesToConfigXml(this.env.project.directory, platformList, imageResourcesForConfig);
            }
            catch (e) {
                throw e;
            }
            tasks.end();
            /**
             * Print out all images that were not processed
             */
            this.env.log.msg(imagesTooLargeForSource.map(imageResource => (`    ${chalk.bold(imageResource.name)}     ${imageResource.platform}/${imageResource.resType} needed ${imageResource.width}w x ${imageResource.height}h`))
                .concat((imagesTooLargeForSource.length > 0) ? `\nThe following images were not created because their source image was too small:` : [])
                .reverse()
                .join('\n'));
        });
    }
};
ResourcesCommand = __decorate([
    cli_utils_1.CommandMetadata({
        name: 'resources',
        description: 'Automatically create icon and splash screen resources',
        exampleCommands: [''],
        options: [
            {
                name: 'icon',
                description: 'Generate icon resources',
                type: Boolean,
                aliases: ['i']
            },
            {
                name: 'splash',
                description: 'Generate splash screen resources',
                type: Boolean,
                aliases: ['s']
            }
        ]
    })
], ResourcesCommand);
exports.ResourcesCommand = ResourcesCommand;
