/*
 * QtGl.h
 *
 *  Created on: Jul 20, 2011
 *      Author: lyard
 */

#ifndef QTGL_H_
#define QTGL_H_

#define NBOARDS      40      // max. number of boards
#define NPIX       1440      // max. number of pixels
#define NTMARK      160      // max. number of timeMarker signals

//#define LOAD_RAW

#include <QtCore/QObject>
#include <QtCore/QTimer>
#include <QtGui/QLabel>
#include <QtGui/QListWidget>
#include <QtGui/QMainWindow>
#include <QtOpenGL/QGLWidget>
#include <QtGui/QMouseEvent>
#include <QtGui/QColorDialog>
#include <QtGui/QApplication>
#include <QtGui/QSpinBox>
#include <QtGui/QDoubleSpinBox>
#include <QtGui/QRadioButton>
#include <iostream>
#include <GL/gl.h>

#include "qwt_plot.h"
#include "qwt_plot_histogram.h"
#include "qwt_plot_curve.h"

#include <qwt_plot_zoomer.h>


//#define __MARS__
//#include "MFits.h"
#include <string>
#include "fits.h"

using namespace std;

#define NUM_STORED_EVENTS 5
#define MAX_NUM_PIXELS 1600
#define ACTUAL_NUM_PIXELS 1440

///structure for storing edges of hexagons (for blurry display)
struct edge
{
    int first;
    int second;
};

///structure for storing neighbors of pixels. For camera position calculation and blurry display
struct PixelsNeighbors
{
    //neighbors. clockwise, starting from top
    int neighbors[6];
    PixelsNeighbors()
    {
        for (int i=0;i<6;i++)
            neighbors[i] = -1;
    }
    int& operator[](int index){return neighbors[index];}
};

/*************************************************
 * Class Raw Data Viewer. FACT raw data diplayer
 *************************************************/
class RawDataViewer : public QGLWidget
{
    Q_OBJECT

    friend class UIConnector;
public:
    RawDataViewer(QWidget *parent = 0);
    ~RawDataViewer();
    void openFile(string& filename);

public Q_SLOTS:
    void plusEvent();
    void minusEvent();
    void setEventStep(int step);
    void nextSlice();
    void previousSlice();

Q_SIGNALS:
    void signalCurrentEvent(int event);
    void signalCurrentSlice(int slice);
    void newFileLoaded();
    void signalCurrentPixel(int pixel);

protected:
    void initializeGL();
    void resizeGL(int width, int height);
    void paintGL();
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mouseDoubleClickEvent(QMouseEvent *event);

private:
    void drawCamera(bool alsoWire);
    void drawPixelCurve();
    void drawPatches();
    int PixelAtPosition(const QPoint &pos);
    void updateNeighbors(int currentPixel);
    void skipPixels(int start, int howMany);
    void calculatePixelsCoords();
    void drawHexagon(int index, bool solid);
    void setCorrectSlice(QMouseEvent* event);
    void eventStepping(bool plus);
    void buildVerticesList();
    void buildPatchesIndices();
    void calcBlurColor(int pixel, int vertex);
    void drawBlurryHexagon(int index);
    float hexRadius;
    float hexTolerance;
    float viewSize;
    int whichSlice;
    int selectedPixel;
    float pixelSize;
    float shownSizex;
    float shownSizey;
    bool drawPatch;
    bool drawImpulse;
    bool drawBlur;
    bool loopCurrentEvent;
    //allocate the maximum size for one event
    int16_t *eventData;
    uint32_t boardTime[NBOARDS];
    int16_t startPix[NPIX];
    int16_t startTM[NTMARK];
    uint32_t pcTime;
    uint32_t softTrig;
    uint16_t triggerType;
    int nRows;
    int rowNum;
    int eventNum;
    int nRoi;
    int nRoiTM;
    int runNumber;
    int nTM;
    int runType;
    int firstDataTime;
    int lastDataTime;
    int revision;
    int builderVersion;
    int nBoards;
    int nPixels;
    string timeSystem;
    string creationDate;
    int nightInt;
    string camera;
    string daq;
    float adcCount;
    int nbOk;
    int nbRej;
    int nbBad;

    int eventStep;

    int hardwareMapping[1440];
    int softwareMapping[1440];
    int patches[160][9];
    GLfloat patchesColor[160][3];
    vector<edge> patchesIndices[160];
    fits* inputFile;

    QPoint lastPos;

    GLfloat pixelsCoords[MAX_NUM_PIXELS][3];
    PixelsNeighbors neighbors[MAX_NUM_PIXELS];
    GLfloat pixelsColor[ACTUAL_NUM_PIXELS][3];
    GLfloat verticesList[ACTUAL_NUM_PIXELS*6][2];
    int verticesIndices[ACTUAL_NUM_PIXELS][6];
    int numVertices;
};
/*************************************************
 * Class UIConnector. used to connect the interface to the raw data displayer
 *************************************************/
class UIConnector : public QObject
{
    Q_OBJECT
public:
    UIConnector(QWidget *parent = 0);
    void setViewer(RawDataViewer* v);

public Q_SLOTS:
    void loadNewFileClicked();
    void fileSelected(QString file);
    void drawPatchesCheckChange(int state);
    void drawImpulseCheckChange(int state);
    void drawBlurCheckChange(int state);
    void loopEventCheckChange(int state);
    void newFileLoaded();
    void playPauseClicked();
    void slicesPerSecondChanged(double value);
    void nextSlicePlease();
    void currentSliceHasChanged(int slice);
    void currentEventHasChanged(int event);
    void rangeChanged0(double value);
    void rangeChanged1(double value);
    void rangeChanged2(double value);
    void rangeChanged3(double value);
    void rangeChanged4(double value);
    void redChanged0(double value);
    void redChanged1(double value);
    void redChanged2(double value);
    void redChanged3(double value);
    void redChanged4(double value);
    void greenChanged0(double value);
    void greenChanged1(double value);
    void greenChanged2(double value);
    void greenChanged3(double value);
    void greenChanged4(double value);
    void blueChanged0(double value);
    void blueChanged1(double value);
    void blueChanged2(double value);
    void blueChanged3(double value);
    void blueChanged4(double value);
    void pixelChanged(int pixel);
    void hwIDChanged(int hwid);
    void swIDChanged(int swid);
    void crateIDChanged(int cid);
    void boardIDChanged(int bid);
    void patchIDChanged(int pid);
    void autoScalePressed();
    void entireCameraChanged(bool state);
    void currentPixelChanged(bool state);
    void slicesPlusPlus();
    void slicesMinusMinus();

Q_SIGNALS:
    void updateCurrentSliceDisplay(QString);
    void updateCurrentEventDisplay(QString);
    void updateCurrentPCTime(QString);
    void updateCurrentSoftTrigger(QString);
    void updateCurrentTriggerType(QString);
    void updateCurrentPixelSliceValue(QString);


private:
    RawDataViewer* viewer;
    QTimer timer;
    string currentFile;
    int crateID;
    int boardID;
    int patchID;
    int hwID;
    int swID;
    bool rescaleWholeCamera;
public:
    QListWidget *boardsTimeList;
    QListWidget* startPixelsList;
    QListWidget* startTimeMarksList;
//   QLabel*      fileLoadedLabel;
//    QLabel*      runNumberLabel;
//    QLabel*      numberOfSlicesLabel;
//    QLabel*      numberOfTimeMarksLabel;
//    QLabel*      runTypeLabel;
//    QLabel*      firstTimeLabel;
//    QLabel*      lastTimeLabel;
    QLabel*      currentPixelValue;
    QLabel*      extraInfoLabel;

    QwtPlot*     boardsTimeHisto;
    QwtPlot*     startCellHisto;
    QwtPlot*     startTimeMarkHisto;
    QwtPlot*     pixelValueCurve;
    QwtPlotHistogram boardsTimeHistoItem;
    QwtPlotHistogram startCellHistoItem;
    QwtPlotHistogram startTimeMarkHistoItem;
    QwtPlotCurve     pixelValueCurveItem;
    QwtPlotZoomer* curveZoom;
    QwtPlotZoomer* boardsTimeHistoZoom;
    QwtPlotZoomer* startCellHistoZoom;
    QwtPlotZoomer* startTimeMarkHistoZoom;

    QwtPlot*        triggerDelayHisto;
    QwtPlotHistogram triggerDelayHistoItem;
    QwtPlotZoomer* triggerDelayHistoZoom;
    QListWidget* triggerDelayList;

    QSpinBox*   HwIDBox;
    QSpinBox*   SwIDBox;
    QSpinBox*   crateIDBox;
    QSpinBox*   boardIDBox;
    QSpinBox*   patchIDBox;

    QRadioButton* currentPixelScale;
    QRadioButton* entireCameraScale;

    QDoubleSpinBox* range0;
    QDoubleSpinBox* range1;
    QDoubleSpinBox* range2;
    QDoubleSpinBox* range3;
    QDoubleSpinBox* range4;

    void initHistograms();

};

#endif /* QTGL_H_ */
