/**
 * Test resource manage module.
 * @module testResource
 * @author "ci.worker.generateStructure"
 */

var path = require('path'),
    fs = require('fs'),
    resolve = path.resolve;

/**
 * Mock directory path.
 * @type {string}
 */
exports.mockDir = resolve(__dirname, 'mock');

/**
 * Work directory path.
 * @type {string}
 */
exports.workDir = resolve(__dirname, 'work');

/**
 * Resolve mock file path from file name.
 * @param  {string} filename - Mock filename.
 * @returns {string} - Full path of mock resource file.
 */
exports.resolveMockFile = function (filename) {
    filename = path.join.apply(path, arguments);
    return resolve(exports.mockDir, filename);
};

/**
 * Resolve work file path from file name.
 * @param {string} filename - Work filename.
 * @returns {string} - Full path of work resource file.
 */
exports.resolveWorkFile = function (filename) {
    filename = path.join.apply(path, arguments);
    return resolve(exports.workDir, filename);
};


/**
 * Read mock file content.
 * @param {string} filename - Mock filename.
 * @param {function} callback - Callback with contents.
 */
exports.readMockFile = function (filename, callback) {
    var filepath = exports.resolveMockFile(filename);
    fs.readFile(filepath, callback);
};


/**
 * Read mock work content.
 * @param {string} filename - Work filename.
 * @param {function} callback - Callback with contents.
 */
exports.readWorkFile = function (filename, callback) {
    var filepath = exports.resolveWorkFile(filename);
    return fs.readFile(filepath, callback);
};

function mkdirP(dirname, callback) {
    if (!callback) callback = new Function;
    fs.exists(dirname, function (exists) {
        if (exists) {
            callback(null);
        } else {
            exports(path.dirname(dirname), function (err) {
                if (err) {
                    callback(err);
                } else {
                    fs.mkdir(dirname, function (err) {
                        callback(err);
                    });
                }
            });
        }
    });
};

/**
 * Prepare clean work directory.
 * @param {string} dirname - Directory name to prepare.
 * @param {function} callback - Callback when done. Passes work dir path.
 */
exports.prepareCleanWorkDir = function (dirname, callback) {
    var dirpath = exports.resolveWorkFile(dirname);
    fs.exists(dirpath, function (exists) {
        if (exists) {
            exports._rmdirRecursive(dirpath, function () {
                fs.mkdir(dirpath, function () {
                    callback(dirpath);
                });
            });
        } else {
            mkdirP(dirpath, function () {
                callback(dirpath);
            });
        }
    });
};

/**
 * Require a mock module.
 * @param {string} filename - Module file name.
 * @returns {object} - A mock module.
 */
exports.requireMockModule = function (filename) {
    return require(exports.resolveMockFile(filename));
};


/**
 * Remove directory recursively.
 * @param {string} dirname - Directory path string.
 * @param {function} callback - Callback when done.
 */
exports._rmdirRecursive = function (dirname, callback) {
    fs.readdir(dirname, function (err, filenames) {
        if (err) {
            callback(err);
            return;
        }
        var jobs = filenames
            .map(function (filename) {
                return path.resolve(dirname, filename);
            })
            .map(function (filename) {
                return function (callback) {
                    fs.stat(filename, function (err, stats) {
                        if (err) {
                            callback(err);
                        } else {
                            if (stats.isDirectory()) {
                                fs.lstat(filename, function (err, lstats) {
                                    if (err) {
                                        callback(err);
                                        return;
                                    }
                                    if (lstats.isSymbolicLink()) {
                                        fs.unlink(filename, callback);
                                        return;
                                    }
                                    exports._rmdirRecursive(filename, function (err) {
                                        if (err) {
                                            callback(err);
                                        } else {
                                            fs.rmdir(filename, function (err) {
                                                callback(err);
                                            });
                                        }
                                    });
                                });
                            } else {
                                fs.lstat(filename, function (err, stat) {
                                    if (err) {
                                        callback && callback(err);
                                        return;
                                    }
                                    var isSymlink = stat.isSymbolicLink();
                                    if (isSymlink) {
                                        fs.unlink(filename, function (err) {
                                            callback && callback(err);
                                        });
                                    } else {
                                        fs.chmod(filename, '777', function (err) {
                                            if (err) {
                                                callback && callback(err);
                                            } else {
                                                fs.unlink(filename, function (err) {
                                                    callback && callback(err);
                                                });
                                            }
                                        });
                                    }
                                });
                            }
                        }
                    });
                }
            });
        var count = jobs.length;
        if (count) {
            var abort = false;
            jobs.forEach(function (job) {
                job(function (err) {
                    if (abort) return;
                    if (err) {
                        callback(err);
                        abort = true;
                        return;
                    }
                    count--;
                    var finished = count <= 0;
                    if (finished) {
                        callback(null);
                    }
                })
            });
        } else {
            callback();
        }
    });
};

/**
 * Prepare clean work dir for a test file.
 * @param {string} testFilename - Test filename.
 * @param {function} callback - Callback with contents.
 */
exports.prepareCleanWorkDirForTestFile = function (testFilename, callback) {
    var testFileBaseName = path.basename(testFilename, path.extname(testFilename));
    var workDir = exports.resolveWorkFile('work_' + testFileBaseName);
    exports.prepareCleanWorkDir(workDir, function (err) {
        callback(err, workDir);
    });
};