/*
 *
 *    soniK digital audio editor
 *    Copyright (C) 2003-2006  Robert Walker <rob@tenfoot.org.uk>
 *
 *    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.
 *
 *    This program 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 this program; if not, write to the Free Software
 *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
#ifndef SONIK_SPECTRAL_DISPLAY_PLUGIN_H
#define SONIK_SPECTRAL_DISPLAY_PLUGIN_H

#include "display.h"
#include "wavewidget.h"

#include "sonik_sigproc.h"

#include <klibloader.h>

#include <qbrush.h>
#include <qpen.h>

class SpectralDisplayConfigDlg;

namespace Sonik
{
  class SpectralDisplay : public Sonik::Display
  {
    Q_OBJECT
  public:
    static const size_t kColourmapSize = 256;
    struct ColourValue
    {
      unsigned char r;
      unsigned char g;
      unsigned char b;
    };

    class Widget : public Sonik::WaveWidget
    {
    public:
      static const size_t kMinWindowSize = 32;
      static const size_t kMaxWindowSize = 1024;

      Widget(const SpectralDisplay& display,
             const Data& data, uint8_t channel,
             QWidget* parent = 0, const char* name = 0);
      virtual ~Widget();

    protected:
      virtual void render(QPainter& p, const QRect& r);
      virtual void clearCache(CacheClearOp op, off_t start, size_t length);

    private:
      // Cache data is keyed on:
      //   (window function, window size)[(window pos % windowSize/2)]
      struct CacheKey
      {
        CacheKey() : wf(Sonik::UNKNOWN), ws(0) { }
        CacheKey(WindowFunction _wf, size_t _ws) : wf(_wf), ws(_ws) { }

        bool operator==(const CacheKey& r) const;
        bool operator<(const CacheKey& r) const;

        WindowFunction wf;
        size_t ws;
      };
      typedef QValueVector<float*> CacheData;
      typedef QMap<CacheKey, CacheData > Cache;

      float* getSpectrum(size_t ws, off_t pos);

      void drawSpectrums(QPainter& p, const QRect& r, uint start, uint end);
      void drawSliceScaleDown(QPainter& p,
                              int x, int y, int w, int h,
                              float* spect, size_t spectSize, double scale);
      void drawSliceScaleUp(QPainter& p,
                            int x, int y, int w, int h,
                            float* spect, size_t spectSize, double step);
      void drawSelection(QPainter& p, const QRect& r, uint start, uint end);

      const SpectralDisplay& mDisplay;

      Cache mCache;

      size_t           mLastWindowSize;
      WindowFunction   mLastWindowFunction;
      Sonik::FFTParms* mFftParms;
      SampleBuffer     mWindow;
    };

    SpectralDisplay(QObject* parent, const char* name, const QStringList& args);
    virtual ~SpectralDisplay();

    virtual WaveWidget* makeWidget(const Data& data,
                                   uint8_t channel,
                                   QWidget* parent = 0,
                                   const char* name = 0) const;

    virtual VerticalAxis verticalAxis() const { return Display::kFreq; }
    virtual uint32_t verticalBorder() const   { return 0; }

    WindowFunction windowFunction() const { return mWindowFunction; }
    size_t         windowSize() const     { return mWindowSize; }
    const QBrush&  selectColour() const   { return mSelectColour; }
    const QBrush*  brushColourmap() const { return mBrushColourmap; }
    const QPen*    penColourmap() const   { return mPenColourmap; }

    virtual QWidget* makeConfigPage(QWidget* parent=0);
    virtual void     applyConfigPage();

  private:
    void applyConfig();
    void buildColourmap(const ColourValue *map);

    SpectralDisplayConfigDlg *mConfigDlg;

    size_t         mWindowSize;
    QBrush         mSelectColour;
    WindowFunction mWindowFunction;
    QString        mColourmapName;
    QBrush         mBrushColourmap[kColourmapSize];
    QPen           mPenColourmap[kColourmapSize];
  };
}

#endif // SONIK_SPECTRAL_DISPLAY_PLUGIN_H
