/*
   This file is part of the KDE project

   Copyright © 2007 Fredrik Höglund <fredrik@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#ifndef DELEGATEANIMATIONHANDLER_P_H
#define DELEGATEANIMATIONHANDLER_P_H

#include <QBasicTimer>
#include <QMap>
#include <QLinkedList>
#include <QPersistentModelIndex>
#include <QStyle>
#include <QTimeLine>
#include <QTime>
#include <QTimer>

class QAbstractItemView;

namespace KIO
{

class CachedRendering : public QObject
{
    Q_OBJECT
public:

    CachedRendering(QStyle::State state, const QSize &size, QModelIndex validityIndex, qreal devicePixelRatio = 1.0);
    bool checkValidity(QStyle::State current) const
    {
        return state == current && valid;
    }

    QStyle::State state;
    QPixmap regular;
    QPixmap hover;

    bool valid;
    QPersistentModelIndex validityIndex;
private Q_SLOTS:
    void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
    void modelReset();
};

class AnimationState
{
public:
    ~AnimationState();
    //Progress of the mouse hovering animation
    qreal hoverProgress() const;
    //Progress of the icon fading animation
    qreal fadeProgress() const;
    //Angle of the painter, to paint the animation for a file job on an item
    qreal jobAnimationAngle() const;

    void setJobAnimation(bool value);
    bool hasJobAnimation() const;

    CachedRendering *cachedRendering() const
    {
        return renderCache;
    }
    //The previous render-cache is deleted, if there was one
    void setCachedRendering(CachedRendering *rendering)
    {
        delete renderCache;
        renderCache = rendering;
    }

    //Returns current cached rendering, and removes it from this state.
    //The caller has the ownership.
    CachedRendering *takeCachedRendering()
    {
        CachedRendering *ret = renderCache;
        renderCache = nullptr;
        return ret;
    }

    CachedRendering *cachedRenderingFadeFrom() const
    {
        return fadeFromRenderCache;
    }
    //The previous render-cache is deleted, if there was one
    void setCachedRenderingFadeFrom(CachedRendering *rendering)
    {
        delete fadeFromRenderCache;
        fadeFromRenderCache = rendering;
        if (rendering) {
            m_fadeProgress = 0;
        } else {
            m_fadeProgress = 1;
        }
    }

private:
    AnimationState(const QModelIndex &index);
    bool update();

    QPersistentModelIndex index;
    QTimeLine::Direction direction;
    bool animating;
    bool jobAnimation;
    qreal progress;
    qreal m_fadeProgress;
    qreal m_jobAnimationAngle;
    QTime time;
    QTime creationTime;
    CachedRendering *renderCache;
    CachedRendering *fadeFromRenderCache;

    friend class DelegateAnimationHandler;
};

class DelegateAnimationHandler : public QObject
{
    Q_OBJECT

    typedef QLinkedList<AnimationState *> AnimationList;
    typedef QMapIterator<const QAbstractItemView *, AnimationList *> AnimationListsIterator;
    typedef QMutableMapIterator<const QAbstractItemView *, AnimationList *> MutableAnimationListsIterator;

public:
    DelegateAnimationHandler(QObject *parent = nullptr);
    ~DelegateAnimationHandler();

    AnimationState *animationState(const QStyleOption &option, const QModelIndex &index, const QAbstractItemView *view);

    void restartAnimation(AnimationState *state);

    void gotNewIcon(const QModelIndex &index);

private Q_SLOTS:
    void viewDeleted(QObject *view);
    void sequenceTimerTimeout();

private:
    void eventuallyStartIteration(QModelIndex index);
    AnimationState *findAnimationState(const QAbstractItemView *view, const QModelIndex &index) const;
    void addAnimationState(AnimationState *state, const QAbstractItemView *view);
    void startAnimation(AnimationState *state);
    int runAnimations(AnimationList *list, const QAbstractItemView *view);
    void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE;
    void setSequenceIndex(int arg1);

private:
    QMap<const QAbstractItemView *, AnimationList *> animationLists;
    QTime fadeInAddTime;
    QBasicTimer timer;
    //Icon sequence handling:
    QPersistentModelIndex sequenceModelIndex;
    QTimer iconSequenceTimer;
    int currentSequenceIndex;
};

}

#endif
