var fs = require("fs-extra");
var path = require("path");
var ghdownload = require('github-download');
var request = require('request');
var vcsurl = require('vcsurl');
var parseURL = require('url').parse;
var tmp = require('tmp');
var exec = require('child_process').exec;
var cwd = require('process').cwd();

var config = require('../config');

function checkDestination(destination) {
  return Promise.resolve()
    .then(() => {
      const contents = fs.readdirSync(destination);
      if (contents.length) {
        const err = "Something already exists at the destination. " +
                  "Without the --force parameter, `truffle init` and `truffle unbox` must be " +
                  "executed in an empty folder. Add the --force parameter to init or unbox " +
                  "to ignore existing files in the current directory and potentially overwrite them. " +
                  "Stopping to prevent overwriting data."
        throw new Error(err);
      }
  });
}

function verifyURL(url) {
  // Next let's see if the expected repository exists. If it doesn't, ghdownload
  // will fail spectacularly in a way we can't catch, so we have to do it ourselves.
  return new Promise(function(accept, reject) {

    var configURL = parseURL(
      vcsurl(url)
        .replace("github.com", "raw.githubusercontent.com")
        .replace(/#.*/, "") +
        "/master/truffle.js"
    );

    var options = {
      method: 'HEAD',
      uri: 'https://' + configURL.host + configURL.path
    };
    request(options, function(error, r) {
      if (error) {
        return reject(new Error(
          "Error making request to " + options.uri + ". Got error: " + error.message +
          ". Please check the format of the requested resource."
        ));
      } else if (r.statusCode == 404) {
        return reject(new Error("Truffle Box at URL " + url + " doesn't exist. If you believe this is an error, please contact Truffle support."));
      } else if (r.statusCode != 200) {
        return reject(new Error("Error connecting to github.com. Please check your internet connection and try again."));
      }
      accept();
    });
  });
}

function setupTempDirectory() {
  return new Promise(function(accept, reject) {
    tmp.dir({dir: cwd, unsafeCleanup: true}, function(err, dir, cleanupCallback) {
      if (err) return reject(err);

      accept(path.join(dir, "box"), cleanupCallback);
    });
  });
}

function fetchRepository(url, dir) {
  return new Promise(function(accept, reject) {
    // Download the package from github.
    ghdownload(url, dir)
      .on('err', function(err) {
        reject(err);
      })
      .on('end', function() {
        accept();
      });
  });
}

function copyTempIntoDestination(tmpDir, destination) {
  return new Promise(function(accept, reject) {
    fs.copy(tmpDir, destination, function(err) {
      if (err) return reject(err);
      accept();
    });
  });
}

function readBoxConfig(destination) {
  var possibleConfigs = [
    path.join(destination, "truffle-box.json"),
    path.join(destination, "truffle-init.json")
  ];

  var configPath = possibleConfigs.reduce(function(path, alt) {
    return path || fs.existsSync(alt) && alt;
  }, undefined);

  return config.read(configPath);
}

function cleanupUnpack(boxConfig, destination) {
  var needingRemoval = boxConfig.ignore || [];

  // remove box config file
  needingRemoval.push("truffle-box.json");
  needingRemoval.push("truffle-init.json");

  var promises = needingRemoval.map(function(file_path) {
    return path.join(destination, file_path);
  }).map(function(file_path) {
    return new Promise(function(accept, reject) {
      fs.remove(file_path, function(err) {
        if (err) return reject(err);
        accept();
      });
    });
  });

  return Promise.all(promises);
}

function installBoxDependencies(boxConfig, destination) {
  var postUnpack = boxConfig.hooks['post-unpack']

  return new Promise(function(accept, reject) {
    if (postUnpack.length === 0) {
      return accept();
    }

    exec(postUnpack, {cwd: destination}, function(err, stdout, stderr) {
      if (err) return reject(err);
      accept(stdout, stderr);
    });
  });
}

module.exports = {
  checkDestination: checkDestination,
  verifyURL: verifyURL,
  setupTempDirectory: setupTempDirectory,
  fetchRepository: fetchRepository,
  copyTempIntoDestination: copyTempIntoDestination,
  readBoxConfig: readBoxConfig,
  cleanupUnpack: cleanupUnpack,
  installBoxDependencies: installBoxDependencies
}

@@ -600,39 +600,8 @@
    %22
-Without the --force parameter, 
 %60tru
@@ -643,75 +643,148 @@
  be 
-%22 +%0A                  %22executed in an empty folder. Add 
+executed in an empty folder. %22 +%0A                  %22If you are absolutely sure you want to proceed, add %22 +%0A                  %22
 the 
+%60
 --force
+%60
  par
@@ -793,16 +793,20 @@
 eter to 
+the 
 init or 
@@ -811,39 +811,103 @@
 r unbox 
-%22 +%0A                  %22
+command. Be careful though, %22 +%0A                  %22adding %60--force%60 will cause truffle 
 to ignor
@@ -938,16 +938,39 @@
 current 
+%22 +%0A                  %22
 director
@@ -1003,39 +1003,16 @@
 e them. 
-%22 +%0A                  %22
 Stopping

Edit error message