var childProcess = require('child_process');
var spawn = require('spawn-cmd').spawn;
var Promise = require('./promise');

// Execute a command
function exec(command, options) {
    var d = Promise.defer();

    var child = childProcess.exec(command, options, function(err, stdout, stderr) {
        if (!err) {
            return d.resolve();
        }

        err.message = stdout.toString('utf8') + stderr.toString('utf8');
        d.reject(err);
    });

    child.stdout.on('data', function (data) {
        d.notify(data);
    });

    child.stderr.on('data', function (data) {
        d.notify(data);
    });

    return d.promise;
}

// Spawn an executable
function spawnCmd(command, args, options) {
    var d = Promise.defer();
    var child = spawn(command, args, options);

    child.on('error', function(error) {
        return d.reject(error);
    });

    child.stdout.on('data', function (data) {
        d.notify(data);
    });

    child.stderr.on('data', function (data) {
        d.notify(data);
    });

    child.on('close', function(code) {
        if (code === 0) {
            d.resolve();
        } else {
            d.reject(new Error('Error with command "'+command+'"'));
        }
    });

    return d.promise;
}

// Transform an option object to a command line string
function escapeShellArg(s) {
    s = s.replace(/"/g, '\\"');
    return '"' + s + '"';
}

function optionsToShellArgs(options) {
    var result = [];

    for (var key in options) {
        var value = options[key];

        if (value === null || value === undefined || value === false) {
            continue;
        }
        if (value === true) {
            result.push(key);
        }

        result.push(key + '=' + escapeShellArg(value));
    }

    return result.join(' ');
}

module.exports = {
    exec: exec,
    spawn: spawnCmd,
    optionsToShellArgs: optionsToShellArgs
};

@@ -1,16 +1,40 @@
+var is = require('is');%0A
 var childProcess
@@ -1263,17 +1263,22 @@
 se;%0A%7D%0A%0A/
-/
+**%0A   
  Transfo
@@ -1321,16 +1321,73 @@
 e string
+%0A%0A    @param %7BString%7Cnumber%7D value%0A    @param %7BString%7D%0A*/
 %0Afunctio
@@ -1403,25 +1403,29 @@
 hellArg(
-s
+value
 ) %7B%0A    
 s = s.re
@@ -1420,13 +1420,105 @@
     
-s = s
+if (is.number(value)) %7B%0A        return value;%0A    %7D%0A%0A    value = String(value);%0A    value = value
 .rep
@@ -1532,24 +1532,25 @@
 /g, '%5C%5C%22');%0A
+%0A
     return '
@@ -1554,17 +1554,21 @@
 n '%22' + 
-s
+value
  + '%22';%0A
@@ -1570,16 +1570,141 @@
 '%22';%0A%7D%0A%0A
+/**%0A    Transform a map of options into a command line arguments string%0A%0A    @param %7BObject%7D options%0A    @return %7BString%7D%0A*/%0A
 function
@@ -1922,24 +1922,25 @@
 ;%0A        %7D%0A
+%0A
         if (
@@ -1943,22 +1943,22 @@
 if (
-value === true
+is.bool(value)
 ) %7B%0A
@@ -1988,34 +1988,44 @@
 (key);%0A        %7D
-%0A%0A
+ else %7B%0A    
         result.p
@@ -2060,24 +2060,34 @@
 rg(value));%0A
+        %7D%0A
     %7D%0A%0A    r

Fix escaping of ebook-convert options