/***************************************************************************
        OverViewCache.h  -  fast cache for sample data overview
                             -------------------
    begin                : Mon May 20 2002
    copyright            : (C) 2000 by Thomas Eschenbacher
    email                : Thomas.Eschenbacher@gmx.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef OVER_VIEW_CACHE_H
#define OVER_VIEW_CACHE_H

#include "config.h"
#include "libkwavegui_export.h"

#include <QtGlobal>
#include <QHash>
#include <QImage>
#include <QList>
#include <QObject>
#include <QRecursiveMutex>
#include <QUuid>
#include <QVector>

#include "libkwave/Sample.h"

#include "libgui/SelectionTracker.h"

class QColor;

namespace Kwave
{

    class SignalManager;
    class Track;

    /**
     * @class OverViewCache
     * Fixed-size cache for multi-track sample data. Automatically updates
     * itself if data has been changed, inserted or deleted.
     * Optimized for speed!
     */
    class LIBKWAVEGUI_EXPORT OverViewCache: public QObject
    {
        Q_OBJECT
    public:

        typedef struct {
            sample_t min;
            sample_t max;
        } MinMax;

        typedef QVector<MinMax> MinMaxArray;

        /**
         * Constructor
         * @param signal reference to a SignalManager with the source
         * @param src_offset first sample index in the source.
         *                   optional, default=0
         * @param src_length number of samples in the source.
         *                   optional, default=0 (whole signal)
         * @param src_tracks list of selected source tracks
         *                   optional, default=0 (whole signal)
         */
        OverViewCache(Kwave::SignalManager &signal,
                      sample_index_t src_offset,
                      sample_index_t src_length,
                      const QVector<unsigned int> *src_tracks);

        /** Destructor */
        ~OverViewCache() override;

        /**
         * Get an array with min/max sample values
         * @param width number of min/max entries to fill
         * @param minmax array that receives the minmax values
         * @return number of successfully filled min/max entries
         */
        int getMinMax(int width, MinMaxArray &minmax);

        /**
         * Renders an overview into a QImage.
         * @param width the width of the bitmap in pixels
         * @param height the width of the bitmap in pixels
         * @param fg foreground color
         * @param bg background color
         * @param gain additional y scaling factor (optional, default = 1.0)
         * @return the created bitmap
         */
        virtual QImage getOverView(int width, int height,
                                   const QColor &fg, const QColor &bg,
                                   double gain = 1.0);

    signals:

        /** emitted whenever the cache content has changed */
        void changed();

    protected slots:

        /**
         * Connected to the selection tracker's sigTrackInserted.
         * @param track_id unique ID of the track
         * @see SelectionTracker::sigTrackInserted
         */
        void slotTrackInserted(const QUuid &track_id);

        /**
         * Connected to the selection tracker's sigTrackInserted.
         * @param track_id unique ID of the track
         * @see SelectionTracker::sigTrackDeleted
         */
        void slotTrackDeleted(const QUuid &track_id);

        /**
         * Connected to the selection tracker's sigLengthChanged.
         * @param new_length new length of the selection in samples
         * @see SelectionTracker::sigLengthChanged
         */
        void slotLengthChanged(sample_index_t new_length);

        /**
         * Connected to the selection tracker's sigInvalidated.
         * @param track_id UUID of the track or null for "all tracks"
         * @param first index of the first invalidated sample
         * @param last index of the last invalidated sample
         */
        void slotInvalidated(const QUuid *track_id,
                             sample_index_t first,
                             sample_index_t last);

    protected:

        /** State of a cache entry */
        typedef enum {
            Invalid = 0,
            Fuzzy,
            Valid,
            Unused
        } CacheState;

    private:

        /**
         * Compresses the cache to hold more samples per entry.
         */
        void scaleUp();

        /**
         * Expands the cache to hold less samples per entry. As this
         * process loses accuracy, the cache must be "polished" in
         * a second step.
         */
        void scaleDown();

        /**
         * Marks a range of cache entries of a track as invalid
         * @param uuid ID of the track to invalidate or null for "all tracks"
         * @param first index of the first entry
         * @param last index of the last entry
         *             (will be truncated to CACHE_SIZE-1)
         */
        void invalidateCache(const QUuid *uuid,
                             unsigned int first,
                             unsigned int last);

    private:

        /** signal with the data to be shown */
        Kwave::SignalManager &m_signal;

        /** selection tracker */
        Kwave::SelectionTracker m_selection;

        /** list of minimum value arrays, one array per track */
        QHash<QUuid, QVector <sample_t> > m_min;

        /** list of maximum value arrays, one array per track */
        QHash<QUuid, QVector <sample_t> > m_max;

        /** bitmask for "validity" of the min/max values */
        QHash<QUuid, QVector <CacheState> > m_state;

        /** list of min/max pairs, cached internally for getOverView */
        MinMaxArray m_minmax;

        /** number of samples per cache entry */
        quint64 m_scale;

        /** mutex for threadsafe access to the cache */
        QRecursiveMutex m_lock;

    };
}

#endif // _OVER_VIEW_CACHE_H_

//***************************************************************************
//***************************************************************************
