/*
 * SPDX-FileCopyrightText: 2019-2026 Mattia Basaglia <dev@dragon.best>
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#include "glaxnimate/model/shapes/composable/precomp_layer.hpp"

#include <QPainter>

#include "glaxnimate/model/document.hpp"
#include "glaxnimate/model/assets/composition.hpp"
#include "glaxnimate/model/assets/assets.hpp"

GLAXNIMATE_OBJECT_IMPL(glaxnimate::model::PreCompLayer)


QIcon glaxnimate::model::PreCompLayer::tree_icon() const
{
    return QIcon::fromTheme("component");
}

QString glaxnimate::model::PreCompLayer::type_name_human() const
{
    return i18n("Composition Layer");
}

glaxnimate::model::FrameTime glaxnimate::model::PreCompLayer::relative_time(glaxnimate::model::FrameTime time) const
{
    return timing->time_to_local(time);
}

void glaxnimate::model::PreCompLayer::set_time(glaxnimate::model::FrameTime t)
{
    ShapeElement::set_time(relative_time(t));
    Q_EMIT document()->graphics_invalidated();
}

std::vector<glaxnimate::model::DocumentNode *> glaxnimate::model::PreCompLayer::valid_precomps() const
{
    auto comps = document()->comp_graph().possible_descendants(owner_composition(), document());
    return std::vector<glaxnimate::model::DocumentNode *>(comps.begin(), comps.end());
}

bool glaxnimate::model::PreCompLayer::is_valid_precomp(glaxnimate::model::DocumentNode* node) const
{
    auto owncomp = owner_composition();
    if ( auto precomp = qobject_cast<glaxnimate::model::Composition*>(node) )
        return !document()->comp_graph().is_ancestor_of(precomp, owncomp);
    return false;
}

void glaxnimate::model::PreCompLayer::on_paint(renderer::Renderer* painter, glaxnimate::model::FrameTime time, glaxnimate::model::VisualNode::PaintMode mode, glaxnimate::model::Modifier* mod) const
{
    if ( composition.get() )
    {
        time = timing->time_to_local(time);
        Composable::on_paint(painter, time, mode, mod);
        if ( !unbounded.get() )
            painter->clip_rect(QRectF(QPointF(0, 0), size.get()));
        composition->paint(painter, time, mode);
    }
}

QRectF glaxnimate::model::PreCompLayer::local_bounding_rect(FrameTime) const
{
    return QRectF(QPointF(0, 0), size.get());
}

QTransform glaxnimate::model::PreCompLayer::local_transform_matrix(glaxnimate::model::FrameTime t) const
{
    return transform.get()->transform_matrix(t);
}

void glaxnimate::model::PreCompLayer::add_shapes(glaxnimate::model::FrameTime, math::bezier::MultiBezier&, const QTransform&) const
{
}

void glaxnimate::model::PreCompLayer::on_composition_changed(model::Composition* old_comp, model::Composition* new_comp)
{
    if ( old_comp )
        document()->comp_graph().remove_connection(old_comp, this);

    if ( new_comp )
        document()->comp_graph().add_connection(new_comp, this);

    if ( composition.get() )
    {
        if ( !new_comp )
            composition->remove_user(&composition);
        else if ( !old_comp )
            composition->add_user(&composition);
    }
}

glaxnimate::math::bezier::MultiBezier glaxnimate::model::PreCompLayer::to_painter_path_impl(glaxnimate::model::FrameTime time) const
{
    glaxnimate::math::bezier::MultiBezier p;
    if ( composition.get() )
    {
        time = timing->time_to_local(time);
        for ( const auto& sh : composition->shapes )
            p.append(sh->to_clip(time));
    }
    return p;
}

glaxnimate::math::bezier::MultiBezier glaxnimate::model::PreCompLayer::to_clip(glaxnimate::model::FrameTime time) const
{
    return to_painter_path(time).transformed(transform.get()->transform_matrix(time));
}
