#pragma once

#include <assert.h>
#include <iostream>

#include "Utils.h"

//! @brief Helper class for slicing containers.
class Slicer
{
public:
    Slicer();


protected:
    // Slicing.
    template <class Container1, class Container2>
    void update     (const Container1 &source, Container2 &slice);
    template <class Container1, class Container2>
    void next       (const Container1 &source, Container2 &slice);
    template <class Container1, class Container2>
    void previous   (const Container1 &source, Container2 &slice);
    template <class Container1, class Container2>
    void reset      (const Container1 &source, Container2 &slice);

public:
    // Slicing parameters.
    //! @brief Sets the overlap.
    //!
    //! @param overlap The number of overlapping vertices
    //! between on and the next slice.
    void setOverlap            (uint32_t overlap);
    //! @brief Sets the number of vertices per slice.
    //!
    //! @param N The number of vertices per slice.
    void setN   (std::uint32_t N);
    //! @brief Sets the start index.
    //!
    //! @param idxStart The start index.
    void setStartIndex         (int idxStart);

    //! @return Returns the overlap.
    uint32_t      overlap       ();
    //! @return Returns the number of vertices per slice N.
    uint32_t      N             ();
    //! @return Returns the start index.
    int           startIndex    ();

    Slicer &operator=(const Slicer &other);


private:
    void _updateIdx(std::size_t size);

    long          _idxStart;
    long          _idxEnd;
    long          _idxNext;
    long          _idxPrevious;
    uint32_t      _overlap;
    uint32_t      _N;
    bool          _idxValid;
    bool          _atEnd;


};

template <class Container1, class Container2>
void Slicer::update(const Container1 &source, Container2 &slice){

    _updateIdx(source.size());
    WaypointManager::Utils::extract(source, slice, _idxStart, _idxEnd);
}

template <class Container1, class Container2>
void Slicer::next(const Container1 &source, Container2 &slice){
    _updateIdx(source.size());
    setStartIndex(_idxNext);
    update(source, slice);
}


template <class Container1, class Container2>
void Slicer::previous(const Container1 &source, Container2 &slice){
    _updateIdx(source.size());
    setStartIndex(_idxPrevious);
    update(source, slice);
}


template <class Container1, class Container2>
void Slicer::reset(const Container1 &source, Container2 &slice){
    setStartIndex(0);
    update(source, slice);
}
