//***************************************************************************
//* Copyright (c) 2015 Saint Petersburg State University
//* Copyright (c) 2011-2014 Saint Petersburg Academic University
//* All Rights Reserved
//* See file LICENSE for details.
//***************************************************************************

#pragma once

#include "read_stream_vector.hpp"

namespace io {

/**
* SquashingWrapper is the class-wrapper that reads SingleReads
* from Reader<PairedRead> (first and second single reads in a pair
* one by one).
*/
template<class PairedReadType>
class SquashingWrapper : public ReadStream<typename PairedReadType::SingleReadT> {
    typedef typename PairedReadType::SingleReadT SingleReadT;
    typedef std::shared_ptr<ReadStream<PairedReadType>> PairedReaderPtrT;
public:

    explicit SquashingWrapper(PairedReaderPtrT reader)
            : reader_(reader), pairedread_(), index_(0) {
    }

    /*
     * Check whether the stream is opened.
     *
     * @return true if the stream is opened and false otherwise.
     */
    /* virtual */ bool is_open() {
        return reader_->is_open();
    }

    /*
     * Check whether we've reached the end of stream.
     *
     * @return true if the end of the stream is reached and false
     * otherwise.
     */
    /* virtual */ bool eof() {
        return (index_ == 0) && (reader_->eof());
    }

    /*
     * Read SingleRead from stream (which is actually the part of
     * PairedRead from stream).
     *
     * @param singleread The SingleRead that will store read data.
     *
     * @return Reference to this stream.
     */
    /* virtual */ SquashingWrapper &operator>>(
            SingleReadT &singleread) {
        if (index_ == 0) {
            (*reader_) >> pairedread_;
        }
        singleread = pairedread_[index_];
        index_ = 1 - index_;
        return (*this);
    }

    /*
     * Close the stream.
     */
    /* virtual */ void close() {
        reader_->close();
    }

    /*
     * Close the stream and open it again.
     */
    /* virtual */ void reset() {
        index_ = 0;
        reader_->reset();
    }

    ReadStreamStat get_stat() const {
        return reader_->get_stat();
    }

private:
    /*
     * @variable Internal stream reader.
     */
    PairedReaderPtrT reader_;
    /*
     * @variable Element that stores the last read PairedRead from
     * stream.
     */
    PairedReadType pairedread_;
    /*
     * @variable Index of current part of PairedRead.
     */
    size_t index_;

};

template<class PairedReadType>
std::shared_ptr<ReadStream<typename PairedReadType::SingleReadT>> SquashingWrap(
        std::shared_ptr<ReadStream<PairedReadType>> reader_ptr) {
    return std::make_shared<SquashingWrapper<PairedReadType>>(reader_ptr);
}

template<class PairedReadType>
ReadStreamList<typename PairedReadType::SingleReadT> SquashingWrap(ReadStreamList<PairedReadType> &readers) {
    ReadStreamList<typename PairedReadType::SingleReadT> answer;
    for (size_t i = 0; i < readers.size(); ++i) {
        answer.push_back(SquashingWrap<PairedReadType>(readers.ptr_at(i)));
    }
    return answer;
}

//template<class ReaderPtrType>
//std::shared_ptr<Reader<typename ReaderPtrType::element_type::ReadT::SingleReadT>> SquashingWrap(ReaderPtrType reader_ptr) {
//    return std::make_shared<SquashingWrapper<typename ReaderPtrType::element_type::ReadT>>(reader_ptr);
//}
}
