// nUtil - An utility Library for gnurbs
// Copyright (C) 2008-2026 Eric Bechet
//
// See the LICENSE file for contributions and license information.
// Please report all bugs and problems to <bechet@cadxfem.org>.
//


#ifndef __NDISPLAY_BASE_H
#define __NDISPLAY_BASE_H

#include "npoint.h"
#include "ndata.h"



enum {DRAW_NORMAL,DRAW_PICK,DRAW_SELECT};

struct pickinfo
{
  int seg;
  int type;
  int id;
  int nb_uid;
  int uids[3];
  unsigned int z;
  pickinfo(): seg(-1),type(-1),id(-1),nb_uid(0) {}
  pickinfo(int seg_,int type_,int id_,int nb_uid_,const int uids_[]): seg(seg_),type(type_),id(id_),nb_uid(nb_uid_) {if (nb_uid<=3) for (int i=0;i<nb_uid;++i) uids[i]=uids_[i];}
  bool operator <(const pickinfo & other) const // z comparison (to classify picks)
  {
    return (z+type)<(other.z+other.type);
  }
  bool operator==(const pickinfo & other) const // id comparison. if uids exist on both sides, then compare them; otherwise compare type and id.
  {
    if ((nb_uid==other.nb_uid) && (nb_uid>0))
    {
      for (int i=0;i<nb_uid;++i)
      {
        if (uids[i]!=other.uids[i]) return false;
      }
      return true;
    }
    else
    {
      if (seg!=other.seg) return false;
      if (type!=other.type) return false;
      if (id!=other.id) return false;
      return true;
    }
  }
  bool operator!=(const pickinfo & other) const
  {
    return (!operator==(other));
  }
};

struct less_pick
{
  bool operator()(const pickinfo &p1,const pickinfo &p2) const
  {
    if ((p1.nb_uid==p2.nb_uid) && (p1.nb_uid>0))
    {
      for (int i=0;i<p1.nb_uid;++i)
      {
        if (p1.uids[i]<p2.uids[i]) return true;
        if (p1.uids[i]>p2.uids[i]) return false; 
      }
      return false;
    }
    else
    {
      if (p1.seg<p2.seg) return true;
      if (p1.seg>p2.seg) return false; 
      if (p1.type<p2.type) return true;
      if (p1.type>p2.type) return false;
      if (p1.id<p2.id) return true;
      return false;
    }    
  }
};

class ndrawable
{
public:
  virtual ~ndrawable() {}
  /// \brief Discretizes the entity.
  /// \param[in] data data to fill-in.
  virtual void Display(data_container& data) const = 0;

  virtual ndrawable* clone() const =0 ;

  /// \brief Returns the dimension of the object (0 = point, 1=line , 2=surface)
  /// \return dimension.
  virtual int dim(void) const =0;
};


class ncallbacks
{
public :
  virtual ~ncallbacks() {}
  // called when elements are picked. Returns which one is of interest (0 by default = first one on stack)
  // return -1 if pick is not desired
  virtual int pick_callback(int, pickinfo[],npoint3) {return 0;}
  // called when pick succeeded and draw. Return 0 if no redraw is needed, 1 else.
  virtual int drag_callback(npoint3,npoint3,pickinfo) {return 0;}
  // called upon release
  virtual int release_callback(npoint3,npoint3,pickinfo) {return 0;}
  // get textual info about picked point (e.g. to be displayed)
  virtual std::string get_info(pickinfo) { return std::string("---");}
  
  virtual int key_callback(int key, const char* str) { return 0;}
  virtual void draw() {}
  virtual const std::vector<data_container>* get_data() {return NULL;}
protected :
  ncallbacks() {};// never instantiate this type
  npoint3 pickedpoint;
};

class ndisplay_base
{
public:
  ndisplay_base(): allow_pick(false),ncb(NULL) {} // constructor
  virtual ~ndisplay_base(){} // destructor
  virtual void init_data(const data_container &data) =0;   // all
  virtual void init_data(const std::vector<data_container> &data)=0;   // all
  virtual void init_data() {};   // self created datastructure
  virtual data_container * get_data() {return 0x0;}   // return self created datastructure or null
  virtual const std::vector<data_container> * get_data_all() const {return 0x0;}   // return pointer to structure (read only)
  virtual void display()=0;   // display loop
  virtual void save(const char *fname="default.d3d"){};
  virtual int getnumpick(void) {return 0;} // return max number of pickable elements
  virtual void setpick(bool p) {allow_pick=p;}
  virtual bool getpick() const {return allow_pick;}
  virtual void setcallbacks(ncallbacks *cb) {ncb=cb;}
  ncallbacks *ncb;
private :
  bool allow_pick;
};


#endif // __NDISPLAY_BASE_H
