/* 
 * File:   PairedEndIO.h
 * Author: yangxi
 *
 * Created on March 27, 2014, 9:15 AM
 */

#ifndef HTIO2_PAIRED_END_IO_H
#define	HTIO2_PAIRED_END_IO_H

#include "htio2/RefCounted.h"
#include "htio2/Enum.h"
#include "htio2/FastqSeq.h"

namespace htio2
{

class SeqIO;
class FastqSeq;

/**
 * A wrapper class that handle several paired-end reads read/write issues.
 * 
 * The PairedEndIO class is designed for handle several paired-end related
 * issues:
 * 
 *  - they are stored in one interleaved file, or two files?
 *  - the strand of the reads are Fwd-Rev (the most common), or Rev-Fwd (common for long insersion libraries)?
 * 
 * For the first issue, PairedEndIO provides two constructors: one with only one
 * file parameter, and the other one with two file parameters. If the object is
 * built with the one-file constructor, it is 
 * 
 * For the second issue, when PairedEndIO is being constructed, it requires the
 * strand of reads in file being specified; and when read/write sequences, it
 * require the strand of the sequence object being specified.
 * 
 * For example, if you specify the reads file is in FWD and REV format (the most
 * common case), and you specify the reads you get is in FWD and FWD format when
 * you call next_pair(), read 1 will be given as-is, while read 2 will be
 * reverse-complemented.
 */
class PairedEndIO : public RefCounted
{
public:
    typedef SmartPtr<PairedEndIO> Ptr;
    typedef SmartPtr<const PairedEndIO> ConstPtr;
public:
    /**
     * create PairedEndIO object. Both ends are stored in one interleaved file.
     * @param file file for input reads.
     * @param mode READ/WRITE/APPEND.
     * @param strand_r1_in_file strand of read 1 in file.
     * @param strand_r2_in_file strand of read 2 in file.
     * @param comp compression format. COMPRESS_UNKNOWN for automatically guess by file name.
     * @param format sequence format. FORMAT_UNKNOWN for automatically guess by file name and/or content.
     */
    PairedEndIO(const std::string& file,
                IOMode mode,
                Strand strand_r1_in_file = STRAND_FWD,
                Strand strand_r2_in_file = STRAND_REV,
                CompressFormat comp = COMPRESS_UNKNOWN,
                SeqFormat format = FORMAT_UNKNOWN);

    /**
     * create PairedEndIO object. Two read ends are stored in two separate file.
     * @param file1 file for read 1.
     * @param file2 file for read 2.
     * @param mode READ/WRITE/APPEND.
     * @param strand_r1_in_file strand of read 1 in file.
     * @param strand_r2_in_file strand of read 2 in file.
     * @param comp compression format. COMPRESS_UNKNOWN for automatically guess by file name.
     * @param format sequence format. FORMAT_UNKNOWN for automatically guess by file name and/or content.
     */
    PairedEndIO(const std::string& file1,
                const std::string& file2,
                IOMode mode,
                Strand strand_r1_in_file = STRAND_FWD,
                Strand strand_r2_in_file = STRAND_REV,
                CompressFormat comp = COMPRESS_UNKNOWN,
                SeqFormat format = FORMAT_UNKNOWN);

    virtual ~PairedEndIO();

    /**
     * read one pair from file
     * @param seq1
     * @param seq2
     * @param strand_r1 strand of read 1 you expect to get
     * @param strand_r2 strand of read 2 you expect to get
     * @return false if reached end of file, otherwise true.
     */
    bool next_pair(FastqSeq& seq1,
                   FastqSeq& seq2,
                   Strand strand_r1 = STRAND_FWD,
                   Strand strand_r2 = STRAND_FWD);

    /**
     * 
     * @param seq1 read 1 to be written
     * @param seq2 read 2 to be written
     * @param strand_r1 strand of read 1 you give
     * @param strand_r2 strand of read 2 you give
     */
    void write_pair(const FastqSeq& seq1,
                    const FastqSeq& seq2,
                    Strand strand_r1 = STRAND_FWD,
                    Strand strand_r2 = STRAND_FWD);

protected:
    SeqIO* fh1;
    SeqIO* fh2;

    FastqSeq tmp1;
    FastqSeq tmp2;

    Strand strand_r1_in_file;
    Strand strand_r2_in_file;
    bool interleave;

private:
    bool _read_next_pair(FastqSeq& seq1, FastqSeq& seq2);
    void _write_pair(const FastqSeq& seq1, const FastqSeq& seq2);

    PairedEndIO(const PairedEndIO& orig);
    PairedEndIO& operator =(const PairedEndIO& orig);
};

} // namespace htio2

#endif	/* HTIO2_PAIRED_END_IO_H */


