/*
 * HypBrowser: part of Ubit demos
 * Franck Shen - Cedric Timsit. 2003
 */
/* ==================================================== ======== ======= */
/* ==================================================== [Elc:03] ======= */

#include <iostream>
#include <ubit/ubit.hpp>
#include <ubit/ugraph.hpp>
#include <ubit/udir.hpp>
#include "hbrowser.hpp"
#include "hnode.hpp"
using namespace std;


#define RECTCOLOR   UColor::black
#define FONTCOLOR   UColor::white
#define DIRCOLOR    UColor::yellow
#define EDGECOLOR   UColor::blue
#define CIRCLECOLOR UColor::red
#define N_MAX 2000

/* ==================================================== ======== ======= */
/* ==================================================== [Elc:03] ======= */

NodeInfo::NodeInfo(const UStr& _dirname, const UStr& _name, bool _is_dir) {
  is_dir = _is_dir;
  name = _name;
  path = _dirname & "/" & _name;
}

/* ==================================================== ======== ======= */
/* ==================================================== [Elc:03] ======= */

HBrowser::HBrowser(const UStr& _pathname, const UArgs& a) 
  : UBox(a) {
  T1 = NULL;
  mousedown = false;
  secondtip = false;
  currentpb = NULL;

  currentpath = _pathname;
  nodecount_str = 0;

  p1.set(COORDCART, 0.0, 0.0);
  p2.set(COORDCART, 0.0, 0.0);

  pointage = new PtBox[N_MAX];

  addlist
    (
     UBgcolor::black
     + UOn::viewPaint / ucall(this, &HBrowser::paintCB)
     + UOn::mpress    / ucall(this, &HBrowser::mousePressCB)
     + UOn::mrelease  / ucall(this, &HBrowser::mouseReleaseCB)
     + UOn::mmove     / ucall(this, &HBrowser::mouseMoveCB)
     );

  openDir(currentpath);
}

HBrowser::~HBrowser() {
  delTree1();
  delete[] pointage;
}

/* ==================================================== ======== ======= */
/* ==================================================== [Elc:03] ======= */

void HBrowser::delTree1(){
  //if (T1) FreeTree(T1);
  delete T1;
  T1 = NULL;
}

static HNode* mapTree(HNode* T, const UStr& path,
		      const UStr& name, bool is_dir) {
  //cerr << "mapTree : " << path << " " << name << " dir=" << is_dir <<endl;

  if (!T) T = new HNode();
  T->setInfo(new NodeInfo(path, name, is_dir));
  
  if (is_dir) {
    const UStr& dirname = T->info->getPath();
    UDir dir(dirname);
    
    int count = dir.getFileCount();
    
    if (count > 2) {
      HNode* aux = new HNode();
      for (int i=3; i<count; i++) aux->addBro(new HNode());
      T->child = aux;
      
      for (int i=2; i<count; i++) {
        aux = mapTree(aux, dirname, *dir.getFileEntry(i)->getName(),
                      dir.getFileEntry(i)->isDir());
        aux = aux->bro;
      }
    }
  }
	
  return T;
}

void HBrowser::openDir(const UStr& pathname){
  delTree1();

  currentpath = pathname;
  // recusrion infinie si path est vide!
  if (currentpath.empty()) currentpath = ".";

  T1 = mapTree(null, currentpath, "", true);
  T1->recenterTree(0.0);
  nodecount_str.setNum(int(T1->getNodeCount()));
}

/* ==================================================== ======== ======= */
/* ==================================================== [Elc:03] ======= */
/*
static void updateLabel(QLabel* label, long n){
  char str[20];
  sprintf(str, "%ld", n);
  label->setText( QString(str)+" nods\n" + currentpath);
}
*/

int HBrowser::updateScale(UEvent& e) {
  UView* v = e.getView();
  int d = min(v->getWidth(), v->getHeight());
  scale = d/2;
  xoffset = v->getWidth() / 2;
  yoffset = v->getHeight() / 2;
  return d;
}

void HBrowser::mousePressCB(UEvent& e) {
  updateScale(e);
  mousedown = true;

  p2.set(((double)e.getX()-scale)/scale, ((double)e.getY()-scale)/scale);
  
  double testx = (double)e.getX() - scale;
  double testy = (double)e.getY() - scale;
  //cerr << "mousePressCB: " << e.getX() <<", " << e.getY()
  //    <<" / "<<nbnoeuds << endl;

  for (int i=0;i<nbnoeuds;i++) {
    if (testx > pointage[i].x1 && testx < pointage[i].x2
        && testy < pointage[i].y2 && testy > pointage[i].y1) {
      currentpb = &pointage[i];
      cerr << " -- currentpb: " <<currentpb << endl<< endl;
    }
  }
}

/* ==================================================== ======== ======= */
/* ==================================================== [Elc:03] ======= */

void HBrowser::mouseMoveCB(UEvent& e) {
  currentpb = NULL;
  
  if (mousedown){
    /*
    UGraph painter(e);
    painter.setColor(UColor::red);
    painter.drawRect( pointage[0].x1, pointage[0].y1, 
		      pointage[0].x2 - pointage[0].x1,
		      pointage[0].y2 - pointage[0].y1 );
    */
    double d = scale;
      
    if (secondtip){
      p2.set(((double)e.getX()-scale)/d, ((double)e.getY()-scale)/d);
      d = ComplexNorm(p2);

      if(0.175<d && d<0.547){
        
        //InvComplex(&p2, &p2);
        InvSignComplex(p2, p2);
        AddToModule(p2, 1.0);
        T1->transTree(p1, p2);

        update(UUpdate::paint);
        /* eventuelle opt
          * UGraph painter(e);
        * painter.setColor(UColor::black);
        * painter.clearView(true);
        */
      }
    }

    secondtip = true;
  }
}

/* ==================================================== ======== ======= */
/* ==================================================== [Elc:03] ======= */

void HBrowser::mouseReleaseCB(UEvent& e) {
  if (e.getButtons() == UEvent::MButton3){
    T1->recenterTree(0.0);
  }
  else {
    HComplex c;

    int d = updateScale(e);
    mousedown = true;

    p2.set(((double)e.getX() - scale)/d, ((double)e.getY() - scale)/d);

    c.x = p1.x;//0.0;
    c.y = p2.y;//0.0;

    if (currentpb && currentpb->info != T1->info && currentpb->info->isDir()) {

      cerr << "setTree(" << currentpb->info->getPath() <<")" << endl;
      openDir(currentpb->info->getPath());
      //updateLabel(label, CountNodes(T1));
      currentpb = NULL;
    }
  }

  mousedown = false;
  secondtip = false;
  update();
}

/* ==================================================== ======== ======= */
/* ==================================================== [Elc:03] ======= */

void HBrowser::paintCB(UEvent& e){
  int d = updateScale(e);

  UGraph painter(e);
  painter.setColor(CIRCLECOLOR);
  painter.drawEllipse(xoffset-scale, yoffset-scale, d, d);

  nbnoeuds = 0;
  if (mousedown) drawNode(T1, painter, false);
  else drawNode(T1, painter, true);
}

/* ==================================================== ======== ======= */
/* ==================================================== [Elc:03] ======= */

void HBrowser::drawNode(HNode* T, UGraph& painter, bool draw_str) {
  if(!T) return;

  if (T->v.type == COORDPOL){
    T->v.type = COORDCART;
    AffixToCart(T->v, T->v);
  }

  double x = T->v.x * scale + xoffset;
  double y = T->v.y * scale + yoffset;

  painter.setColor(EDGECOLOR);

  HNode* aux = T->child;
  while(aux) {
    double x_, y_;
    x_ = aux->v.x * scale + xoffset;
    y_ = aux->v.y * scale + yoffset;
    painter.drawLine(int(x), int(y), int(x_), int(y_));
    aux = aux->bro;
  }

  double thres = draw_str ? 0.98 : 0.7;

  if (ComplexNorm2(T->v) < thres) {
    UFont& font = UFont::small;
    const UStr& str = T->info->getName();

    u_dim h = 0, w = 0;
    //painter.getTextSize(font, str, w, h);
    //w = w / 2;

    if (!draw_str) {
      //painter.setColor(RECTCOLOR);
      //painter.fillRect(x - w/2, y-(h*3)/6, w, (h*3)/2);

      if (T->info->isDir()) painter.setColor(DIRCOLOR);
      else painter.setColor(FONTCOLOR);
      painter.setFont(font);
      painter.drawString(str, x - w/2, y+h/2.0);
    }

    else {
      PtBox& pt = pointage[nbnoeuds];
      pt.x1 = x - w/2;
      pt.y1 = y - (h*3)/6;
      double auxh = (h*3)/2;

      //painter.setColor(RECTCOLOR);
      //painter.fillRect(pt.x1,	pt.y1, w, auxh);

      if (T->info->isDir()) painter.setColor(DIRCOLOR);
      else painter.setColor(FONTCOLOR);
      painter.setFont(font);
      painter.drawString(str, pt.x1, y+h/2.0);

      pt.x2 = pt.x1 + w;
      pt.y2 = pt.y1 + auxh;
      pt.info = T->info;

      if (currentpb)  /*todrawx1 != 1000*/ {
        cerr << "painter.drawRect( " << currentpb << " )" << endl;
        painter.setColor(CIRCLECOLOR);
        painter.drawRect(currentpb->x1, currentpb->y1,
                         currentpb->x2 - currentpb->x1,
                         currentpb->y2 - currentpb->y1 );
      }

      if (nbnoeuds < N_MAX) nbnoeuds++;  // SIZE ???
    }
  }

  // appels recursifs
  drawNode(T->child, painter, draw_str);
  drawNode(T->bro, painter, draw_str);
}

/* ==================================================== ======== ======= */
/* ==================================================== [Elc:03] ======= */
