String title = "17 June, 2012 ver.02";
PFont font;

String ln = "en";// "ja" "fr"
boolean personal        = true;
boolean editmode        = true;
boolean debug           = false;
boolean nodetrace       = false;
boolean edgetrace       = false;
boolean eventtrace      = false;
boolean attractiontrace = false;
boolean load            = false;
boolean showusername    = false;

ParticleSystem physics;
Node selection, 
     selected, 
     previous_selection,
     from_node, to_node,
     dragnode; 
Edge sel_edge, 
     selected_edge;
int edgeCount = 0;
int topicCount = 0;

boolean touch          = false;
boolean free           = true;
boolean dragging       = false;
boolean draggingnode   = false;
boolean menu_active    = false;
boolean apmenu_active  = false;
boolean edgmenu_active = false;
boolean mouseMode      = false;
boolean dowbleclick    = false;
boolean touched        = false;
boolean holding        = false;
boolean dragmode       = false;

int menu    = 0;
int edgmenu = 0;
int apmenu  = 0;
int centerX,     
    centerY;
int touchX,      
    touchY;
int menuX,       
    menuY;
int scrnX,       
    scrnY;
int pressStartX, 
    pressStartY;
int pointX,      
    pointY;
int topicX,      
    topicY;

float start             = 0;
float elapsedTimeMillis = 0;
float elapsedTimeSec    = 0.0;
float factor            = 1.0;
float damper            = 1.0;
float maxMotion         = 0;
float motionRatio;
float start_dist, 
      currt_dist;
float scl;
float theta1, 
      phai, 
      theta2;
float fromX, 
      fromY, 
      toX, 
      toY, 
      cX, 
      cY;

String both = "both";
String msg  = "";
String str  = "";
String event= "";
String func = "";

String unescapeSTR(String text) {
  String str=text;
  if (str == null || str.equals("")) return "";
  str = str.replaceAll("&amp;","&");
  str = str.replaceAll("&#034;","\"");	    
  str = str.replaceAll("&#039;","'");
  str = str.replaceAll("&quot;","\"");
  str = str.replaceAll("&lt;","<");
  str = str.replaceAll("&gt;",">");
  str = str.replaceAll("<br>","\n");
  return str;
}

String trimSTR(String text) {
  String str=text;
  if (str == null || str.equals("")) return "";
  str = str.replaceAll("\n","");
  str = str.replaceAll("\f","");	    
  str = str.replaceAll(" ","");
  str = str.replaceAll("　","");
  str = str.replaceAll("\r","");
  return str;
}

void setDebugmode(){
  debug = true;
}

////////  PROCESSING  //////////////////////////////////////////////////////////
int WORLD_SIZE_W, WORLD_SIZE_H;

void setSize(int w, int h) { 
  if (javascript != null) {
    WORLD_SIZE_W = w;
    WORLD_SIZE_H = h;  
    size(w, h);  
  }
}

void setup() {
  WORLD_SIZE_W = 600;
  WORLD_SIZE_H = 600;
  size(WORLD_SIZE_W, WORLD_SIZE_H);
  //size(600, 600);

  physics = new ParticleSystem( 0, DRAGFACTOR/* 0.1*/ ); 
  // Runge-Kutta, the default integrator is stable and snappy,
  // but slows down quickly as you add particles.
  // Try this to see how Euler is faster, but borderline unstable.
  // physics.setIntegrator( ParticleSystem.EULER ); 
  // Now try this to see make it more damped, but stable.
  physics.setDrag( DRAGFACTOR );
  physics.clear(); 
  
  setNodeShapes();
  if (load) loadData();
  
  frameRate(FRAME);
  smooth();
  
  selected      = null;
  selection    = null;
  menu_active  = false;
  apmenu_active = false;
  mouseMode    = false;
  damper        = 1.0f;
  
  if( debug || load || nodetrace || edgetrace || eventtrace || attractiontrace || editmode ) setMode();
  stopDoubleClickTimer();
}

void draw() {
  physics.tick(TICK); 
  if (dragmode)
    bgColor = MintCream;
  else
    bgColor = White;
  background(bgColor);
  smooth();  
  
  translate( WORLD_SIZE_W/2, WORLD_SIZE_H/2); 
  if (dragging == true) {
    pushMatrix();
    translate((pointX - pressStartX) * factor, 
              (pointY - pressStartY) * factor);
  }  
  
  drawNetwork();  
  
  if (dragging == true) popMatrix();
  if (menu_active)         showMenu();
  else if (apmenu_active)  showApMenu();  
  else if (edgmenu_active) showEdgMenu();
  translate( -WORLD_SIZE_W/2, -WORLD_SIZE_H/2); 
  debugTrace();
  checkHoldTimer();
}

void zoom(float value) {
  factor = round(value*10)/10;
}

void drawNetwork() {
  noStroke();
  // draw attractions
  if (attractiontrace) {
    Iterator ita = physics.attractions.iterator();
    while (ita.hasNext ()) {
      Attraction attraction = (Attraction) ita.next();
      if ( attraction.isOn() ) {
        strokeWeight(1);
        stroke(LightPink);
        line(factor*attraction.getOneEnd().position.x,      factor*attraction.getOneEnd().position.y,
            factor*attraction.getTheOtherEnd().position.x, factor*attraction.getTheOtherEnd().position.y);
      }
    }
  }  
  // draw edges
  Iterator ite = edges.entrySet().iterator();
  while (ite.hasNext ()) {
    Map.Entry ee = (Map.Entry)ite.next();
    String k  = (String) ee.getKey();
    Edge edge = (Edge) ee.getValue();
    edge.show();
  }
  if (sel_edge != null)    sel_edge.highlight();
  // draw vertices
  Iterator itv = nodes.entrySet().iterator();
  while (itv.hasNext ()) {
    Map.Entry ev = (Map.Entry)itv.next();
    String k  = (String) ev.getKey();
    Node node = (Node) ev.getValue();
    node.update();
    if(node != selection && node != selected) node.show();
  }  
  if ( selection != null)  {
    selection.highlight();
    highlite_vizgroup();
  }
  if ( selected  != null )  selected.highlight();  
  if ( from_node  != null ) from_node.highlight();  
  if ( sel_edge  != null )  sel_edge.highlight();
  markNode();
  markEdge();
}

void highlite_vizgroup() {//Displays selected group topics
  if (vizgroup!=null){
    for (int i = 0; i < vizgroup.size(); i++) {
      Node n = (Node) vizgroup.get(i);
      n.highlight();
    }  
  }
}

////////  DEBUG TRACE  /////////////////////////////////////////////////////////
void funcTrace(String f) {
  func = f;
  fill(Gray);
  textSize(12);
  textAlign(RIGHT, TOP);
  text(f, WORLD_SIZE_W - 20, 10);
}

void debugTrace() {
  funcTrace(func);
  fill(Gray);
  textSize(12);
  textAlign(LEFT, TOP);
  str = "scale:" + factor; text(str, 10, 10);
  str = (personal)?"personal":"team"; 
  str += " work";
  text(str, 70, 10);
  
  Iterator it = usercolors.keySet().iterator();
  int i=0,loc=10,h=10;
  while (it.hasNext ()) {
    String key = (String) it.next();
    UserColor usercolor = (UserColor) usercolors.get(key);
    stroke(usercolor.c); 
    strokeWeight(3);   
    line (loc,WORLD_SIZE_H-h,loc+20,WORLD_SIZE_H-h);
    text(usercolor.name,loc+25,WORLD_SIZE_H-h-10);
    loc += textWidth(usercolor.name)+35;
    if (loc > WORLD_SIZE_W - 100) {
      loc=10; h -= 10; 
    }
  }
 
  //str = "motion:" + toStr(mouse_motion); text(str, 10, 10);
  if (debug) {
    if (!isMouse) {
      str = "touch menu active:" + menu_active;            text(str, 10, 20);
      str = "apmenu active:" + apmenu_active;              text(str, 150, 20);
      str = "menu:" + toStr(menu);                         text(str, 10, 30);
      str = "apmenu:" + toStr(apmenu);                     text(str, 150, 30);
      str = "tuoch x=" + touchX + " y=" + touchY;          text(str, 10, 40);
      str = "screen x=" + scrnX + " y=" + scrnY;           text(str, 140, 40);
      str = "point x=" + pointX + " y=" + pointY;          text(str, 270, 40);
      str = "screen x=" + scrnX + " y=" + scrnY;           text(str, 400, 40);
      str = "start x=" + pressStartX + " y=" + pressStartY; text(str, 530, 40);
      str = (selection != null)? selection.name : "";  
      str = "selection:\t" + str;                          text(str, 10, 50);
      str = (selected != null)?  selected.name  : "";
      str = "selected:\t"  + str;                          text(str, 10, 60);
      str = event;                                         text(str, 10, 70);
      str = "dragging=" + dragging;                        text(str, 140, 70);
      str = "dragging node=" + draggingnode;               text(str, 270, 70);
      str = "func=" + func;                                text(str, 400, 70);
      str = "touch count=" + touch_count;                  text(str, 10, 80);
      //str = "start time(ms)=" + start;                      text(str, 140, 80);
      //str = "elapsed time=" + elapsedTimeSec;              text(str, 270, 80);
      //str = "holding=" + holding;                          text(str, 400, 80);
      //str = "touched=" + touched;                          text(str, 530, 80);
    }
    else {
      str = "menu active:" + menu_active;                  text(str,  10, 20);
      str = "apmenu active:" + apmenu_active;              text(str, 150, 20);
      str = "menu:" + toStr(menu);                         text(str,  10, 30);
      str = "apmenu:" + toStr(apmenu);                     text(str, 150, 30);
      str = "mouse x=" + mouseX + " y=" + mouseY;          text(str,  10, 40);
      str = "point x=" + pointX + " y=" + pointY;          text(str, 150, 40);
      str = "screen x=" + scrnX + " y=" + scrnY;           text(str, 290, 40);
      str = "start x=" + pressStartX + " y=" + pressStartY;text(str, 430, 40);
      str = (selection != null)? selection.name : "";      
      str = "selection:\t" + str;                          text(str,  10, 50);
      str = (from_node != null)? from_node.name : "";      
      str = "from:\t" + str;                               text(str, 150, 50);
      str = (selection != null)? selection.shape : "";      
      str = "shape:\t" + str;                              text(str, 290, 50);
      str = (selected != null)? selected.name : "";      
      str = "selected:\t"  + str;                          text(str,  10, 60);
      str = (to_node != null)? to_node.name : "";      
      str = "to:\t"  + str;                          text(str, 150, 60);
      str = event;                                         text(str,  10, 70);        
      str = "mouse=" + mouseMode;                          text(str, 150, 70);    
      str = "dragging=" + dragging;                        text(str, 290, 70);
      str = "func=" + func;                                text(str, 430, 70);
      str = "start=" + start;                              text(str, 570, 70);
      str = (sel_edge != null)? sel_edge.from.name : "";      
      str = "edge from:\t"  + str;                         text(str,  10, 80);
      str = (sel_edge != null)? sel_edge.to.name : "";      
      str = "to:\t"  + str;                                text(str, 150, 80);
      str = (sel_edge != null)? sel_edge.asc_id : "";      
      str = "asc_id:\t"  + str;                            text(str, 290, 80);
      str = (sel_edge != null)? "" + sel_edge.dup : "";      
      str = "dup:\t"  + str;                               text(str, 430, 80);
      str = (previous_selection != null)? "" + previous_selection.name : "";            
      str = "previous_selection=" + str;                   text(str,  10, 90);
      //str = "theta1=" + degrees(theta1);                   text(str,  10, 90);
      //str = "phai=" + degrees(phai);                       text(str, 150, 90);
      //str = "theta2=" + degrees(theta2);                   text(str, 290, 90);
  }
}

if (eventtrace) {  
    str = "mouse :"  + toStr(mouse_event); text(str, 10, 110);
    str = "touch :"  + toStr(touch_event); text(str, 10, 120);
    str = "motion:" + toStr(mouse_motion); text(str, 10, 130);
    str = "action:" + toStr(mouse_action); text(str, 10, 140);
    str = "time:" + millis()/1000F;        text(str, 10, 150);
    str = "Ct:" + touchedC;                text(str, 10, 160);
    str = "startC:" + startC;              text(str, 10, 170);
    str = "CTimer:" + elapsedTimeClick;    text(str, 10, 180);
    str = "Dt:" + touchedD;                text(str,100, 160);
    str = "startD:" + startD;              text(str,100, 170);
    str = "DTimer:" + elapsedTimeDoubleClick;          text(str,100, 180);
    str = "Ht:" + touchedH;                text(str,180, 160);
    str = "startH:" + startH;              text(str,180, 170);
    str = "HTimer:" + elapsedTimeHold;    text(str,180, 180);
    str = "pressed:" + mousePressed;      text(str,120, 110);
    str = "is down:" + is_down;            text(str,120, 120);
    str = "start__:" + start_dist;        text(str, 10, 190);
    str = "current:" + currt_dist;        text(str, 10, 200);
    str = "scale__:" + scl/100;           text(str, 10, 210);
  }
}
/*
void setParams(float frame, float spring_length, float spring_strength, float spring_damping, float spacer_strength, float drag, int mass) {
  FRAME          = frame;
  SPRING_LENGTH  = spring_length;
  SPRING_STRENGTH = spring_strength; // 0.2;
  SPRING_DAMPING  = spring_damping; // 0.2;
  SPACER_STRENGTH = spacer_strength;// 1000;
  DRAGFACTOR      = drag; //0.2
  //MASS            = mass;
}
*/
