//-*-c++-*-
/**
 Author: David Auber
 Email : auber@labri.fr
 Last modification : 20/08/2001
 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.
*/
#ifndef Tulip_GLGRAPH_H
#define Tulip_GLGRAPH_H

#ifndef NDEBUG
#define TRACE_EXEC()			       
//	cerr << __PRETTY_FUNCTION__ << endl;
#else
#define TRACE_EXEC()
#endif

#if (__GNUC__ < 3)
#include <hash_map>
#else
#include <ext/hash_map>
#endif

#include <GL/gl.h>
#include <tulip/PluginContext.h>
#include <tulip/Observable.h>
#include <tulip/Coord.h>
#include <tulip/Color.h>
#include <tulip/SuperGraph.h>
#include <tulip/Types.h>
#include <tulip/TemplateFactory.h>
#include <tulip/Reflect.h>
#include "tulip/GlGraphStrategy.h"

class LayoutProxy;
class MetricProxy;
class StringProxy;
class IntProxy;
class SelectionProxy;
class SizesProxy;
class ColorsProxy;
class MetaGraphProxy;
class PropertyProxyContainer;

class Glyph;
class GlyphFactory;
class GlyphContext;

namespace STL_EXT_NS {
  struct hash<string>{size_t operator()(std::string const& s) const {return hash<char const*>()(s.c_str());}};
}

typedef STL_EXT_NS::hash_map<int, string , STL_EXT_NS::hash<int> >  GlyphTableString;
typedef STL_EXT_NS::hash_map<int, Glyph *, STL_EXT_NS::hash<int> > GlyphTableGlyph;

/**
 * This widget enables an incremental 3D drawing of a Tulip SuperGraph.
 *  It also includes 3D navigation capabilities and selection methods.
 *  All the displaying is done with OpenGl.
*/
class GlGraph : public Observer {
private:
  GlGraphStrategy *strategy;

public:
  GlGraph(GlGraphStrategy &strategy);
 ~GlGraph();

  //============================================
  DataSet getParameters() const;
  void setParameters(const DataSet);
  /**
   *  Initialize scale factors according to layout bounding box
   *  Initialize the camera position.
   */
  void init();
  void setGlyphTable(const GlyphTableString &v);
  void setGlyphTable(const GlyphTableGlyph &v);
  GlyphTableString getGlyphTable() const;
  
  /// Rebuild the OpenGl Display lists
  void updateList();
  /**
   * Initialize OpenGl renderer parameters
   * GL_LINE_SMOOTH,GL_BLEND,GL_CULL_FACE,GL_DEPTH_TEST
   */
  void initializeGL();
  /**
   *  Set ligths, clipping plane, camera position, 
   *  and launch the incremental rendering of the graph.
   */
  void paintGL();
  /// Change the dimension of the drawing, and enable redrawing.
  void resizeGL( const int w, const int h );
  /// Manages observers change notification.
  void update (set<Observable *>::iterator,set<Observable *>::iterator);
  void drawGraph();
  /// Repaint the graph in is whole.
  void redraw();
  ///
  void getWinParameters(int *winX, int *winY, int *winW, int *winH, GLint *vp[4]);

  //==============================================================================
  // Data centralization in order to optimize memory using
  //==============================================================================
  /// Activate Texture wuth name filename
  bool activateTexture(const string &filename);
  /// Deactivate textue
  void desactivateTexture();

  //==============================================================================
  // Rendering parameters
  //==============================================================================
  ///Return the background color
  Color getBackgroundColor() const;
  ///Set the background color.
  void setBackgroundColor(const int r,const int v, const int b);
  ///Activate or deactivate displaying of arrows along the graph's edges.
  void setViewArrow(const bool);
  ///Return true if arrows drawing is activated else false.
  bool isViewArrow()const;
  ///Activate or deactivate displaying of labels on nodes and edges.
  void setViewLabel(const bool);
  ///Return true if label drawing is on else false.
  bool isViewLabel()const;
  /// Activate or deactivate interpolation of nodes colors along edge
  void setEdgeColorInterpolate(const bool);
  /// Return true if label drawing is on else false.
  bool isEdgeColorInterpolate()const;
  /// Return the type of fonts used in the renderer(0=3D,1=bitmap,2=texture)
  unsigned int fontsType()const;
  /// Set fonts type used in the renderer (0=3D,1=bitmap,2=texture)
  void setFontsType(unsigned int i);
  /// If true activate the Orthogonal projection, else perspective is used.
  void setViewOrtho(const bool);
  /// Return true if orthogonal projection is used.
  bool isViewOrtho()const;
  /// If true glgraph use the incremental rendering else display all elements in one pass
  void setIncrementalRendering(bool);
  /// return the incremental rendering stats
  bool isIncementalRendering()const;
  ///
  void setViewKey(const bool);
  ///
  bool isViewKey() const;
  ///
  void setViewStrahler(const bool);
  ///
  bool isViewStrahler() const;
  /// Use 3D displaying of edges instead of 2D lines
  void setEdge3D(const bool);
  /// return true is 3D drawing of edges is activated
  bool isEdged3D() const;


  //=======================================================================
  // Navigation functions: GlGraphNavigate.cpp
  //=======================================================================
  // get camera related variables
  Coord getSceneTranslation() const;
  void setSceneTranslation(const Coord &);
  Coord getSceneRotation() const;
  void setSceneRotation(const Coord &);
  
  // translation, rotation, ...
  void setTranslation(const int x, const int y, const int z);
  void setRotation(const int x, const int y, const int z);

  ///Translate the screen on the X axis.
  void transX(const int);
  ///Translate the screen on the Y axis.
  void transY(const int);
  ///Translate ths screnn on the Z axis
  void transZ(const int);
  ///Rotate the graph arround the X axis.
  void rotX(const int step);
  ///Rotate the graph arround the Y axis.
  void rotY(const int step);
  ///Rotate the graph arround the Z axis.
  void rotZ(const int step);
  ///Zoom on the center of the screen
  void zoom(const int step);
  ///Zoom to coordinates
  void zoomXY(const int step, const int x, const int y);
  
  //turn head on y screen axis
  //turn head on x screen axis
  //walk in to the center


  //=======================================================================
  //Selection of elements on the screen
  //=======================================================================
  ///
  void doSelect(const int x, const int y, const int w, const int h, set<node> &sNode, set<edge> &sEdge);
  ///
  bool doSelect(const int x, const int y, int &type, node &, edge &);
  ///
  bool doNodeSelect(const int x, const int y, const int w, const int h, set<node> &sNode);
  ///
  bool doEdgeSelect(const int x, const int y, const int w, const int h, set<edge> &sEdge);
  ///
  bool doNodeSelect(const int x, const int y, vector<node> &);
  ///
  bool doEdgeSelect(const int x, const int y, vector<edge> &);
  ///
  void initDoSelect(const GLint x, const GLint y, GLint w, GLint h);
  ///
  void makeNodeSelect(const int);
  ///
  void makeEdgeSelect(const int);
  ///
  void addSelection(const GLint x, const GLint y);
  ///
  void initAndSelect(const GLint x, const GLint y);
  ///
  void selectItem(const GLint x, const GLint y);


  //=======================================================================
  // Drawing function
  //=======================================================================
  

  //=======================================================================
  //Tools
  //=======================================================================
  void outputEPS(int size, int doSort, const char *filename);
  void changeCoord(double& x, double& y, double& z);
  /**Wait drawing of the graph and take a snapshot
   *Image is return in an array w*y*3 char. (8bits per color RGB)
   *The returned pointer must be deleted when one finish to work with the image.
   **/
  unsigned char *getImage(int &w, int &h);

  //=======================================
  //contôle de la fenêtre openGl
  //=======================================
  void goodScale();

  //=========================================
  //Operation sur la structure du Graphe
  //=========================================
  void del(const GLint x, const GLint y);

  void setSuperGraph(SuperGraph *);
  SuperGraph* getSuperGraph() const;

  void delSelection();
  void initProjection();
  void initModelView();
  void initLights();
  void initGlParameter();

  SuperGraph     *_superGraph;
  static TemplateFactory<GlyphFactory,Glyph,GlyphContext *> glyphFactory;

protected:
  void drawEdge(const Coord &startNode, const Coord &finalNode,
                const Coord &startPoint,const LineType::RealType &bends, const Coord &endPoint,
		const Color &startColor, const Color &endColor, const Size &size, int shape, const bool selected=false);
  void drawEdge(edge ite);
  unsigned int drawEdges(unsigned int , Iterator<edge> *);
  unsigned int drawEdges(unsigned int , list<edge>::iterator &) _DEPRECATED;
  //  void drawNode(node itv);
  void drawNode(node itv,unsigned int depth);
  unsigned int drawNodes(unsigned int , Iterator<node> *);
  unsigned int drawNodes(unsigned int , list<node>::iterator &) _DEPRECATED;
  void drawFanNode(node n) ;
  unsigned int drawFanNodes(unsigned int , Iterator<node> *);
  void drawMetaNode(node n,unsigned int depth);
  void DrawBitmapString(void *, const char *);
  void DrawStrokeString(void *font, const char *string);
  void makeArrowMatrix(GLfloat *, const Coord , const Coord , GLfloat, GLfloat, GLfloat);
  void initProxies();


  //  void buildColor();
  void buildOrderedList();

  GLuint makeGraphObject() _DEPRECATED;
  GLuint makeCubeWireObject();
  GLuint makeConeObject();
private:
  PropertyProxyContainer *graphProperties;
  Color  backgroundColor;
  bool _viewArrow, _viewLabel, _viewKey, _viewStrahler;
  bool _viewAutoScale, _incrementalRendering, _edgeColorInterpolate, _edge3D;
  unsigned int _viewOrtho;
  unsigned int _FontsType;

  
  int winH;
  int winW;

  STL_EXT_NS::hash_map<int, Glyph *, STL_EXT_NS::hash<int> >  glyphTable;


  STL_EXT_NS::hash_map<string, GLuint > texturesMap;
  
  //display list holding drawing of metaGraph - currently a wire cube
  GLuint	 metaGraphDL;

  //FIXME: made public to allow glyphs to access those proxy
public:
  ColorsProxy    *elementColor;
  SizesProxy     *elementSize;
  IntProxy       *elementShape;
  SelectionProxy *elementSelected;
  StringProxy    *elementLabel;
  LayoutProxy    *elementLayout;
  MetaGraphProxy *elementMetaGraph;
  StringProxy	 *elementTexture;

private:
  //a factoriser
  GLint vp[4]; //->getGetIntegerv(GL_VIEWPORT)
  GLuint (*selectBuf)[4];
  GLuint objectGraph,objectCube,objectCone;
  GLfloat cxTra,cyTra,czTra;// Scene translation
  GLfloat xRot, yRot, zRot; // Rotation of the scene

  //  GLfloat xTra, yTra, zTra; 
  int winX,winY; 
  map<double,double> colorMap;
  double colorMapMin,colorMapMax;
  GLfloat distCam;   //distance for camera translation

  //+++
  Iterator<node>* drawNodesIterator;
  Iterator<edge>* drawEdgesIterator;
  list<node>::iterator drawNodesIteratorStl;
  list<edge>::iterator drawEdgesIteratorStl;
  list<node> orderedNode;
  list<edge> orderedEdge;
  double nodeSizex,nodeSizey;

  //Camera information
  Coord cameraEyes,cameraCenter,cameraUp;
  double cameraZoomFactor;

  //Incremental rendering parameters
  int maxNumberOfNodeToDraw;
  int maxNumberOfEdgeToDraw;
};


template<typename T> struct stlListIterator:public Iterator<T> {
  typename list<T>::iterator &it,itEnd;
  stlListIterator(typename list<T>::iterator &startIt, typename list<T>::iterator endIt):it(startIt),itEnd(endIt){}
  T next(){T tmp=*it;++it;return tmp;}
  bool hasNext(){return (itEnd!=it);}
};

#endif // Tulip_GLGRAPH_H
