boolean isMouse=true;
int mouse_event=0, 
    mouse_motion=HALT, 
    mouse_action=NOOP;
int touch_event=0, 
    touch_motion=UP, 
    touch_action=NOOP;
int touch_count;
boolean is_down;
boolean touchedH,  touchedC,  touchedD;
float   startH,    startC,    startD;
float elapsedTimeHold, elapsedTimeClick, elapsedTimeDoubleClick;
float holdX,    holdY;

////////// EVENT ACTION /////////////////////////////
void doMove(float x, float y) {
  event = "Move";
  if (menu_active || apmenu_active || edgmenu_active) return;
  adjustCoordinates(Math.round(x), Math.round(y));
  pressStartX = pointX;
  pressStartY = pointY;
  doSelectEdge();
  doSelectNode();
}

void doClick(float x, float y) {
  event = "Click";
  adjustCoordinates(Math.round(x), Math.round(y));
  pressStartX = pointX;
  pressStartY = pointY;
  doSelectEdge();
  doSelectNode();
  // ADDED BY IRI
  if (javascript != null) javascript.click(selection);
  //
  if (mouseButton == RIGHT) {
    if (selection != null && selected == null && !menu_active) 
      doBeginMenu();
    else if (sel_edge != null && !edgmenu_active)
      doBeginEdgMenu();
    else if (selection == null && !apmenu_active)
      doBeginApMenu();
  }
  else if (from_node == null && selection != null && selected == null) {
    if (debug) println("doExpandNode");
    doExpandNode(selection);
  }
  else if (from_node != null) {
    if (debug) println("new_relation("+from_node.name+", "+selection.name+")");
    String id      = from_node.id;
    String name    = from_node.name;
    String grp     = from_node.grp;
    String proj    = from_node.proj;
    if (grp==null) grp="";
    String to_id, to_name, to_grp, to_proj;
    if (selection != null) {
      to_node        = selection; 
      to_id   = to_node.id;
      to_name = to_node.name;
      to_grp  = to_node.grp;
      to_proj = to_node.proj;
      if (to_grp==null) to_grp="";
      to_node = null;
    }
    else {
      to_id   = "";
      to_name = "";
      to_grp  = "";
      to_proj = "";      
    }
    from_node = null;
    if (debug) println("javascript.new_relation2("+id+", "+name+", "+grp+", "+proj+", "+to_id+", "+to_name+", "+to_grp+", "+to_proj+")");
    javascript.new_relation(id, name, grp, proj, to_id, to_name, to_grp, to_proj);
  }
  else if (menu_active && selected != null) {
    if (debug) println("doMenu " + nls(menu,ln) );
    doMenu();
  }
  else if (edgmenu_active && sel_edge != null) {
    doEdgMenu();
  }
  else if (apmenu_active) {
    doApMenu();
  }
  dragging = false;
}

void doDoubleClick(float x, float y) {
  event = "DoubleClick";
  if (selection != null && selected == null) {
    rootNode(selection);
  }
}

void doHold(float x, float y) {
  event = "Hold";
  if (selection != null && selected == null) {
    doBeginMenu();
  } 
  else if (sel_edge != null) {
    doBeginEdgMenu();
  }
  else if (selection == null) {
    doBeginApMenu();
  }
}

void doDrag(float x, float y) {
  event = "Drag";
  adjustCoordinates(Math.round(x), Math.round(y));
  if (menu_active == false && apmenu_active == false) {
    if (selection != null) {
      doDragNode();
      dragging = false;
    } 
    else {
      dragging = true;
    }
  }
}

void doReleased(float x, float y) {
  event = "Released";
  adjustCoordinates(Math.round(x), Math.round(y));
  if (dragging) {
    doUpdateNodePosition();
  }  
  dragging = false;
  menu = 0;
  selection = null;
  previous_selection = null;
  //javascript.end_select();
}

////////// MOUSE EVENT DETECTION ///////////////////////////////////
void mouseMoved() {
  //if (debug) print("\tmouseMoved");
  is_down = false;
  if (!isMouse) return;
  mouse_event  = MOVED;
  mouse_motion = MOVING;
  doEvent(mouseX, mouseY);
}

void mouseDragged() {
  //if (debug) print("\tmouseDragged");
  is_down = true;
  if (!isMouse) return;
  if (mouse_action==HOLDED) { //Handling wrong dragging status after holding
    //if (debug) print("\tMoved");
    is_down = false;
    mouse_event  = MOVED;
    mouse_motion = MOVING;
  } else {
    //if (debug) print("\tDragged");
    mouse_event  = DRAGGED;
    mouse_motion = DRAGGING;
  }
  doEvent(mouseX, mouseY);
}
void mouseClicked() {
  //if (debug) print("\nmouseClicked");
  is_down = true;
  if (!isMouse) return;
  mouse_event = CLICKED;
  doEvent(mouseX, mouseY);
}
void mouseReleased() {
  //if (debug) print("\nmouseReleased");
  is_down = false;
  if (!isMouse) return;
  mouse_event = RELEASED;
  doEvent(mouseX, mouseY);
}

////////// MOUSE EVENT HANDLING ////////////////////////////
void doEvent(float x, float y) {
  //if (debug) print( "\ndoEvent event=" + toStr(mouse_event) + "\taction=" + toStr(mouse_action) + "\tmotion=" + toStr(mouse_motion) );
  switch (mouse_event) {
    case CLICKED:
      //if (debug) print("\nCLICKED");
      checkClickTimer(x, y);
      checkDoubleClickTimer(x, y);
      break;
    case RELEASED:
      //if (debug) print("\nRELEASED");
      checkClickTimer(x, y);
      if (mouse_motion == DRAGGING) {      // TO DETECT RELEASE AFTER DRAGGINNG
        mouse_action = RELEASE;
        doReleased(x, y);
        stopClickTimer(); 
        stopDoubleClickTimer(); 
        stopHoldTimer();
      } else if (mouse_motion == MOVING) { // TO CATCH CLICK DUE TO NO CLICKED AFTER HOLDING
        mouse_action = CLICK;
        doClick(x, y);
        stopClickTimer(); 
        stopDoubleClickTimer(); 
        stopHoldTimer();
      }
      break;
    case MOVED:
      //if (debug) print("\nMOVED");
      mouse_motion = MOVING;
      doMove(x, y);
      stopClickTimer(); 
      stopDoubleClickTimer(); 
      stopHoldTimer();
      break;
    case DRAGGED:
      //if (debug) print("\nDRAGGED");
      mouse_motion = DRAGGING;
      doDrag(x, y);
      stopClickTimer(); 
      stopDoubleClickTimer(); 
      stopHoldTimer();
      break;
    default:
  }
}
////////// TOUCH EVENT DETECTION ///////////////////////////////////
// Following functions are used for iPad(iOS)

void touchMove(TouchEvent touchEvent) { //Comment out while debugging. These routines are for iPad.
  //if (debug) print("\ttouchMove");
  isMouse=false;
  is_down = true;
  touch_event = MOVE;
  // draw circles at where fingers touch
  touch_count = touchEvent.touches.length;
  for (int i = 0; i < touch_count; i++) {
    int x = touchEvent.touches[i].offsetX;
    int y = touchEvent.touches[i].offsetY;
    fill(128,128,128);
    ellipse(x, y, 10, 10);
  }
  if (touch_count > 1) {
    currtXa = touchEvent.touches[0].offsetX;
    currtYa = touchEvent.touches[0].offsetY;
    currtXb = touchEvent.touches[1].offsetX;
    currtYb = touchEvent.touches[1].offsetY;
    currt_dist = Math.sqrt((currtXa - currtXb)*(currtXa - currtXb) + (currtYa - currtYb)*(currtYa - currtYb));
    scl = currt_dist / start_dist;
    zoom(scl);
    javascript.setscale(scl);
  }
  if (touch_count==1) {
    touchX = touchEvent.touches[0].offsetX;
    touchY = touchEvent.touches[0].offsetY;
    fill(128,64,64);
    ellipse(touchX, touchY, 10, 10);
    doTouch(touchX, touchY);
  }
}

void touchEnd(TouchEvent touchEvent) {
  //if (debug) print("\ttouchEnd");
  touch_event = END;
  isMouse=false;
  is_down = false;
  if (touch_count==1) {
    doTouch(touchX, touchY);
  }
}

void touchStart(TouchEvent touchEvent) {
  //if (debug) print("\ttouchStart");
  isMouse=false;
  is_down = true;
  // draw circles at where fingers touch
  touch_count = touchEvent.touches.length;
  for (int i = 0; i < touch_count; i++) {
    int x = touchEvent.touches[i].offsetX;
    int y = touchEvent.touches[i].offsetY;
    fill(0,128,64);
    ellipse(x, y, 10, 10);
  }
  if (touch_count > 1) {
    startXa = touchEvent.touches[0].offsetX;
    startYa = touchEvent.touches[0].offsetY;
    startXb = touchEvent.touches[1].offsetX;
    startYb = touchEvent.touches[1].offsetY;
    start_dist = Math.sqrt((startXa - startXb)*(startXa - startXb) + (startYa - startYb)*(startYa - startYb));
  }
  touchX = touchEvent.touches[0].offsetX;
  touchY = touchEvent.touches[0].offsetY;
  fill(64,128,255);
  ellipse(touchX, touchY, 10, 10);
  touch_event = START;
  doTouch(touchX, touchY);
}

////////// TOUCH EVENT HANDLING ////////////////////////////////
void doTouch(float x, float y) {
  //if (debug) print("\ndoTouch event=" + toStr(touch_event));
  switch (touch_event) {
    case START:
      dragmode = !dragmode;
      checkClickTimer(x, y);
      checkDoubleClickTimer(x, y);
      break;
    case END:
      mouse_motion = (mouse_motion==DRAGGING)? DRAG:UP;
      checkClickTimer(x, y);
      if (mouse_motion == DRAG) {      // TO DETECT RELEASE AFTER DRAGGINNG
        mouse_action = RELEASE;
        doReleased(x, y);
      } 
      stopClickTimer(); 
      stopDoubleClickTimer(); 
      stopHoldTimer();
      break;
    case MOVE:
      if (dragmode && selection==null) {
        mouse_motion = MOVING;
        doMove(x, y);
      }
      else {
        mouse_motion = DRAGGING;
        doDrag(x, y);
      }
      stopClickTimer(); 
      stopDoubleClickTimer(); 
      stopHoldTimer();
      break;
    default:
  }
}

////////// TIMER ///////////////////////////////////////////////
void checkClickTimer(float x, float y) {
  float current = millis()/1000F;
  elapsedTimeClick = current - startC; // Get elapsed time in seconds 
  //if (debug) print("\n"+current+"\tCheck\tClick\ttouched="+touchedC+"\tstart="+startC+"\telapsed="+elapsedTimeClick);
  if ( !touchedC ) {  // IF Not touched
    startClickTimer();
  }
  else if ( touchedC ) {
    if ( elapsedTimeClick < 1 ) {
      //if (debug) print("\nCLICK");
      mouse_motion = HALT;
      mouse_action = CLICK;
      if (isMouse) doClick(mouseX, mouseY);
      else        doClick(touchX, touchY);
      stopClickTimer();
    }
  }
}
void startClickTimer() {
  float current = millis()/1000F;
  touchedC = true;  
  startC = millis()/1000F; // Get current time
  elapsedTimeClick = 0;
  //if (debug) print("\n"+current+"\tStart\tClick");
}

void stopClickTimer() {
  touchedC  = false;
  elapsedTimeClick = 0;
}

void checkDoubleClickTimer(float x, float y) {  // This routine works only under PC Firefox. Other environment doesn't work.
  float current = millis()/1000F;
  elapsedTimeDoubleClick = current - startD; // Get elapsed time in seconds 
  //if (debug) print("\n"+current+"\tCheck\tDoubleClick\ttouched="+touchedD+"\tstart="+startD+"\telapsed="+elapsedTimeDoubleClick);
  if ( !touchedD ) {  // IF Not touched
    startDoubleClickTimer();
  }
  else if ( touchedD ) {
    if ( elapsedTimeDoubleClick < 1 ) {
      //if (debug) print("\nDOUBLE CLICK");
      mouse_motion = HALT;
      mouse_action = DOUBLECLICK;
      if (isMouse) doDoubleClick(mouseX, mouseY);
      else        doDoubleClick(touchX, touchY);
      stopDoubleClickTimer();
    }
  }
}

void startDoubleClickTimer() {
  float current = millis()/1000F;
  touchedD = true;
  startD = millis()/1000F; // Get current time
  elapsedTimeDoubleClick = 0;  
  //if (debug) print("\n"+current+"\tStart\tDoubleClick");
}

void stopDoubleClickTimer() {  // ditto.
  touchedD  = false;
  elapsedTimeDoubleClick = 0;
}

void checkHoldTimer() {
  float current = millis()/1000F;
  elapsedTimeHold = current - startH; // Get elapsed time in seconds 
  /*if (Math.round(elapsedTimeHold*10)%10==0)
    if (debug) print("\n"+current+"\tCheck\tHold\ttouched="+touchedH+"\tstart="+startH+"\telapsed="+elapsedTimeHold);
  */
  if ((isMouse && mousePressed && !(mouse_motion==MOVING && mouse_action==HOLDED)) 
  || (!isMouse  && is_down)) {
    if ( !touchedH ) {  // IF Not touched
      startHoldTimer();
      holdX = (isMouse)? mouseX:touchX;
      holdY = (isMouse)? mouseY:touchY;
    }
    else if ( touchedH ) {
      float currentX = (isMouse)? mouseX:touchX;
      float currentY = (isMouse)? mouseY:touchY;
      float dist2 = (currentX - holdX)*(currentX - holdX) + (currentY - holdY)*(currentY - holdY);
      if ( dist2 < 16 && elapsedTimeHold > 0.5 ) {
        //if (debug) print("\nHOLD");
        mouse_motion = HALT;
        mouse_action = HOLDING;
        if (isMouse) doHold(mouseX, mouseY);
        else        doHold(touchX, touchY);
        mouse_action = HOLDED;
        stopHoldTimer();
      }
    }
  }
  else {
    stopHoldTimer();
  }
}

void startHoldTimer() {
  touchedH = true;
  float current = millis()/1000F;
  startH = current; // Get current time 
  elapsedTimeHold = 0;
  //if (debug) print("\n"+current+"\tStart\tHold");
}

void stopHoldTimer() {
  touchedH = false;
  elapsedTimeHold = 0;
}


