/* 
     Description: 处理intervals

     Copyright : All right reserved by ICT

     Author : Zhang Zhonghai
     Date : 2019/11/24
*/

#ifndef INTERVAL_H_
#define INTERVAL_H_

#include <stdint.h>
#include <vector>
#include <string>
#include <sstream>

#include <htslib/sam.h>

#include "bam_wrap.h"

using namespace std;

// 前向声明
class Interval;
typedef std::vector<Interval> IntervalArr;
/*
 * 闭区间
 */
struct Interval {
    // const常量
    const static int CONTIG_SHIFT = 40;
    const static uint64_t POS_MASK = (1LL << CONTIG_SHIFT) - 1;

    // 类变量
    int64_t left;
    int64_t right;

    // 构造函数
    Interval();
    explicit Interval(int64_t l, int64_t r);
    explicit Interval(int tid, int l, int r) : Interval(BamWrap::bam_global_pos(tid, l), BamWrap::bam_global_pos(tid, r)) {}
    // 获取tid
    int contig() { return left >> CONTIG_SHIFT; }
    int contigLeft() { return left & POS_MASK; }
    int contigRight() { return right & POS_MASK; }

    // 比较函数
    bool operator<(const Interval &other);
    // 是否有重叠
    bool overlaps(const Interval &other);
    // 两个interval的合并, 会改变当前interval
    Interval& spanWith(const Interval &other);
    // 返回两个interval的交集，不改变当前interval
    Interval intersect(const Interval &that) const;

    // for debug
    string toString() const {
        ostringstream oss;
        oss << BamWrap::bam_tid(left) + 1 << ":"
            << BamWrap::bam_pos(left) + 1 << "-"
            << BamWrap::bam_pos(right) + 1;

        return oss.str();
    }
    /*
     * 合并两个interval arr，取相交区域的交集, interval arr都是排序后的
     */
    static void IntersectIntervals(const IntervalArr &a_arr, 
                                   const IntervalArr &b_arr, 
                                   IntervalArr *r_arr);
    /*
     * 合并两个interval arr，相交的区域取并集
     */
    static void UnionIntervals(const IntervalArr &a_arr,
                               const IntervalArr &b_arr,
                               IntervalArr *r_arr);
    /*
     * 将有read覆盖的区域和参数提供的interval文件中的区域做一个交集
     */
    static int64_t MergeIntervals(const IntervalArr &n_arr,
                                   const IntervalArr &t_arr,
                                   IntervalArr &in_arr, // 会更改
                                   int64_t start_loc, // 闭区间
                                   int64_t *end_loc, // 开区间, 会更改
                                   IntervalArr *r_arr);
    /*
     * 读取interval文件
     */
    static void ReadInterval(const std::string &interval_fn, 
                             bam_hdr_t* header, 
                             int interval_padding,
                             IntervalArr *r_arr);
    /*
     * 将interval相连的区域合并
     */
    static void ShrinkInterval(IntervalArr *iva);

    /*
     * 根据header信息，扩展interval
     */
    static Interval ExpandInterval(int64_t start, int64_t end, int expandVal, bam_hdr_t* header);
};


#endif


