/*!
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
*/

const fs = require('fs-extra');
const path = require('path');
const { ConfigParser, events } = require('cordova-common');
const platformAdd = require('../src/cordova/platform').add;
const HooksRunner = require('../src/hooks/HooksRunner');

/**
 * Creates a function that provides access to various fixtures by name.
 *
 * @param {Function} tmpDir creates a temp dir when called and returns its path
 * @returns {Function} that provides access to various fixtures by name
 */
module.exports = function fixtureHelper (tmpDir) {
    let fixturesBaseDir;

    // Setup and teardown the directory where we setup our fixtures
    beforeAll(() => { fixturesBaseDir = tmpDir(); });
    afterAll(() => fs.removeSync(fixturesBaseDir));

    // The recipes for building the different kinds of fixture.
    // Resolve to the fixture path.
    const fixtureConstructors = {
        // Creates a stand-alone cordova-android app (platform-centered)
        androidApp () {
            const PlatformApi = require('cordova-android');
            const appPath = path.join(fixturesBaseDir, 'android-app');

            // We need to provide a ConfigParser instance to createPlatform :(
            const cfgXmlPath = require.resolve('cordova-android/bin/templates/project/res/xml/config.xml');
            const config = new ConfigParser(cfgXmlPath);

            // Create the app folder and return its path
            return PlatformApi.createPlatform(appPath, config, null, events)
                // Make our node_modules accessible from the app dir to make
                // platform modules work when they are required from the app dir.
                .then(_ => linkToGlobalModulesFrom(appPath))
                .then(_ => appPath);
        },

        // Creates a cordova project with one platform installed
        projectWithPlatform () {
            const projectFixture = path.join(__dirname, 'cordova/fixtures/basePkgJson');
            const projectPath = path.join(fixturesBaseDir, 'project-with-platform');

            return fs.copy(projectFixture, projectPath)
                .then(_ => process.chdir(projectPath))
                .then(_ => {
                    // Talk about a clunky interface :(
                    const platforms = ['android'];
                    const opts = { platforms, save: true };
                    const hooksRunner = new HooksRunner(projectPath);
                    return platformAdd(hooksRunner, projectPath, platforms, opts);
                })
                .then(_ => projectPath);
        },

        androidPlatform () {
            return path.dirname(require.resolve('cordova-android/package'));
        }
    };

    // The fixture cache; contains promises to paths of already created fixtures
    const fixturePromises = {};

    // Finally, the public interface we provide our consumers. We intentionally
    // provide only a method to copy the fixtures, so that tests cannot alter
    // the global fixtures in any way.
    return function getFixture (name) {
        if (!(name in fixturePromises)) {
            fixturePromises[name] = Promise.resolve(fixtureConstructors[name]());
        }
        return {
            copyTo (targetPath) {
                return fixturePromises[name]
                    .then(fixturePath => fs.copy(fixturePath, targetPath))
                    .then(_ => targetPath);
            }
        };
    };
};

function linkToGlobalModulesFrom (dir) {
    return fs.symlink(
        path.join(__dirname, '../node_modules'),
        path.join(dir, 'node_modules'),
        'junction'
    );
}

@@ -2621,16 +2621,22 @@
         
+async 
 projectW
@@ -2644,32 +2644,32 @@
 thPlatform () %7B%0A
-
             cons
@@ -2843,22 +2843,19 @@
     
-return 
 fs.copy
+Sync
 (pro
@@ -2879,16 +2879,17 @@
 ectPath)
+;
 %0A       
@@ -2888,39 +2888,24 @@
 %0A           
-     .then(_ =%3E
  process.chd
@@ -2923,47 +2923,11 @@
 ath)
-)%0A                .then(_ =%3E %7B%0A        
+;%0A%0A
     
@@ -2978,32 +2978,24 @@
             
-      
-  
 const platfo
@@ -3013,24 +3013,16 @@
 roid'%5D;%0A
-        
         
@@ -3065,24 +3065,16 @@
 true %7D;%0A
-        
         
@@ -3139,30 +3139,21 @@
         
-        return
+await
  platfor
@@ -3205,53 +3205,27 @@
 s);%0A
-                %7D)%0A                .then(_ =%3E
+%0A            return
  pro
@@ -3224,33 +3224,32 @@
 turn projectPath
-)
 ;%0A        %7D,%0A%0A  
@@ -3884,16 +3884,22 @@
         
+async 
 copyTo (
@@ -3928,22 +3928,41 @@
         
-return
+const fixturePath = await
  fixture
@@ -3975,20 +3975,18 @@
 es%5Bname%5D
+;
 %0A
-   
         
@@ -3996,38 +3996,16 @@
     
-  .then(fixturePath =%3E
  fs.copy
 (fix
@@ -4000,16 +4000,20 @@
  fs.copy
+Sync
 (fixture
@@ -4025,25 +4025,25 @@
  targetPath)
-)
+;
 %0A           
@@ -4047,30 +4047,22 @@
         
-    .then(_ =%3E
+return
  targetP
@@ -4056,33 +4056,32 @@
 eturn targetPath
-)
 ;%0A            %7D%0A

use fs.copySync for increased performance (#826)