/*Copyright (C) 2010-2023 Duncan Deveaux

This file is part of Hikou no mizu.

Hikou no mizu is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Hikou no mizu is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Hikou no mizu.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "ArenaDrawer.hpp"
#include "Arena/Arena.hpp"
#include "Arena/Platform.hpp"
#include "Engines/Resources/TextureManager.hpp"

/////////////////
///ArenaDrawer///
/////////////////
void ArenaDrawer::draw()
{
    m_background.draw();
    for (ArenaDrawer::PlatformDrawer &platform : m_platformDraw)
    {
        platform.update();
        platform.draw();
    }
}

void ArenaDrawer::detach()
{
    m_platformDraw.clear();
    m_background = Sprite();
}

void ArenaDrawer::attachTo(const Arena &arena, TextureManager &textureManager)
{
    m_platformDraw.clear();

    //Load background
    Texture &texture = textureManager.getTexture(arena.getTexturePath());
    const Box &backgroundSrc = arena.getBakgroundSource();

    float textureWidth = static_cast<float>(texture.getWidth()),
          textureHeight = static_cast<float>(texture.getHeight());

    Box subRect;
    subRect.left = (textureWidth > 0.f) ? static_cast<float>(backgroundSrc.left) / textureWidth : 0.f;
    subRect.top = (textureHeight > 0.f) ? static_cast<float>(backgroundSrc.top) / textureHeight : 0.f;
    subRect.width = (textureWidth > 0.f) ? static_cast<float>(backgroundSrc.width) / textureWidth : 1.f;
    subRect.height = (textureHeight > 0.f) ? static_cast<float>(backgroundSrc.height) / textureHeight : 1.f;

    m_background.setTexture(texture);
    m_background.setSubRect(subRect);

    //Resize background to arena size
    if (m_background.getWidth() > 0.f && m_background.getHeight() > 0.f)
    {
        m_background.setXScale(arena.getWidth() / m_background.getWidth());
        m_background.setYScale(arena.getHeight() / m_background.getHeight());
    }

    //Load platforms
    const std::list<Platform> &platforms = arena.getPlatforms();
    m_platformDraw.reserve(platforms.size());

    for (const Platform &platform : platforms)
    {
        ArenaDrawer::PlatformDrawer platformDrawer;
        platformDrawer.attachTo(platform, texture);
        platformDrawer.lockToGrid(false);

        m_platformDraw.push_back(platformDrawer);
    }
}

////////////////////
///PlatformDrawer///
////////////////////
void ArenaDrawer::PlatformDrawer::draw()
{
    //Update matrix
    Drawable::pushMatrix();
    Drawable::updateMatrix();

    m_sprite.draw();

    Drawable::popMatrix();
}

void ArenaDrawer::PlatformDrawer::update()
{
    if (m_platform != nullptr)
    {
        const Box &platformBox = m_platform->getBox();
        setXPosition(platformBox.left);
        setYPosition(platformBox.top + platformBox.height);
    }
}

void ArenaDrawer::PlatformDrawer::attachTo(const Platform &platform, Texture &texture)
{
    m_platform = &platform;

    //Initialize the sprite from the source texture
    const Box &textureSource = platform.getSourceBox();
    float textureWidth = static_cast<float>(texture.getWidth()),
          textureHeight = static_cast<float>(texture.getHeight());

    Box subRect;
    subRect.left = (textureWidth > 0.f) ? static_cast<float>(textureSource.left) / textureWidth : 0.f;
    subRect.top = (textureHeight > 0.f) ? static_cast<float>(textureSource.top) / textureHeight : 0.f;
    subRect.width = (textureWidth > 0.f) ? static_cast<float>(textureSource.width) / textureWidth : 1.f;
    subRect.height = (textureHeight > 0.f) ? static_cast<float>(textureSource.height) / textureHeight : 1.f;

    m_sprite.setTexture(texture);
    m_sprite.setSubRect(subRect);
    m_sprite.lockToGrid(false);

    //Scale the sprite to fit the platform size
    if (m_sprite.getWidth() > 0.f && m_sprite.getHeight() > 0.f)
    {
        m_sprite.setXScale(platform.getDrawSize().x / m_sprite.getWidth());
        m_sprite.setYScale(platform.getDrawSize().y / m_sprite.getHeight());
    }

    //Set the sprite origin relatively to the platform body box
    const Box &bodyBox = platform.getBodyBox();
    m_sprite.setOrigin(bodyBox.left, bodyBox.top + bodyBox.height);
}
