/****************************************************************************
**  SCALASCA    http://www.scalasca.org/                                   **
*****************************************************************************
**  Copyright (c) 1998-2012                                                **
**  Forschungszentrum Juelich GmbH, Juelich Supercomputing Centre          **
**                                                                         **
**  See the file COPYRIGHT in the package base directory for details       **
****************************************************************************/


#ifndef _SYSTEMTOPOLOGYWIDGET_H
#define _SYSTEMTOPOLOGYWIDGET_H

#include <QtGui>
#include <QWidget>
#include <QPainter>
#include <QMouseEvent>
#include <QInputDialog>

#include <vector>
#include <math.h>
#include <iostream>
#include <map>

#include "TreeWidget.h"
#include "Plane.h"
#include "Constants.h"

#include "Cube.h"

class ScrollArea;
class QSettings;

struct ViewFactors {
   ViewFactors() : angleChanged(false), distanceChanged(false), scale(1.) {}
   void reset() {
       angleChanged = false; distanceChanged = false, scale=1.;
   }
   bool angleChanged;
   bool distanceChanged;
   double scale;
};


class SystemTopologyWidget : public QWidget {

   Q_OBJECT


signals:

   //these signals are emitted to update the x/y spin values when the
   //x/y values have been changed internally, in order to update the
   //topology tool bar
   void xAngleChanged(int angle);
   void yAngleChanged(int angle);

public slots:

   //these slots are called when the x/y values
   //have been changed by the corresponding spins
   void setXAngleFromExtern(int angle);
   void setYAngleFromExtern(int angle);

public:

   SystemTopologyWidget(QWidget* widget, unsigned topologyId);
   ~SystemTopologyWidget();

   //some get methods

   int getXAngle();
   int getYAngle();

   //some set methods

   void setSystemTreeWidget(TreeWidget * systemTreeWidget);
   void setScrollArea(ScrollArea* scrollArea);
   void setDimOrder(unsigned dim0, unsigned dim1, unsigned dim2);

   //initialize topology from the cube object
   void initialize(cube::Cube* cube);
   void reinit(bool resetValues = true);
   //re-compute the colors
   void updateColors();
    //re-mark selected items of topology
    void updateSelection();
   //update the colors and repaint
   void displayItems();
   //remove all data
   void cleanUp();
   //rescale the topology sizes such that the topology fits into the
   //scroll widget's window
   void rescalePlane(bool resetValues = true);
   //rescale this widget such that the topology fits into
   void rescaleWidget();
   //compute the width of the topology
   int  getOptimalWidth();

   //save and load topology settings
   void saveSettings(QSettings& settings);
   bool loadSettings(QSettings& settings);

   //methods for the topology tool bar
   void moveDown();
   void moveUp();
   void moveRight();
   void moveLeft();
   void increasePlaneDistance();
   void decreasePlaneDistance();
   void zoomIn();
   void zoomOut();
   void reset(bool resetValues = true);

   //get user-defined minimal and maximal values for the minimal and
   //maximal colors
   void minMaxValues();

   //update the value widget
   void updateValueWidget();

   //set the color for the lines framing processes/threads in the topology
   void setLineType(LineType lineType);

   //toggle the flag if unused planes should be painted or not
   void toggleUnused();

   QWidget *getDimensionSelectionBar();

protected:

   //main painting method
   void paintEvent(QPaintEvent*);

   //mouse and key event handling
   void mousePressEvent(QMouseEvent *event);
   void mouseMoveEvent(QMouseEvent *event);
   void mouseReleaseEvent(QMouseEvent *event);
   void wheelEvent(QWheelEvent *e);
   void keyPressEvent(QKeyEvent *event);
   void keyReleaseEvent(QKeyEvent *event);

private slots:
   void selectedDimensionsChanged(const std::vector<long> &dims);
   void foldingDimensionsChanged(std::vector<std::vector<int> >);

private:

   //the original dimensions
   unsigned dim[3];
   //the current order of the dimension
   unsigned dimToOrigDim[3];
   //which original dimension is at which position currently
   unsigned origDimToDim[3];

   //the cube object for the data
   cube::Cube* cube;

   ScrollArea* scrollArea;
   ColorWidget* colorWidget;
   ValueWidget* valueWidget;
   TreeWidget* systemTreeWidget;

   //the index of this topology in the cube object
   unsigned topologyId;

   //the topology itself: assignment of items to coordinates
   std::vector<std::vector<std::vector<int> > > coordToSystemId;
   // assignment of displayed coordinates to items
    std::map<int, std::vector<std::vector<long> > > systemToCoord;
   // if more than 3 dimensions: assignment of complete coordinates to items
   std::vector<QString> systemToCoordStr;

   // for topologies with more than 3 dimensions:
   // value -1: show all elements, other: show only the given index
   std::vector<long> selectedDimensions;
   // for topologies with 4-6 dims
   int foldingDimensions[3][2];

   //we store only one plane and shift it for paining if several planes are defined
   Plane plane;
   //distance between planes above each other
   double planeDistance;

   //current angles
   int xAngle;
   int yAngle;

   //colors for the topology items
   std::vector<std::vector<std::vector<QColor*> > > colors;
   //flags whether an item is part of selected area or not.
   std::vector<std::vector<std::vector<bool> > > selected_rects;
    
   //for mouse and key event handling
   QPoint lastPoint, firstPoint;
   bool leftMousePressed;
   bool rightMousePressed;
   bool shiftPressed;
   bool controlPressed;
   bool toSelect;
   TreeWidgetItem* newSelection;

   //initialize the plane
   void initPlane();

   // main drawing method
   void draw();
   void drawOffScreen();
   void drawOnScreen();
   void paintTopology(QPainter &painter, bool optimizeScreen = false);
   void initScale();

   //some transformation functions
   void rotateTo(const QPoint &endPoint);
   void moveTo(const QPoint &endPoint);
   void increasePlaneDistanceTo(const QPoint &endPoint);
   void setDims(unsigned dim1, unsigned dim2, unsigned dim3);

   //minimal and maximal current and abolute values
   double minValue, maxValue, minAbsValue, maxAbsValue;
   //for user-defined values for the minimal and maximal colors
   bool userDefinedMinMaxValues;
   double userMinValue, userMaxValue;


   QColor* getColor(unsigned id);


   //set the current angles
   void setXAngle(int angle);
   void setYAngle(int angle);
   //if we set an angle from intern then we also have to update the topology tool bar
   void setXAngleFromIntern(int angle);
   void setYAngleFromIntern(int angle);

   void multiDim0(const std::vector<long>& coord, unsigned id, std::vector<std::string> dimNames);
   void multiDim1(const std::vector<long>& coord, unsigned id, std::vector<std::string> dimNames);
   int selectMode; // if > 3 dimensions: call multiDim0 or multiDim1
   bool invalidDimensions; // if > 3 dimensions: selection is not valid

   ViewFactors diffs;

   QPixmap *offscreen; // used for double buffering
   TopologyDimensionBar *tbar;
};

#endif
