/**
 * Copy files from inbound archives to arbitrary locations.
 * Based on nodelist_handler.js, but less ugly.
 * 
 * tickit.ini:
 * 
 * [FSX_INFO]
 * Dir = FSXNET_FSX_INFO
 * Handler = tickit/file_handler.js
 * HandlerArg = { "match": "fsxinfo.zip", "files": [{ "source": "FSXNET.NA", "destination": "/sbbs/fido/echolists/fsxnet.na" }]}
 * 
 * Where "files" is an array of { source, destination } objects, copy any
 * "source" file from the archive to "destination".
 * 
 * The HandlerArg object can have a "cmd" property, which is a command-line
 * to be executed after everything in the "files" array has been processed.
 * 
 * Each object in the "files" array may also have a "cmd" property, which
 * is a command-line to be executed after that file has been processed.
 * 
 * Command line specifiers are supported in the "cmd" strings.
 * http://wiki.synchro.net/config:cmdline#specifiers
 * In the case of the global "cmd", %f is the full TIC file path, and %s
 * is the directory it was extracted to.
 * In the case of a per-file "cmd", %f is the destination file, and %s is
 * the source file.
 * 
 * Wildcards are allowed in "match" and "source".
 * (Wildcards in "source" untested on Windows.)
 */

function mycmdstr(instr, fpath, fspec)
{
	instr = instr.replace(/%%/i, "\x00");
	instr = instr.replace(/%f/i, fpath);
	instr = instr.replace(/%g/i, system.temp_dir);
	instr = instr.replace(/%j/i, system.data_dir);
	instr = instr.replace(/%k/i, system.ctrl_dir);
	instr = instr.replace(/%n/i, system.node_dir);
	instr = instr.replace(/%o/i, system.operator);
	instr = instr.replace(/%q/i, system.qwk_id);
	instr = instr.replace(/%s/i, fspec);
	instr = instr.replace(/%!/, system.exec_dir);
	instr = instr.replace(/%@/, system.platform == 'Win32' ? system.exec_dir : '');
	instr = instr.replace(/%#/, '0');		// TODO: Can't get ENV variables...
	instr = instr.replace(/%\*/, '000');	// TODO: Can't get ENV variables...
	instr = instr.replace(/%\./, system.platform == 'Win32' ? '.exe' : '');
	instr = instr.replace(/%\?/, system.platform);
	instr = instr.replace(/\x00/i, "%");
	return instr;
}

function run_and_log(cmd, fpath, fspec) {
	var cs = mycmdstr(cmd, fpath, fspec);
	log(LOG_DEBUG, 'Executing: ' + cs);
	var rc;
	if ((rc = system.exec(cs)) != 0) {
		log(LOG_ERROR, 'Command failed. Return value: ' + rc);
		return false;
	}
	return true;
}

function Handle_TIC(tic, ctx, arg) {
	var cfg;
	var unpack;
	var dir;
	var rc;

	// Parse the config...
	try {
		cfg = JSON.parse(arg);
	} catch (e) {
		log(LOG_ERROR, 'Unable to parse "' + arg + '" as JSON, aborting');
		return false;
	}

	if (cfg.match === undefined) cfg.match = '*.*';

	if (!Array.isArray(cfg.files)) {
        log(LOG_ERROR, 'No "files" list specified.  Aborting.');
        return false;
    }

	if (!wildmatch(tic.file, cfg.match)) {
		log(LOG_DEBUG, 'TIC file ' + tic.file + " doesn't match " + cfg.match);
		return false;
	}

	var f = new File(tic.full_path);
	if (!f.open('rb', true)) {
		log(LOG_ERROR, 'Unable to open ' + tic.full_path);
		return false;
	}
	Object.keys(ctx.sbbsecho.packer).forEach(function(key) {
		var i;
		var sig = '';
		f.position = ctx.sbbsecho.packer[key].offset;
		for (i = 0; i < ctx.sbbsecho.packer[key].sig.length; i += 2) {
			sig += format('%02X', f.readBin(1));
			if (f.eof) break;
		}
		if (sig === ctx.sbbsecho.packer[key].sig) {
            unpack = ctx.sbbsecho.packer[key].unpack;
        }
	});
	f.close();

	if (unpack == undefined) {
		log(LOG_ERROR, 'Unable to identify packer for ' + tic.file);
		return false;
	}

	// Create a directory to extract to...
	dir = backslash(system.temp_dir) + 'tickit_file_copier';
	if (!file_isdir(dir)) {
		if (!mkdir(dir)) {
			log(LOG_ERROR, 'Unable to create temp directory ' + dir);
			return false;
		}
	} else {
		// Empty the directory
		directory(backslash(dir) + (system.platform == 'Win32' ? '*.*' : '*')).forEach(function(e) {
			if (!file_remove(e)) log(LOG_ERROR, 'Unable to delete file ' + e);
		});
		if (directory(backslash(dir) + (system.platform == 'Win32' ? '*.*' : '*')).length) {
			log(LOG_ERROR, 'Unable to empty directory ' + dir);
			return false;
		}
	}

	if (!run_and_log(unpack, tic.full_path, dir)) return false;

    cfg.files.forEach(function (e) {
        var sf = backslash(dir) + e.source;
        const df = e.destination;
        if (!file_exists(sf)) {
			log(LOG_ERROR, e.source + ' not found in ' + tic.file);
			return;
        }
        if (!file_copy(sf, df)) {
			log(LOG_ERROR, 'Failed to copy ' + sf + ' to ' + df);
			return;
        }
		log(LOG_DEBUG, 'Copied ' + sf + ' to ' + df);
		if (e.cmd) run_and_log(e.cmd, df, sf);
	});
	if (cfg.cmd) run_and_log(cfg.cmd, tic.full_path, dir);

	// Return false so it is still moved into the appropriate dir
	return false;
}

0; // Whaa?