Fix a varscan VCF line.

    Fixes the ALT column and also fixes floating point values
    output as strings to by Floats: FREQ, SSC.

    This function was contributed by Sean Davis <sdavis2@mail.nih.gov>,
    with minor modifications by Luca Beltrame <luca.beltrame@marionegri.it>.

def fix_varscan_output(line, normal_name="", tumor_name=""):
    """Fix a varscan VCF line.

    Fixes the ALT column and also fixes floating point values
    output as strings to by Floats: FREQ, SSC.

    This function was contributed by Sean Davis <sdavis2@mail.nih.gov>,
    with minor modifications by Luca Beltrame <luca.beltrame@marionegri.it>.
    """
    line = line.strip()

    tofix = ("##INFO=<ID=SSC", "##FORMAT=<ID=FREQ")
    if(line.startswith("##")):
        if line.startswith(tofix):
            line = line.replace('Number=1,Type=String',
                                'Number=1,Type=Float')
        return line
    line = line.split("\t")

    if line[0].startswith("#CHROM"):
        if tumor_name and normal_name:
            mapping = {"NORMAL": normal_name, "TUMOR": tumor_name}
            base_header = line[:9]
            old_samples = line[9:]

            if len(old_samples) == 0:
                return "\t".join(line)

            samples = [mapping[sample_name] for sample_name in old_samples]

            assert len(old_samples) == len(samples)
            return "\t".join(base_header + samples)
        else:
            return "\t".join(line)

    try:
        REF, ALT = line[3:5]
    except ValueError:
        return "\t".join(line)

    def _normalize_freq(line, sample_i):
        """Ensure FREQ genotype value is float as defined in header.
        """
        ft_parts = line[8].split(":")
        dat = line[sample_i].split(":")
        # Non-conforming no-call sample, don't try to fix FREQ
        if len(dat) != len(ft_parts):
            return line
        freq_i = ft_parts.index("FREQ")
        try:
            dat[freq_i] = str(float(dat[freq_i].rstrip("%")) / 100)
        except ValueError:  # illegal binary characters -- set frequency to zero
            dat[freq_i] = "0.0"
        line[sample_i] = ":".join(dat)
        return line

    if len(line) > 9:
        line = _normalize_freq(line, 9)
        if len(line) > 10:
            line = _normalize_freq(line, 10)
            # HACK: The position of the SS= changes, so we just search for it
            ss_vals = [item for item in line[7].split(";") if item.startswith("SS=")]
            if len(ss_vals) > 0:
                somatic_status = int(ss_vals[0].split("=")[1])  # Get the number
            else:
                somatic_status = None
            if somatic_status == 5:
                # "Unknown" states are broken in current versions of VarScan
                # so we just bail out here for now
                return
            # fix FREQ for any additional samples -- multi-sample VarScan calling
            if len(line) > 11:
                for i in range(11, len(line)):
                    line = _normalize_freq(line, i)

    #FIXME: VarScan also produces invalid REF records (e.g. CAA/A)
    # This is not handled yet.

    if "+" in ALT or "-" in ALT:
        if "/" not in ALT:
            if ALT[0] == "+":
                R = REF
                A = REF + ALT[1:]
            elif ALT[0] == "-":
                R = REF + ALT[1:]
                A = REF
        else:
            Ins = [p[1:] for p in ALT.split("/") if p[0] == "+"]
            Del = [p[1:] for p in ALT.split("/") if p[0] == "-"]

            if len(Del):
                REF += sorted(Del, key=lambda x: len(x))[-1]

            A = ",".join([REF[::-1].replace(p[::-1], "", 1)[::-1]
                          for p in Del] + [REF + p for p in Ins])
            R = REF

        REF = R
        ALT = A
    else:
        ALT = ALT.replace('/', ',')

    line[3] = REF
    line[4] = ALT
    return "\t".join(line)