/**
 * Module dependencies
 */

var path = require('path'),
    fs = require('fs'),
    async = require('async'),
    install = require('./install'),
    utils = require('../utils'),
    rimraf = require('rimraf'),
    settings = require('../settings'),
    project = require('../project'),
    tree = require('../tree');
    logger = require('../logger'),
    argParse = require('../args').parse,
    _ = require('underscore/underscore')._;


/**
 * Usage information and docs
 */

exports.summary = 'Removes unused packages from the package directory';


exports.usage = '' +
'jam clean [PATH]\n' +
'\n' +
'Parameters:\n' +
'  PATH    Optional project directory to read dependencies from\n' +
'          (defaults to ".")\n' +
'\n' +
'Options:\n' +
'  --package-dir  Package directory (defaults to "PATH/jam")';


/**
 * Run function called when "jam clean" command is used
 *
 * @param {Object} settings - the values from .jamrc files
 * @param {Array} args - command-line arguments
 */

exports.run = function (settings, args) {
    var a = argParse(args, {
        'target_dir': {match: '--package-dir', value: true}
    });

    var opt = a.options;
    var dir = a.positional[0] || '.';

    opt.target_dir = opt.target_dir || path.resolve(dir, 'jam');
    exports.clean(dir, opt, function (err) {
        if (err) {
            return logger.error(err);
        }
        logger.end();
    });
};


/**
 * Clean the project directory's dependencies.
 *
 * @param {Array} dir - path to project dir
 * @param {Object} opt - the options object
 * @param {Function} callback
 */

exports.clean = function (dir, opt, callback) {
    exports.unusedDirs(dir, opt, function (err, dirs) {
        if (err) {
            return callback(err);
        }
        if (!dirs.length) {
            // nothing to remove
            return logger.end();
        }
        var reldirs = dirs.map(function (d) {
            return path.relative(dir, d);
        });
        console.log(
            '\n' +
            'The following directories will be REMOVED:\n' +
            '    ' + reldirs.join('\n    ') +
            '\n'
        );
        utils.getConfirmation('Continue', function (err, ok) {
            if (err) {
                return callback(err);
            }
            if (ok) {
                exports.deleteDirs(dirs, function (err) {
                    if (err) {
                        return logger.error(err);
                    }
                    console.log('');
                    logger.end();
                });
            }
            else {
                logger.clean_exit = true;
            }
        });
    });
};


/**
 * Delete multiple directory paths.
 *
 * @param {Array} dirs
 * @param {Function} callback
 */

exports.deleteDirs = function (dirs, callback) {
    async.forEach(dirs, function (d, cb) {
        rimraf(d, cb);
    },
    callback);
};


/**
 * Discover package directories that do not form part of the current
 * package version tree.
 *
 * @param {String} dir - the root package dir
 * @param {Object} opt - the options object
 * @param {Function} callback
 */

exports.unusedDirs = function (dir, opt, callback) {
    project.load(dir, function (err, cfg) {
        if (err) {
            return callback(err);
        }
        var sources = [
            install.dirSource(opt.target_dir)
        ];
        var newcfg = _.extend({name: '_root'}, cfg);
        var pkg = {
            config: newcfg,
            source: 'root'
        };
        logger.info('Building version tree...');
        tree.build(pkg, sources, function (err, packages) {
            if (err) {
                return callback(err);
            }
            return exports.unusedDirsTree(packages, opt, callback);
        });
    });
};


/**
 * Lists packages in the package dir and compares against the provided
 * version tree, returning the packages not in the tree.
 *
 * @param {Object} packages - version tree
 * @param {Object} opt - options object
 * @param {Function} callback
 */

exports.unusedDirsTree = function (packages, opt, callback) {
    exports.listDirs(opt.target_dir, function (err, dirs) {
        if (err) {
            return callback(err);
        }
        var unused = _.difference(dirs, Object.keys(packages));
        var unused = [];
        var names = Object.keys(packages);
        dirs.forEach(function (d) {
            if (!_.contains(names, path.basename(d))) {
                unused.push(d);
            }
        });
        return callback(null, unused);
    });
};


/**
 * List directories within a directory. Filters out regular files etc.
 *
 * @param {String} dir
 * @param {Function} callback
 */

exports.listDirs = function (dir, callback) {
    fs.readdir(dir, function (err, files) {
        if (err) {
            return callback(err);
        }
        var paths = files.map(function (f) {
            return path.resolve(dir, f);
        });
        async.map(paths, exports.isDir, function (err, results) {
            if (err) {
                return callback(err);
            }
            var dirs = _.compact(results.map(function (d) {
                return d.dir ? d.path: null;
            }));
            return callback(null, dirs);
        });
    });
};


/**
 * Checks if a path is a directory, returns an object containing the
 * checked path and a boolean for whether it's a directory.
 *
 * @param {String} path
 * @param {Function} callback
 */

exports.isDir = function (path, callback) {
    fs.stat(path, function (err, info) {
        if (err) {
            return callback(err);
        }
        return callback(null, {
            path: path,
            dir: info.isDirectory()
        });
    });
};

@@ -585,143 +585,8 @@
 lean
- %5BPATH%5D%5Cn' +%0A'%5Cn' +%0A'Parameters:%5Cn' +%0A'  PATH    Optional project directory to read dependencies from%5Cn' +%0A'          (defaults to %22.%22)
 %5Cn' 
@@ -988,17 +988,16 @@
     %7D);%0A
-%0A
     var 
@@ -1016,46 +1016,8 @@
 ons;
-%0A    var dir = a.positional%5B0%5D %7C%7C '.';
 %0A%0A  
@@ -1066,21 +1066,16 @@
 resolve(
-dir, 
 'jam');%0A
@@ -1092,21 +1092,16 @@
 s.clean(
-dir, 
 opt, fun
@@ -1274,52 +1274,8 @@
 %0A *%0A
- * @param %7BArray%7D dir - path to project dir%0A
  * @
@@ -1367,37 +1367,32 @@
 ean = function (
-dir, 
 opt, callback) %7B
@@ -1415,21 +1415,16 @@
 sedDirs(
-dir, 
 opt, fun
@@ -1689,16 +1689,26 @@
 elative(
+opt.taget_
 dir, d);
@@ -2769,54 +2769,8 @@
 %0A *%0A
- * @param %7BString%7D dir - the root package dir%0A
  * @
@@ -2875,21 +2875,16 @@
 nction (
-dir, 
 opt, cal
@@ -2909,16 +2909,27 @@
 ct.load(
+opt.target_
 dir, fun

fix clean command