#pragma once

#include <iostream>

#include "Slicer.h"

namespace WaypointManager {

template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
class GenericWaypointManager : public Slicer
{
public:
    typedef ContainerType<WaypointType>  WaypointList;

    GenericWaypointManager() = delete;
    GenericWaypointManager(SettingsType &settings);

    // Waypoint editing.
    void            setWaypoints(const WaypointList &waypoints);
    void            push_back   (const WaypointType &wp);
    void            push_front  (const WaypointType &wp);
    virtual void    clear       ();
    void            insert      (std::size_t i, const WaypointType &wp);
    std::size_t     size        ()  const;
    WaypointType    &at         (std::size_t i);


    const WaypointList      &waypoints() const;
    const WaypointList      &currentWaypoints() const;
    const MissionItemList   &missionItems() const;
    const MissionItemList   &currentMissionItems() const;

    const QVariantList &waypointsVariant() const;
    const QVariantList &currentWaypointsVariant() const;

    virtual bool update() = 0;
    virtual bool next() = 0;
    virtual bool previous() = 0;
    virtual bool reset() = 0;

protected:
    WaypointList        _waypoints;
    WaypointList        _currentWaypoints;
    MissionItemList     _currentMissionItems;
    MissionItemList     _missionItems;
    SettingsType       *_settings;
    bool                _dirty;
    QVariantList        _waypointsVariant;
    QVariantList        _currentWaypointsVariant;
};


template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
GenericWaypointManager<WaypointType,
                       ContainerType,
                       MissionItemList,
                       SettingsType>::GenericWaypointManager(SettingsType &settings)
  : Slicer()
  , _settings(&settings)
  , _dirty(true)
{}

template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
void GenericWaypointManager<WaypointType,
                            ContainerType,
                            MissionItemList,
                            SettingsType>::push_back(const WaypointType &wp)
{
    _dirty = true;
    _waypoints.push_back(wp);
}

template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
void GenericWaypointManager<WaypointType,
                            ContainerType,
                            MissionItemList,
                            SettingsType>::push_front(
        const WaypointType &wp)
{
    _dirty = true;
    _waypoints.push_front(wp);
}

template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
void GenericWaypointManager<WaypointType,
                            ContainerType,
                            MissionItemList,
                            SettingsType>::clear()
{
    _dirty = true;
    _waypoints.clear();
    _currentWaypoints.clear();
    _missionItems.clear();
    _currentMissionItems.clear();
    _waypointsVariant.clear();
    _currentWaypointsVariant.clear();
}

template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
void GenericWaypointManager<WaypointType,
                            ContainerType,
                            MissionItemList,
                            SettingsType>::insert(std::size_t i,
                                                  const WaypointType &wp)
{
    _dirty = true;
    _waypoints.insert(i, wp);
}

template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
std::size_t GenericWaypointManager<WaypointType,
                                   ContainerType,
                                   MissionItemList,
                                   SettingsType>::size() const
{
    return _waypoints.size();
}

template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
WaypointType & GenericWaypointManager<WaypointType,
                                      ContainerType,
                                      MissionItemList,
                                      SettingsType>::at(std::size_t i)
{
    return _waypoints.at(i);
}

template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
const QVariantList  &GenericWaypointManager<WaypointType,
                                            ContainerType,
                                            MissionItemList,
                                            SettingsType>::waypointsVariant() const
{
    return _waypointsVariant;
}

template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
const QVariantList  &GenericWaypointManager<WaypointType,
                                            ContainerType,
                                            MissionItemList,
                                            SettingsType>::currentWaypointsVariant() const
{
    return _currentWaypointsVariant;
}

template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
const ContainerType<WaypointType>  &GenericWaypointManager<WaypointType,
                                                           ContainerType,
                                                           MissionItemList,
                                                           SettingsType>::waypoints() const
{
    return _waypoints;
}

template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
const ContainerType<WaypointType> &GenericWaypointManager<WaypointType,
                                                          ContainerType,
                                                          MissionItemList,
                                                          SettingsType>::currentWaypoints() const
{
    return _currentWaypoints;
}

template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
const MissionItemList &GenericWaypointManager<WaypointType,
                                              ContainerType,
                                              MissionItemList,
                                              SettingsType>::missionItems() const
{
    return _missionItems;
}

template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
const MissionItemList &GenericWaypointManager<WaypointType,
                                              ContainerType,
                                              MissionItemList,
                                              SettingsType>::currentMissionItems() const
{
    return _currentMissionItems;
}

template<class WaypointType,
         template<class, class...> class ContainerType,
         class MissionItemList,
         class SettingsType>
void GenericWaypointManager<WaypointType,
                            ContainerType,
                            MissionItemList,
                            SettingsType>::setWaypoints(const ContainerType<WaypointType> &waypoints)
{
    _waypoints = waypoints;
}



} // namespace WaypointManager

