/* This file is part of the KDE project

   SPDX-FileCopyrightText: 2006-2008 Thorsten Zachmann <zachmann@kde.org>
   SPDX-FileCopyrightText: 2006-2010 Thomas Zander <zander@kde.org>
   SPDX-FileCopyrightText: 2009-2010 Jan Hambrecht <jaham@gmx.net>

   SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef KoShapeManager_p_h
#define KoShapeManager_p_h

#include "KoCanvasBase.h"
#include "KoClipPath.h"
#include "KoFilterEffect.h"
#include "KoFilterEffectRenderContext.h"
#include "KoFilterEffectStack.h"
#include "KoPointerEvent.h"
#include "KoSelection.h"
#include "KoShape.h"
#include "KoShapeBackground.h"
#include "KoShapeContainer.h"
#include "KoShapeGroup.h"
#include "KoShapeLayer.h"
#include "KoShapeManager.h"
#include "KoShapeManagerPaintingStrategy.h"
#include "KoShapePaintingContext.h"
#include "KoShapeShadow.h"
#include "KoShapeStrokeModel.h"
#include "KoShape_p.h"
#include "KoToolProxy.h"
#include <KoRTree.h>

#include <FlakeDebug.h>
#include <QPainter>
#include <QTimer>

class Q_DECL_HIDDEN KoShapeManager::Private
{
public:
    Private(KoShapeManager *shapeManager, KoCanvasBase *c)
        : selection(new KoSelection())
        , canvas(c)
        , tree(4, 2)
        , strategy(new KoShapeManagerPaintingStrategy(shapeManager))
        , q(shapeManager)
    {
    }

    ~Private()
    {
        delete selection;
        delete strategy;
    }

    /**
     * Update the tree when there are shapes in m_aggregate4update. This is done so not all
     * updates to the tree are done when they are asked for but when they are needed.
     */
    void updateTree();

    /**
     * Recursively paints the given group shape to the specified painter
     * This is needed for filter effects on group shapes where the filter effect
     * applies to all the children of the group shape at once
     */
    void paintGroup(KoShapeGroup *group, QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext);

    class DetectCollision
    {
    public:
        DetectCollision() = default;
        void detect(KoRTree<KoShape *> &tree, KoShape *s, int prevZIndex)
        {
            foreach (KoShape *shape, tree.intersects(s->boundingRect())) {
                bool isChild = false;
                KoShapeContainer *parent = s->parent();
                while (parent && !isChild) {
                    if (parent == shape)
                        isChild = true;
                    parent = parent->parent();
                }
                if (isChild)
                    continue;
                if (s->zIndex() <= shape->zIndex() && prevZIndex <= shape->zIndex())
                    // Moving a shape will only make it collide with shapes below it.
                    continue;
                if (shape->collisionDetection() && !shapesWithCollisionDetection.contains(shape))
                    shapesWithCollisionDetection.append(shape);
            }
        }

        void fireSignals()
        {
            foreach (KoShape *shape, shapesWithCollisionDetection)
                shape->priv()->shapeChanged(KoShape::CollisionDetected);
        }

    private:
        QList<KoShape *> shapesWithCollisionDetection;
    };

    QList<KoShape *> shapes;
    QList<KoShape *> additionalShapes; // these are shapes that are only handled for updates
    KoSelection *selection;
    KoCanvasBase *canvas;
    KoRTree<KoShape *> tree;
    QSet<KoShape *> aggregate4update;
    QHash<KoShape *, int> shapeIndexesBeforeUpdate;
    KoShapeManagerPaintingStrategy *strategy;
    KoShapeManager *q;
};

#endif
