#include "mockclassicnote.h"
#include "graphics/classicgraphicsmanager.h"

// Replace with interface by dependency injection
#include "graphics/classicflyinganimationscenario.h"
#include "graphics/classicdyinganimationscenario.h"
//

#include <iostream>

// A LOT OF CODE DUPLICATES game/arrowclassicnote, DO SOMETHING   D:<

MockClassicNote::MockClassicNote(MockArrowNoteInitializer&& init) :
    Note(init.initializer.perfect_offset),
    _state(State::NONE),
    _context(init.initializer.context)
{
    _elements.resize(init.elements.size());

    for (std::size_t i = 0; i < _elements.size(); ++i)
    {
        _elements[i].coordinates = init.elements[i].coordinates;
        _elements[i].type = init.elements[i].type;

        // Animations will be injected into note.
        _elements[i].animations[State::NONE] = nullptr;
        _elements[i].animations[State::FLYING] = std::make_shared<ClassicFlyingAnimationScenario>();
        _elements[i].animations[State::DYING] = std::make_shared<ClassicDyingAnimationScenario>();
        _elements[i].animations[State::DEAD] = nullptr;
    }
}

bool MockClassicNote::isActive() const
{
    return _state != State::DEAD
        && _state != State::NONE;
}

bool MockClassicNote::isInGame() const
{
    return _state == State::FLYING
        || _state == State::DYING;
}

bool MockClassicNote::shouldRemove() const
{
    return _state == State::DEAD;
}

void MockClassicNote::putToGame(const microsec &music_offset)
{
    _state = State::FLYING;

    std::cout << "Put to game " << this << ": " << music_offset << '\n';

    for (auto& element : _elements)
    {
        element.sprite = _context->graphics_manager->getSprite(element.type);
        element.sprite->setCoordinates(element.coordinates);
        element.sprite->setTrailCoordinates(Coordinates(0.f, 9.f));
        element.animations[_state]->launch(element.sprite, music_offset, offset());
    }
}

void MockClassicNote::update(const microsec &music_offset)
{
    switch (_state)
    {
    default: return;
        break;

    case State::FLYING:
        if (music_offset > offset())
            _state = State::DEAD;
        break;
    }

    for (auto& element : _elements)
        if (element.animations[_state])
            element.animations[_state]->update(music_offset);
}

void MockClassicNote::draw() const
{
    for (std::size_t i = 0; i < _elements.size(); ++i)
    {
        if (i >= 1)
            _context->graphics_manager->drawLine(_elements[i-1].sprite->trailCoordinates(), _elements[i].sprite->trailCoordinates());

        _context->graphics_manager->draw(_elements[i].sprite);
    }
}