"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.flipCigar = flipCigar;
exports.swapIndelCigar = swapIndelCigar;
exports.createPIF = createPIF;
const child_process_1 = require("child_process");
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const readline_1 = __importDefault(require("readline"));
const zlib_1 = require("zlib");
const core_1 = require("@oclif/core");
const command_exists_1 = require("command-exists");
const base_1 = __importDefault(require("../base"));
const cigarRegex = new RegExp(/([MIDNSHPX=])/);
function getReadline(filename) {
    const stream = fs_1.default.createReadStream(filename);
    return readline_1.default.createInterface({
        input: /.b?gz$/.exec(filename) ? stream.pipe((0, zlib_1.createGunzip)()) : stream,
    });
}
function getStdReadline() {
    return readline_1.default.createInterface({
        input: process.stdin,
    });
}
function parseCigar(cigar = '') {
    return cigar.split(cigarRegex).slice(0, -1);
}
function flipCigar(cigar) {
    const arr = [];
    for (let i = cigar.length - 2; i >= 0; i -= 2) {
        arr.push(cigar[i]);
        const op = cigar[i + 1];
        if (op === 'D') {
            arr.push('I');
        }
        else if (op === 'I') {
            arr.push('D');
        }
        else {
            arr.push(op);
        }
    }
    return arr;
}
function swapIndelCigar(cigar) {
    return cigar.replaceAll('D', 'K').replaceAll('I', 'D').replaceAll('K', 'I');
}
async function createPIF(filename, stream) {
    const rl1 = filename ? getReadline(filename) : getStdReadline();
    for await (const line of rl1) {
        const [c1, l1, s1, e1, strand, c2, l2, s2, e2, ...rest] = line.split('\t');
        stream.write(`${[`t${c2}`, l2, s2, e2, strand, c1, l1, s1, e1, ...rest].join('\t')}\n`);
        const cigarIdx = rest.findIndex(f => f.startsWith('cg:Z'));
        const CIGAR = rest[cigarIdx];
        if (CIGAR) {
            rest[cigarIdx] = `cg:Z:${strand === '-'
                ? flipCigar(parseCigar(CIGAR.slice(5))).join('')
                : swapIndelCigar(CIGAR.slice(5))}`;
        }
        stream.write(`${[`q${c1}`, l1, s1, e1, strand, c2, l2, s2, e2, ...rest].join('\t')}\n`);
    }
    rl1.close();
}
class MakePIF extends base_1.default {
    async run() {
        const { args: { file }, flags: { out, csi }, } = await this.parse(MakePIF);
        if ((0, command_exists_1.sync)('sh') &&
            (0, command_exists_1.sync)('sort') &&
            (0, command_exists_1.sync)('grep') &&
            (0, command_exists_1.sync)('tabix') &&
            (0, command_exists_1.sync)('bgzip')) {
            const fn = out || `${path_1.default.basename(file || 'output', '.paf')}.pif.gz`;
            const child = (0, child_process_1.spawn)('sh', [
                '-c',
                `sort -t"\`printf '\t'\`" -k1,1 -k3,3n | bgzip > ${fn}; tabix ${csi ? '-C ' : ''}-s1 -b3 -e4 -0 ${fn}`,
            ], {
                env: { ...process.env, LC_ALL: 'C' },
                stdio: ['pipe', process.stdout, process.stderr],
            });
            await createPIF(file, child.stdin);
            child.stdin.end();
            await new Promise(resolve => {
                child.on('close', resolve);
            });
        }
        else {
            throw new Error('Unable to sort, requires unix type environment with sort, grep, bgzip, tabix');
        }
    }
}
MakePIF.description = 'creates pairwise indexed PAF (PIF), with bgzip and tabix';
MakePIF.examples = [
    '$ jbrowse pif input.paf # creates input.pif.gz in same directory',
    '',
    '$ jbrowse pif input.paf --out output.pif.gz # specify output file, creates output.pif.gz.tbi also',
];
MakePIF.flags = {
    out: core_1.Flags.string({
        description: 'Where to write the output file. will write ${file}.pif.gz and ${file}.pif.gz.tbi',
    }),
    csi: core_1.Flags.boolean({
        description: 'Create a CSI index for the PIF file instead of TBI',
    }),
    help: core_1.Flags.help({ char: 'h' }),
};
MakePIF.args = {
    file: core_1.Args.string({
        required: true,
        description: 'PAF file as input',
    }),
};
exports.default = MakePIF;
