#ifndef QFITSBASEBUFFER_H
#define QFITSBASEBUFFER_H

#include <QWidget>
#include "QFitsGlobal.h"
#include "QFitsMainView.h"
#include "dpuserType.h"

class QFitsMarkers;
class QFitsSingleBuffer;
class QFitsMultiBuffer;
class QFitsBaseWidget;

//
// Abstract Base class
// contains the state of the Fits to display
//
class QFitsBaseBuffer : public QWidget {
    Q_OBJECT
//----- Functions -----
public:
    QFitsBaseBuffer(QFitsMainView*);
    QFitsBaseBuffer(QFitsMultiBuffer*);
    virtual ~QFitsBaseBuffer();
    void init(int dbg_nr, QString dbg_upper);

    virtual void activateBuffer();
    virtual BufferAppearance updateAppearance();
    std::string  getBufferIndex();
    void         setOrientation(int r, bool flip, bool flop);
    void         notifyCombiner();
    bool         isMultiBufferChild();
    int          indexOfMultiBuffer();
    QString      getExtensionIndicesString();
    QVector<int> getExtensionIndicesVec();
    void         incZoom()                      { zoom++; }
    void         decZoom()                      { zoom--; }
    void         incZoom_3Dwire()               { zoom_3Dwire++; }
    void         decZoom_3Dwire()               { zoom_3Dwire--; }
    double       getZoomFactor();
    virtual void setZoomFactor(double);
    double       getZoomFactor_3Dwire();
    void         setZoomFactor_3Dwire(double);

    virtual void saveImage()        {}
    virtual void saveFits()         {}
    virtual void saveFitsImage()    {}
    virtual void printImage()       {}

    //
    // abstract functions
    //
    virtual void ResetSpectrum()                                             = 0;
    virtual void ChangeWidgetState(dpViewMode)                               = 0;
    virtual void zoomTextChanged(double, FitZoom)                            = 0;
    virtual void showCubePlot()                                              = 0;
    virtual void updateLinemapDialog()                                       = 0;
    virtual void setZoomWidget(double)                                       = 0;
    virtual void orientationChanged()                                        = 0;
    virtual void updateScaling()                                             = 0;
    virtual void enableMovie(bool)                                           = 0;
    virtual void setXRange()                                                 = 0;
    virtual void setYRange()                                                 = 0;
    virtual void setYRange(const double &, const double &)                   = 0;
    virtual void setData()                                                   = 0;
    virtual void newData3D()                                                 = 0;
    virtual void setMovieSpeed(int)                                          = 0;
    virtual void setImageCenter(double, double)                              = 0;
    virtual void setIgnore(bool, double)                                     = 0;
    virtual void copyImage(int copymode = 2)                                 = 0;
    virtual void setFocus()                                                  = 0;
    virtual void setLinemapOptions(bool, bool, int, int, int, int, int, int) = 0;
    virtual QFitsBaseWidget* getState()                                      = 0;
    virtual void updateCubeMode()                                            = 0;
    virtual QFitsSingleBuffer* getFirstImageBuffer()                         = 0;
    virtual void setMouseTrackingView(bool, bool traceUp = false)            = 0;

    //
    // get/set functions
    //
    virtual dpuserType* getDpData()                             { return dpData; }
    dpViewMode      getViewMode()                               { return viewMode; }
//    void            setViewMode(dpViewMode vm)                  { viewMode = vm; }
    dpScaleMode     getImageScaleRange()                        { return imageScaleRange; }
    virtual void    setImageScaleRange(dpScaleMode)             = 0;
    dpCubeMode      getCubeMode()                               { return cubeMode; }
    virtual void    setCubeMode(dpCubeMode m, bool allSB = false)  { cubeMode = m; }
    QAction*        getColormap()                               { return colormap; }
    virtual void    setColormap(QAction*)                       = 0;
    int             getBrightness()                             { return brightness; }
    virtual void    setBrightness(int, bool sbInitialized = false) = 0;
    int             getContrast()                               { return contrast; }
    virtual void    setContrast(int, bool sbInitialized = false)   = 0;
    virtual void    setBrightnessContrast(int, int, bool sbInitialized = false) = 0;
    int             getImageScalingMethod()                     { return imageScaleMethod; }
    virtual void    setImageScalingMethod(int, bool sbInitialized = false) = 0;
    int             getRotation()                               { return rotation; }
    virtual void    setRotation(int)                            = 0;
    virtual int     getSpecChannelMinX()                        { return specChannelMinX; }
    virtual void    setSpecChannelMinX(int channelMinX)         { specChannelMinX = channelMinX; }
    virtual int     getSpecChannelMaxX()                        { return specChannelMaxX; }
    virtual void    setSpecChannelMaxX(int channelMaxX)         { specChannelMaxX = channelMaxX; }
    virtual double  getSpecPhysMinX()                           { return specPhysMinX; }
    virtual void    setSpecPhysMinX(double physMinX)            { specPhysMinX = physMinX; }
    virtual double  getSpecPhysMaxX()                           { return specPhysMaxX; }
    virtual void    setSpecPhysMaxX(double physMaxX)            { specPhysMaxX = physMaxX; }
    virtual double  getSpecPhysMinY()                           { return specPhysMinY; }
    virtual void    setSpecPhysRangeY(double min, double max)   { if (min < max) {
                                                                      specPhysMinY = min;
                                                                      specPhysMaxY = max;
                                                                  }
                                                                }
    virtual double  getSpecPhysMaxY()                           { return specPhysMaxY; }
    virtual double  getImageMinValue()                          { return imageMinValue; }
    virtual void    setImageMinValue(double imageMin)           { imageMinValue = imageMin; }
    virtual double  getImageMaxValue()                          { return imageMaxValue; }
    virtual void    setImageMaxValue(double imageMax)           { imageMaxValue = imageMax; }
    bool getInvertColormap()                                    { return invertColormap; }
    virtual void setInvertColormap(bool)                        = 0;
    bool getFlipX()                                             { return flipX; }
    virtual void setFlipX(bool)                                 = 0;
    bool getFlipY()                                             { return flipY; }
    virtual void setFlipY(bool)                                 = 0;
    virtual BufferAppearance getAppearance()                    { return bufAppearance; }
    virtual void setAppearance(BufferAppearance b)              { bufAppearance = b; }
    virtual QFitsMarkers* getCursorMarkers()                    { return cursorSpectrumMarkers; }
    bool getUsedInCombine()                                     { return usedInCombine; }
    void setUsedInCombine(bool s)                               { usedInCombine = s; }
    bool getDirty()                                             { return dirty; }
    void setDirty(bool b)                                       {  dirty = b;}
    virtual bool showSpectrum()                                 = 0;
    virtual void createManualSpectrum()                         = 0;
    bool getHasSpectrum()                                       { return hasSpectrum; }
    bool getHasImage()                                          { return hasImage; }
    bool getHasCube()                                           { return hasCube; }
    bool getHasStrArr()                                         { return hasStrArr; }
    Fits* getCubeDisplay1D();
    void  setCubeDisplay1D(Fits *f);
    QFitsSingleBuffer* getLockedSingleBuffer();
    void setLockedSingleBuffer(QFitsSingleBuffer*);
    QFitsSingleBuffer* getMarkedSingleBuffer();
    void setMarkedSingleBuffer(QFitsSingleBuffer *sb, bool fromLock = false);
    int     mtv_getLastActiveSection();
    QFV::Orientation mtv_getLastActiveOrientation();
    void    mtv_setLastActiveSection(int, QFV::Orientation);
    bool    getHasMixedView()                                   { return hasMixedView; }
    void    mtv_setMinMaxXbrute(int, int);
    QFV::Orientation getCubeSpecOrientation();
    virtual void setCubeSpecOrientation(QFV::Orientation, bool allSBs = false)  = 0;

    void setVisibleTool(ToolsVisible newtool) { bufAppearance.toolsVisible = newtool; }

    // source & continuum stuff
    virtual double  getCubeCenter(QFV::Orientation o);
    virtual void setCubeCenter(double, QFV::Orientation, bool allSB = false)   = 0;
    virtual double  getLineWidth(QFV::Orientation o);
    virtual void setLineWidth(double, QFV::Orientation, bool allSB = false)    = 0;
    virtual int  getLineCont1Center()                           { return linecont1center; }
    virtual void setLineCont1Center(int l)                      { linecont1center = l; }
    virtual int  getLineCont1Width()                            { return linecont1width; }
    virtual void setLineCont1Width(int l)                       { linecont1width = l; }
    virtual int  getLineCont2Center()                           { return linecont2center; }
    virtual void setLineCont2Center(int l)                      { linecont2center = l; }
    virtual int  getLineCont2Width()                            { return linecont2width; }
    virtual void setLineCont2Width(int l)                       { linecont2width = l; }
    virtual bool getLineCont1()                                 { return linecont1; }
    virtual void setLineCont1(bool l)                           { linecont1 = l; }
    virtual bool getLineCont2()                                 { return linecont2; }
    virtual void setLineCont2(bool l)                           { linecont1 = l; }

protected:
    virtual void    setupColours() = 0;
    virtual void    mousePressEvent(QMouseEvent *);
    QVector<QRgb>*  setActualColortable();
    double          convertZoomIndexToDouble(int);
    int             convertZoomDoubleToIndex(double);
    double          adjustZoomValueLower(double);
    double          adjustZoomValuePrecise(double);

private:
    void calculateColortableScaling(QRgb *current2Table, int *bottom, int *top, int *width);

//----- Slots -----
//----- Signals -----
signals:
    void newBrightness(int);
    void newContrast(int);
    void updateCombiner();

//----- Members -----
protected:
    dpuserType          *dpData;         // the fits data or dpStringList
    dpViewMode          viewMode;        // ViewImage, ViewWiregrid, View3D
    dpScaleMode         imageScaleRange; // minmax, 99%, 95%, etc.
    dpCubeMode          cubeMode;        // DisplayCubeSingle, DisplayCubeAverage,
                                         // DisplayCubeMedian, DisplayCubeLinemap
    QAction*            colormap;        // gray, rainbow, bb, etc.
    int                 zoom,            // for 2D View
                        zoom_3Dwire,     // for 3D and Wiregrid view
                        brightness,
                        contrast,
                        imageScaleMethod,
                        rotation,
                        specChannelMinX,
                        specChannelMaxX,
                        mtv_lastActiveSection;
    QFV::Orientation    mtv_lastActiveOrientation;
    double              specPhysMinX,
                        specPhysMaxX,
                        specPhysMinY,
                        specPhysMaxY,
                        imageMinValue,
                        imageMaxValue;
    bool                tableViewDirty,
                        invertColormap,
                        flipX,
                        flipY,
                        hasSpectrum,
                        hasImage,
                        hasCube,
                        hasStrArr,
                        hasMixedView;
    // cube spectrum stuff
    double              *cubeCenter,
                        *lineWidth;
    int                 linecont1center,
                        linecont1width,
                        linecont2center,
                        linecont2width;
    bool                linecont1,
                        linecont2;
    BufferAppearance    bufAppearance;
    QFitsMarkers        *cursorSpectrumMarkers;  // the pixels taken into account
    Fits                *cubeDisplay1D;          // the 1D view for 3D data or
                                                 // spectrum view for QFitsWidgetTable
    QFitsSingleBuffer   *lockedSingleBuffer,
                        *markedSingleBuffer;
    QFitsMultiBuffer    *myMultiBuffer;
    QFV::Orientation    cubeSpecOrientation;

private:
    bool                usedInCombine,
                        dirty;
public:
    QString dbg_level;
    int dbg_nr;
};

#endif // QFITSBASEBUFFER_H
