Wrapper for using bbduk to quality trim reads. Contains arguments used in OLC Assembly Pipeline, but these can
    be overwritten by using keyword parameters.
    :param forward_in: Forward reads you want to quality trim.
    :param returncmd: If set to true, function will return the cmd string passed to subprocess as a third value.
    :param forward_out: Output forward reads.
    :param reverse_in: Reverse input reads. Don't need to be specified if _R1/_R2 naming convention is used.
    :param reverse_out: Reverse output reads. Don't need to be specified if _R1/_R2 convention is used.
    :param kwargs: Other arguments to give to bbduk in parameter=argument format. See bbduk documentation for full list.
    :return: out and err: stdout string and stderr string from running bbduk.

def bbduk_trim(forward_in, forward_out, reverse_in='NA', reverse_out='NA',
               trimq=20, k=25, minlength=50, forcetrimleft=15, hdist=1, returncmd=False, **kwargs):
    """
    Wrapper for using bbduk to quality trim reads. Contains arguments used in OLC Assembly Pipeline, but these can
    be overwritten by using keyword parameters.
    :param forward_in: Forward reads you want to quality trim.
    :param returncmd: If set to true, function will return the cmd string passed to subprocess as a third value.
    :param forward_out: Output forward reads.
    :param reverse_in: Reverse input reads. Don't need to be specified if _R1/_R2 naming convention is used.
    :param reverse_out: Reverse output reads. Don't need to be specified if _R1/_R2 convention is used.
    :param kwargs: Other arguments to give to bbduk in parameter=argument format. See bbduk documentation for full list.
    :return: out and err: stdout string and stderr string from running bbduk.
    """
    options = kwargs_to_string(kwargs)
    cmd = 'which bbduk.sh'
    try:
        subprocess.check_output(cmd.split()).decode('utf-8')
    except subprocess.CalledProcessError:
        print('ERROR: Could not find bbduk. Plase check that the bbtools package is installed and on your $PATH.\n\n')
        raise FileNotFoundError
    if os.path.isfile(forward_in.replace('_R1', '_R2')) and reverse_in == 'NA' and '_R1' in forward_in:
        reverse_in = forward_in.replace('_R1', '_R2')
        if reverse_out == 'NA':
            if '_R1' in forward_out:
                reverse_out = forward_out.replace('_R1', '_R2')
            else:
                raise ValueError('If you do not specify reverse_out, forward_out must contain R1.\n\n')
        cmd = 'bbduk.sh in1={f_in} in2={r_in} out1={f_out} out2={r_out} qtrim=w trimq={trimq} k={k} ' \
              'minlength={minlength} forcetrimleft={forcetrimleft} ref=adapters overwrite hdist={hdist} tpe tbo{optn}'\
            .format(f_in=forward_in,
                    r_in=reverse_in,
                    f_out=forward_out,
                    r_out=reverse_out,
                    trimq=trimq,
                    k=k,
                    minlength=minlength,
                    forcetrimleft=forcetrimleft,
                    hdist=hdist,
                    optn=options)
    elif reverse_in == 'NA' or reverse_in is None:
        cmd = 'bbduk.sh in={f_in} out={f_out} qtrim=w trimq={trimq} k={k} minlength={minlength} ' \
              'forcetrimleft={forcetrimleft} ref=adapters overwrite hdist={hdist} tpe tbo{optn}'\
            .format(f_in=forward_in,
                    f_out=forward_out,
                    trimq=trimq,
                    k=k,
                    minlength=minlength,
                    forcetrimleft=forcetrimleft,
                    hdist=hdist,
                    optn=options)
    else:
        if reverse_out == 'NA':
            raise ValueError('Reverse output reads must be specified.')
        cmd = 'bbduk.sh in1={f_in} in2={r_in} out1={f_out} out2={r_out} qtrim=w trimq={trimq} k={k} ' \
              'minlength={minlength} forcetrimleft={forcetrimleft} ref=adapters overwrite hdist={hdist} tpe tbo{optn}' \
            .format(f_in=forward_in,
                    r_in=reverse_in,
                    f_out=forward_out,
                    r_out=reverse_out,
                    trimq=trimq,
                    k=k,
                    minlength=minlength,
                    forcetrimleft=forcetrimleft,
                    hdist=hdist,
                    optn=options)
    out, err = accessoryfunctions.run_subprocess(cmd)
    if returncmd:
        return out, err, cmd
    else:
        return out, err