#ifndef QFITSSINGLEBUFFER_H
#define QFITSSINGLEBUFFER_H

#include <QWidget>
#include "QFitsBaseBuffer.h"
#include <defines.h>

class QFitsMainView;
class QFitsBaseWidget;
class Fits;
class QFitsMultiBuffer;
class QFitsWidget1D;
class QFitsWidget2D;
class QFitsMarkers;
class cameraSettings;
class QFitsWidget3D;

//
// Single buffer implementation, contains one QFitsBaseWidget
//
class QFitsSingleBuffer : public QFitsBaseBuffer {
    Q_OBJECT
//----- Functions -----
public:
    QFitsSingleBuffer(QFitsMainView*, dpuserType*, int dbg, QString dbg_upper);
    QFitsSingleBuffer(QFitsMultiBuffer*, dpuserType*, int dbg, QString dbg_upper);
    ~QFitsSingleBuffer();
    void init(dpuserType*, int dbg, QString dbg_upper);

    void activateBuffer();
    BufferAppearance updateAppearance();

    void imageToWidget(int*, int*);
    double calcZoomFitWindow(int, int, FitZoom);
    dpint64 Naxis(int);
    void setMouseTrackingView(bool, bool traceUp = false);
    bool isEmptyPrimary();
    void rotImage(bool);
    void lockSB(bool, int x = 0, int y = 0);
    void transCoordImage2Widget(double*, double*, double/*, bool doRotFlip = true*/);
    void transCoordWidget2Image(double*, double*, double, int, bool doRotFlip = true);

    // nasty functions, can we get rif of it?
    // Then nasty connect in constructor of QFitsWidget3D would be obsolete
    QFitsWidget2D* getQFitsWidget2D();
    QFitsMarkers* getSourceMarkers();
    void calculateMinMax(Fits *work);
    void resizeEvent(QResizeEvent*);

    //
    // implementations of abstract base functions
    //
    void ResetSpectrum();
    void ChangeWidgetState(dpViewMode);
    void zoomTextChanged(double, FitZoom);
    void showCubePlot();
    void updateLinemapDialog();
    void saveImage();
    void saveFits();
    void saveFitsImage();
    void printImage();
    void setZoomWidget(double);
    void updateScaling();
    void enableMovie(bool);
    void setXRange();
    void setYRange();
    void setYRange(const double &, const double &);
    void setData();
    void newData3D();
    void setMovieSpeed(int);
    void setImageCenter(double, double);
    void setIgnore(bool, double);
    void copyImage(int);
    void setFocus();
    void setLinemapOptions(bool, bool, int, int, int, int, int, int);
    QFitsBaseWidget* getState();
    void updateCubeMode();
    QFitsSingleBuffer* getFirstImageBuffer();
    bool showSpectrum();
    void createManualSpectrum();

    //
    // get/set functions
    //
    QFitsMultiBuffer* getMyMultiBuffer()    { return myMultiBuffer; }
    Fits*   getCubeDisplay2D()              { return cubeDisplay2D; }
    Fits*   getManualSpectrum()             { return manualSpectrum; }
    QImage* getImage()                      { return image; }
    void    setImage(QImage *i)             { image = i; }
    void    orientationChanged();
    void    setRotationVal(int r)           { rotation = r; }
    void    setDpData(dpuserType *d)        { dpData = d; }
    double  getIgnoreValue()                { return ignoreValue; }
    double  getWidthVisible()               { return widthVisible; }
    void    setWidthVisible(double w)       { widthVisible = w; }
    double  getHeightVisible()              { return heightVisible; }
    void    setHeightVisible(double h)      { heightVisible = h; }
    double  getXcenter()                    { return xcenter; }
    void    setXcenter(double x)            { xcenter = x; /*printf("SET SET\nSET SET XXXX %g\nSET SET\n", xcenter);fflush(stdout);*/}
    double  getYcenter()                    { return ycenter; }
    void    setYcenter(double y)            { ycenter = y; /*printf("SET SET\nSET SET YYYYY %g\nSET SET\n", ycenter);fflush(stdout);*/}
    bool    getIgnoreInCube()               { return ignoreInCube; }
    bool    getHasManualSpectrum()          { return hasManualSpectrum; }

    //
    // get/set functions (overrides for QFitsBaseBuffer)
    //
    void    setImageScaleRange(dpScaleMode mode);
    void    setColormap(QAction*);
    void    setBrightness(int b, bool sbInitialized = true);
    void    setContrast(int c, bool sbInitialized = true);
    void    setBrightnessContrast(int b, int c, bool sbInitialized = true);
    void    setImageScalingMethod(int, bool sbInitialized = true);
    void    setRotation(int);
    void    setInvertColormap(bool);
    void    setFlipX(bool);
    void    setFlipY(bool);
    QFitsMarkers* getCursorMarkers();
    int     getSpecChannelMinX();
    void    setSpecChannelMinX(int);
    int     getSpecChannelMaxX();
    void    setSpecChannelMaxX(int);
    double  getSpecPhysMinX();
    void    setSpecPhysMinX(double);
    double  getSpecPhysMaxX();
    void    setSpecPhysMaxX(double);
    double  getSpecPhysMinY();
    double  getSpecPhysMaxY();
    void    setSpecPhysRangeY(double, double);
    double  getImageMinValue();
    void    setImageMinValue(double);
    double  getImageMaxValue();
    void    setImageMaxValue(double);
    void    setCubeSpecOrientation(QFV::Orientation, bool allSB = false);
    double  getCubeCenter(QFV::Orientation);
    void    setCubeCenter(double, QFV::Orientation, bool allSB = false);
    double  getLineWidth(QFV::Orientation o);
    void    setLineWidth(double, QFV::Orientation, bool allSB = false);
    int     getLineCont1Center();
    void    setLineCont1Center(int);
    int     getLineCont1Width();
    void    setLineCont1Width(int);
    int     getLineCont2Center();
    void    setLineCont2Center(int);
    int     getLineCont2Width();
    void    setLineCont2Width(int);
    bool    getLineCont1();
    void    setLineCont1(bool);
    bool    getLineCont2();
    void    setLineCont2(bool);
    BufferAppearance getAppearance();

    //
    // 3D view stuff
    //
#ifdef HAS_VTK
    QFitsWidget3D* getQFitsWidget3D(bool create = false);
    void new3Ddata();
    void new3Ddata2();

//    cameraSettings* getCamSettings()        { return camSettings; }
//    void setCamSettings(cameraSettings *c)  { camSettings = c; }

//    bool getFirstView3D()                   { return firstView3D; }
//    void setFirstView3D(bool f)             { firstView3D = f; }
//    int  getZoom3D()                        { return zoom3D; }
//    void setZoom3D(int z)                   { zoom3D = z; }
#endif

protected:
    void setupColours();

private:
    void ScaleImage();
    QFitsWidget1D* getQFitsWidget1D();
    void copyScaledData2Image(Fits *work);
    void ResetContinuum();

//----- Slots -----
//----- Signals -----
//----- Members -----
private:
    QFitsBaseWidget         *widgetState,
                            *prevWidgetState;
    QList<QFitsBaseWidget*> widgetList;

    Fits                    *cubeDisplay2D,     // the 2D view for 3D data
                                                // the 1D view for 3D data can be found in QFitsBaseBuffer
                            *manualSpectrum;    // green spectrum displayed in
                                                // QFitsCubeSpectrum

    // 2D view stuff
    QImage                  *image;             // image for displaying in View2D (rotated/flipped)
    double                  ignoreValue,
                            widthVisible,       // generally widget coords, except when completely visible (--> then image coords), or for View3D, ViewContour etc...
                            heightVisible,
                            xcenter,
                            ycenter;
    bool                    ignoreInCube,
                            hasManualSpectrum;

//#ifdef HAS_VTK
//    cameraSettings          *camSettings;
//    bool                    firstView3D;
//    int                     zoom3D;
//#endif
};

#endif // QFITSSINGLEBUFFER_H
