/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * ___________________
 *
 *  Copyright 2020 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/

const child_process = require('child_process');
const xml2js = require('xml2js');
const VulcanControlLib = require('../build/Release/VulcanControlLib.node').VulcanControlAdapter;
const parser = new xml2js.Parser({ async: false, explicitArray: false });
const opn = require('opn');

class VulcanControlAdapter extends VulcanControlLib {
    getInstalledApps(topLevelOnly = true, onlyVisibleProducts = true) {
        let json;
        parser.parseString(this._getInstalledApps(topLevelOnly), (err, result) => {
            if (err) {
                throw err;
            }
            json = result;
        });

        return json.ProductsInfo.ProductInfo
            .filter(({ IsVisibleProduct }) => !onlyVisibleProducts || IsVisibleProduct === 'true')
            .map(({ SAPCode, CodexVersion, BuildVersion, LaunchString }) => ({ SAPCode, CodexVersion, BuildVersion, LaunchString }));
    }

    isAppInstalled(sapCode) {
        return this.getInstalledApps(false, false).some(({ SAPCode }) => sapCode === SAPCode);
    }

    getAppDetails(sapCode) {
        return this.getInstalledApps(false, false).filter(({ SAPCode }) => sapCode === SAPCode);
    }

    launchApp(sapCode, setFocus, cmdLineArgs) {
        // NOTE: `sapCode` actually contains the app specifier, not the SAP code
        if (sapCode && sapCode.startsWith('SPRK')) {
            const index = sapCode.indexOf('-');
            const realSAPCode = index !== -1 ? sapCode.slice(0, sapCode.indexOf('-')) : sapCode;
            const appDetails = this.getAppDetails(realSAPCode)[0];
            const LaunchString = process.platform === 'darwin' ? 'adbxd:' : appDetails.LaunchString;
            opn(`${LaunchString}//${cmdLineArgs || ''}`);
            return Promise.resolve(true);
        }
        return new Promise((resolve, reject) => {
            this._launchApp(sapCode, setFocus, cmdLineArgs, (err, status) => {
                if (err) {
                    return reject(err);
                }
                resolve(status);
            });
        });
    }

    _getXDDetails() {
        // There can be up to 3 copies of XD running in parallel: public, private and dev
        const cmdToRun = 'tasklist /fo csv /fi "IMAGENAME eq XD*" /nh';
        let result = child_process.execSync(cmdToRun);
        if (result instanceof Buffer) {
            result = result.toString();
        }
        return result.split(`\r\n`)
            .map(build => build.split(',')
                .slice(0,2)
                .map(val => val.slice(1, -1)))
            .filter(build => build[0] !== '');
    }

    isAppRunning(sapCode) {
        // Vulcan doesn't support UWP apps as of now - so return whether we got a valid process id
        if (process.platform !== 'darwin' && sapCode && sapCode.startsWith('SPRK')) {
            return this.getProcessId(sapCode) !== 0;
        }
        return this._isAppRunning(sapCode);
    }

    getProcessId(sapCode) {
        // Vulcan doesn't support UWP apps as of now, putting in this workaround
        // to get information by running tasklist command on windows.
        if (process.platform !== 'darwin' && sapCode && sapCode.startsWith('SPRK')) {
            const runningBuilds = this._getXDDetails();
            const targetBuild = {
                SPRK: 'XD.exe',
                SPRKDV: 'XD (Dev).exe',
                SPRKPR: 'XD (Prerelease).exe'
            }[sapCode];
            for (const index in runningBuilds) {
                if (runningBuilds[index][0] === targetBuild) {
                    return parseInt(runningBuilds[index][1]);
                }
            }
            return 0;
        }
        return this._getProcessId(sapCode);
    }
}

module.exports = VulcanControlAdapter;
