
// Gnurbs - A curve and surface library
// 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>.
//

#include <iostream>
#include <sstream>
#include "nlagrange.h"
#include "nspline.h"
#include "nbeziercurve.h"
#include "ncoons.h"
#include "nbspline.h"
#include "nbsplinesurface.h"
#include "nutil.h"
#include "gnurbscallbacks.h"
#include "ndisplay.h"


class mycallbacks : public ncallbacks
{
public:
  mycallbacks():picked(0x0) {}
  virtual ~mycallbacks() {}
  virtual int pick_callback(int,pickinfo[],npoint3);
  virtual int drag_callback(npoint3,npoint3,pickinfo);
  virtual int release_callback(npoint3,npoint3,pickinfo);
  virtual std::string get_info(pickinfo);
  virtual void draw(void); //redraw everything
  virtual void draw(int i); // draw one element (and keep the others)
  virtual int add_entity(nentity* ent) {objects.push_back(ent);prop_objects.push_back(properties());datas.push_back(data_container()); return (objects.size()-1);}
  virtual int add_entity(nentity* ent,properties p) {objects.push_back(ent);prop_objects.push_back(p);datas.push_back(data_container()); return (objects.size()-1);}
  virtual const std::vector<data_container>* get_data() {return &datas;}
  std::vector<nentity*> objects;
  std::vector<properties> prop_objects;
  std::vector<data_container> datas;
  nentity *picked;
};


int main(void)
{
  data_container data;
  ndisplay display;
  display.setpick(true);
  mycallbacks CB;
  display.setcallbacks(&CB);
  CB.draw();
  display.init_data(CB.datas);
  display.display();
  return 0;
}




int mycallbacks::pick_callback(int nb, pickinfo picks[],npoint3 p)
{
//  std::cout << "pick num=" << nb << std::endl;
  if (nb)
  {
    for(unsigned int j = 0; j <= 0; j++) // print 1st pick if existing
    {
      std::cout << "t=" << picks[j].type << " id=" << picks[j].id << " ";
      for (int i=0;i<picks[j].nb_uid;++i) 
        std::cout << "uid" << i << "=" << picks[j].uids[i] << " " ;
      std::cout << picks[j].z  << std::endl;
    }
    if (picks[0].nb_uid)
    {
      int objid=picks[0].uids[0];
      picked=objects[objid]->clone();
      return 0; // first element in the stack (closest to the eye) is chosen (-1 if no pick want
    }
  }
  return -1;
}

int mycallbacks::drag_callback(npoint3 orig,npoint3 p, pickinfo pick)
{
  int ret=0;
  npoint delta=npoint(p)-npoint(orig);
//  std::cout << "drag" << std::endl;
//  delta.print(std::cout);
  if (picked)
  {
    if (pick.nb_uid>1) // second uid = CP number
    {
      // move control point
      int objid=pick.uids[0];
      int CPid=pick.uids[1];
      npoint P=picked->CP(CPid);
      objects[objid]->set_CP(CPid,picked->CP(CPid)+delta*P[3]);
//      std::cout << "move CP" << std::endl;
      ret=1;
      draw(objid);
    }
    else if (pick.nb_uid>0)
    {
//      std::cout << "move part" << std::endl;
      // move whole part
      int objid=pick.uids[0];
      for (int i=0;i<picked->nb_CP();++i)
      {

        npoint P=picked->CP(i);
        objects[objid]->set_CP(i,picked->CP(i)+delta*P[3]);
      }
      draw(objid);
      ret=1;
    }
  }
  return ret;
}



int mycallbacks::release_callback(npoint3 orig,npoint3 p, pickinfo pick)
{
  int ret=0;
//  std::cout << "release" << std::endl;
  if (picked)
  {
    npoint delta=npoint(p)-npoint(orig);
//    delta.print(std::cout);
    if (pick.nb_uid>1) // second uid = CP number
    {
      // move control point
      int objid=pick.uids[0];
      int CPid=pick.uids[1];
      npoint P=picked->CP(CPid);
      objects[objid]->set_CP(CPid,picked->CP(CPid)+delta*P[3]);
//      std::cout << "move CP" << std::endl;
      ret=1;
      draw();
    }
    else if (pick.nb_uid>0)
    {
//      std::cout << "move part" << std::endl;
      // move whole part
      int objid=pick.uids[0];
      for (int i=0;i<picked->nb_CP();++i)
      {

        npoint P=picked->CP(i);
        objects[objid]->set_CP(i,picked->CP(i)+delta*P[3]);
      }
      draw();
      ret=1;
    }
    delete picked;
    picked=0x0;
  }
  return ret;
}

std::string mycallbacks::get_info(pickinfo pick)
{
  std::stringstream s;
  if (pick.nb_uid)
  {
    s << objects[pick.uids[0]]->info();
    if (pick.nb_uid>1)
      s << " CP(" << objects[pick.uids[0]]->CP(pick.uids[1]) << ")";
  }
  return s.str();
}

void mycallbacks::draw(void)
{
//  std::cout << "test" << objects.size()<< std::endl;
  for (int i=0;i<objects.size();++i) draw(i);
}

void mycallbacks::draw(int i)
{
  datas[i].clear();
  properties prop=prop_objects[i];
  prop.nb_uid=1;
  prop.uids[0]=i;
  datas[i].setpropall(prop);
  objects[i]->Display(datas[i]);
}
