// VectorGetDelta.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2007-2021

#pragma once
#include "TVectorInsertions.h"
#include "TVectorDeletions.h"
#include "TVectorTime.h"
#include "Ceda/cxUtils/CedaAssert.h"
#include "Ceda/cxUtils/Range.h"
#include "Ceda/cxUtils/xvector.h"

namespace ceda
{
    /*
    Calculate dst_insertions
    
    From the VectorInsertions and the underestimate rhv of the remote HB vector time 
    we can scan through the intervals ordered by q-position and test whether 
    t < rhv(s).  So we can find the set of intervals in q-coords that need to be sent.
    
    Note that this corresponds to an RFactor and there is no need to adjust the 
    q-coords.
    */
    template<typename VectorInsertionInterval, typename VectorInsertions, typename VectorTime>
    void GetRFactorInsertions(xvector<const VectorInsertionInterval*>& dst_insertions, const VectorInsertions& src_insertions, const VectorTime& rhv)
    {
        auto r = src_insertions.m_c.m_first;
        while(r)
        {
            cxAssert(r->m_u < src_insertions.m_u2);
            if (!rhv.ExtentContains(r->m_opid))
            {
                dst_insertions.push_back(r);
            }
            r = r->m_next;
        }
    }

    template<typename VectorDeletionInterval, typename VectorDeletions, typename VectorTime>
    void GetRFactorDeletions(xvector<const VectorDeletionInterval*>& dst_deletions, const VectorDeletions& src_deletions, const VectorTime& rhv)
    {
        auto r = src_deletions.m_first;
        while(r)
        {
            if (!rhv.ExtentContains(r->m_opid))
            {
                dst_deletions.push_back(r);
            }
            r = r->m_next;
        }
    }

    template<typename I>
    struct RecordPCoordIntervals
    {
        struct Interval
        {
            I p;
            I n;
        };
                        
        RecordPCoordIntervals() : m_numElements(0) {}
                        
        void Add(I deletionExtent, I q1, I q2)
        {
            cxAssert(0 <= deletionExtent && deletionExtent <= q1 && q1 <= q2);
                            
            Interval i;
            i.p = q1 - deletionExtent;
            i.n = q2-q1;
            m_intervals.push_back(i);
            m_numElements += q2-q1;
        }
                        
        I m_numElements;
        xvector<Interval> m_intervals;
    };
                    
    /*
    Calculate the intervals in i\d, as an xvector of intervals expressed in p coords.
    */
    template<typename I, typename VectorInsertionInterval, typename VectorDeletions>
    void GetIntervalsPresent(
        RecordPCoordIntervals<I>& ri, 
        const xvector<const VectorInsertionInterval*>& i, 
        const VectorDeletions& d)
    {
        SubtractIntervalLists_2(
            MakeRangeFromVectorOfPointers(i), 
            MakeRangeFromBiDirectionalIterators(d),
            ri);
    }

} // namespace ceda
