#pragma once

#include <set>
#include <algorithm>

#include "core/gameevent.h"
#include "core/updatedata.h"
#include "core/bpmsection.h"

namespace kku
{

/// Editor
///
/// Functional aggregation of
/// logic for Editor game mode
class Editor
{
public:
    virtual ~Editor() = default;

    virtual void input(GameEvent&& input) = 0;
    virtual void update(UpdateData&& updatedata) = 0;
    virtual void display() const = 0;
    virtual void recalculate(const microsec& timestamp) = 0;

    void setBPMSections(const std::set<BPMSection, BPMSectionComparator>& sections) noexcept
    {
        _bpm_sections = sections;
    }

    void setBPMSections(std::set<BPMSection, BPMSectionComparator>&& sections) noexcept
    {
        _bpm_sections = std::move(sections);
    }

    bool insertBPMSection(const BPMSection& section)
    {
        return _bpm_sections.insert(section).second;
    }

    bool insertBPMSection(BPMSection&& section)
    {
        return _bpm_sections.insert(section).second;
    }

    bool removeBPMSectionAt(const microsec& offset)
    {
        auto section_it = std::find_if(_bpm_sections.rbegin(), _bpm_sections.rend(),
                                       [offset](const auto& section)
                                       {
                                           return section.offset_start < offset;
                                       });

        if (section_it != _bpm_sections.rend())
        {
            ++section_it;
            _bpm_sections.erase(section_it.base());

            return true;
        }

        return false;
    }

    BPMSection getBPMSectionAt(const microsec& offset) const
    {
        auto section_it = std::find_if(_bpm_sections.rbegin(), _bpm_sections.rend(),
                                       [offset](const auto& section)
                                       {
                                           return section.offset_start < offset;
                                       });

        if (section_it != _bpm_sections.rend())
        {
            ++section_it;
            return *section_it.base();
        }

        return BPMSection();
    }

    void clearBPMSections() noexcept
    {
        _bpm_sections.clear();
    }

protected:
    std::set<BPMSection, BPMSectionComparator> _bpm_sections;
};

}
