//
//  main.js
//
//  A project template for using arbor.js
//

(function($){

  var Renderer = function(canvas){
    var canvas = $(canvas).get(0);
    var ctx = canvas.getContext("2d");
    var gtx = arbor.Graphics(canvas);
    var particleSystem;
    var bgImage = new Image();

    var that = {
      init:function(system){
        //
        // the particle system will call the init function once, right before the
        // first frame is to be drawn. it's a good place to set up the canvas and
        // to pass the canvas size to the particle system
        //
        // save a reference to the particle system for use in the .redraw() loop
        particleSystem = system;

        // inform the system of the screen dimensions so it can map coords for us.
        // if the canvas is ever resized, screenSize should be called again with
        // the new dimensions
        particleSystem.screenSize(canvas.width, canvas.height);
        particleSystem.screenPadding(80); // leave an extra 80px of whitespace per side
        
        // set up some event handlers to allow for node-dragging
        that.initMouseHandling();
        
        bgImage.src = 'images/23_portfolio_bg.jpg';
      },
      
      redraw:function(){
        // 
        // redraw will be called repeatedly during the run whenever the node positions
        // change. the new positions for the nodes can be accessed by looking at the
        // .p attribute of a given node. however the p.x & p.y values are in the coordinates
        // of the particle system rather than the screen. you can either map them to
        // the screen yourself, or use the convenience iterators .eachNode (and .eachEdge)
        // which allow you to step through the actual node objects but also pass an
        // x,y point in the screen's coordinate system
        // 
        //ctx.fillStyle = "white";
        //ctx.fillRect(0,0, canvas.width, canvas.height);
        ctx.drawImage(bgImage, 0, 0);
        
        particleSystem.eachEdge(function(edge, pt1, pt2){
          // edge: {source:Node, target:Node, length:#, data:{}}
          // pt1:  {x:#, y:#}  source position in screen coords
          // pt2:  {x:#, y:#}  target position in screen coords

          // draw a line from pt1 to pt2
          if (edge.source.data.alpha * edge.target.data.alpha == 0) return;
          /*ctx.strokeStyle = "rgba(255, 255, 255, .333)";
          ctx.lineWidth = 2;
          ctx.beginPath();
          ctx.moveTo(pt1.x, pt1.y);
          ctx.lineTo(pt2.x, pt2.y);
          ctx.stroke();*/
          gtx.line(pt1, pt2, {stroke: '#ee0000', width: 2, alpha: edge.target.data.alpha});
        });

        particleSystem.eachNode(function(node, pt){
          // node: {mass:#, p:{x,y}, name:"", data:{}}
          // pt:   {x:#, y:#}  node position in screen coords

          // draw a rectangle centered at pt
          var topW = 10, subW = 6;
          if (node.data.alpha === 0) return;
          if (node.data.isTop) {
              gtx.oval(pt.x - topW / 2, pt.y - topW / 2, topW, topW, {fill: 'white', alpha: node.data.alpha});
              gtx.text(node.name, pt.x + 12, pt.y + 7, {color: 'white', font: 'Helvetica'});
          } else {
              gtx.oval(pt.x - subW / 2, pt.y - subW / 2, subW, subW, {fill: '#e8390a', alpha: node.data.alpha});
              gtx.text(node.name, pt.x + 8, pt.y + 3, {color: '#e8390a', font: 'Helvetica'});
          }
        });
      },
      
      switchSection:function(newSection) {
          var edges = particleSystem.getEdgesFrom(newSection);
          var parent = edges[0].source;
          var children = $.map(edges, function(edge) {
            return edge.target;
          });
          
          particleSystem.eachEdge(function(edge) {
            var nowVisible = ($.inArray(edge, edges) >= 0);
            var newAlpha = (nowVisible) ? 1 : 0;
            
            particleSystem.tweenEdge(edge, .5, {strokeStyle: 'rgba(255,255,255,0)'});
          });
              
          particleSystem.eachNode(function(node) {
            if (node.data.isTop) return; // skip all but leafnodes
      
            var nowVisible = ($.inArray(node, children) >= 0);
            var newAlpha = (nowVisible) ? 1 : 0;
            var dt = (nowVisible) ? .5 : .5;
            particleSystem.tweenNode(node, dt, {alpha:newAlpha});
      
            if (newAlpha == 1){
              node.p.x = parent.p.x + .05 * Math.random() - .025;
              node.p.y = parent.p.y + .05 * Math.random() - .025;
              node.tempMass = .001;
            }
          });
        },
      
      initMouseHandling: function(){
        // no-nonsense drag and drop (thanks springy.js)
        var dragged = null;
        var nowSection;

        // set up a handler object that will initially listen for mousedowns then
        // for moves and mouseups while dragging
        var handler = {
          moved: function(e) {
              var pos = $(canvas).offset();
              _mouseP = arbor.Point(e.pageX - pos.left, e.pageY - pos.top);
              nearest = particleSystem.nearest(_mouseP);
          
              if (!nearest.node) return false;
              
              if (nearest.node.data.isTop) {
                  if (nearest.node.name != nowSection) {
                      nowSection = nearest.node.name;
                      that.switchSection(nowSection);
                  }
              }
              
              return false;
          },
          clicked: function(e) {
              var pos = $(canvas).offset();
              _mouseP = arbor.Point(e.pageX-pos.left, e.pageY-pos.top);
              dragged = particleSystem.nearest(_mouseP);

              if (dragged && dragged.node !== null){
                  // while we're dragging, don't let physics move the node
                  dragged.node.fixed = true;
              }

              $(canvas).unbind('mousemove', handler.moved);
              $(canvas).bind('mousemove', handler.dragged);
              $(window).bind('mouseup', handler.dropped);

              return false;
          },
          dragged: function(e) {
            var pos = $(canvas).offset();
            var s = arbor.Point(e.pageX-pos.left, e.pageY-pos.top);

            if (dragged && dragged.node !== null){
              var p = particleSystem.fromScreen(s);
              dragged.node.p = p;
            }

            return false;
          },

          dropped:function(e){
            if (dragged===null || dragged.node===undefined) return;
            if (dragged.node !== null) dragged.node.fixed = false;
            dragged.node.tempMass = 1000;
            dragged = null;
            $(canvas).unbind('mousemove', handler.dragged);
            $(window).unbind('mouseup', handler.dropped);
            $(canvas).bind('mousemove', handler.moved);
            _mouseP = null;
            return false;
          }
        }
        
        // start listening
        $(canvas).mousedown(handler.clicked);
        $(canvas).mousemove(handler.moved);
      },
      
    }
    return that;
  }    

  $(document).ready(function(){
    var sys = arbor.ParticleSystem(1000, 600, 0.5); // create the system with sensible repulsion/stiffness/friction
    sys.parameters({gravity:true}); // use center-gravity to make the graph settle nicely (ymmv)
    sys.renderer = Renderer("#portfolio"); // our newly created renderer will have its .init() method called shortly by sys...

    // add some nodes to the graph and watch it go...

    // or, equivalently:
    //
     sys.graft({
       nodes: {
         "Life Style": {isTop: true, alpha: 1},
         "Government": {isTop: true, alpha: 1},
         "International": {isTop: true, alpha: 1},
         "Online Payment": {isTop: true, alpha: 1},
         "System": {isTop: true, alpha: 1},
         "Media": {isTop: true, alpha: 1},
         "Service": {isTop: true, alpha: 1},
         
         "Between": {alpha: 0},
         "SK T-me": {alpha: 0},
         "SK T-me 맛집": {alpha: 0},
         "ACE Golf": {alpha: 0},
         "연애성향": {alpha: 0},
         "이상형찾기": {alpha: 0},
         "Best 휴게소21": {alpha: 0},
         "호텔엔조이": {alpha: 0},
         "불고기 브라더스": {alpha: 0},
         "투어캐빈": {alpha: 0},
         "라이브투어": {alpha: 0},
         "매그레 시리즈": {alpha: 0},
         "예스 리더": {alpha: 0},
         "Safe Spot, Japan": {alpha: 0},
         "Magazine Builder": {alpha: 0},
         "Medi Finder": {alpha: 0},
         "Korea Hotel, International": {alpha: 0},
         "Liz Lisa, Japan": {alpha: 0},
         "나가사키, Japan": {alpha: 0},
         "사세보, Japan": {alpha: 0},
         "TWT Voice, Japan": {alpha: 0},
         "INICIS": {alpha: 0},
         "Danal": {alpha: 0},
         "삼성SDI Power Station": {alpha: 0},
         "The Korea Spirit": {alpha: 0},
         "Elle at Zine": {alpha: 0},
         "Elle at TV": {alpha: 0},
         "Elle Beauty Dic": {alpha: 0},
       }, 
       edges: {
         "Life Style": {
           "Between": {length: 6},
           "SK T-me": {length: 6},
           "SK T-me 맛집": {length: 6},
           "ACE Golf": {length: 6},
           "연애성향": {length: 6},
           "이상형찾기": {length: 6},
           "Best 휴게소21": {length: 6},
           "호텔엔조이": {length: 6},
           "불고기 브라더스": {length: 6},
           "투어캐빈": {length: 6},
           "라이브투어": {length: 6},
           "매그레 시리즈": {length: 6},
         },
         "Government": {
           "예스 리더": {length: 6},
           "Safe Spot, Japan": {length: 6},
           "Magazine Builder": {length: 6},
           "Medi Finder": {length: 6},
         },
         "International": {
           "Korea Hotel, International": {length: 6},
           "Liz Lisa, Japan": {length: 6},
           "Safe Spot, Japan": {length: 6},
           "나가사키, Japan": {length: 6},
           "사세보, Japan": {length: 6},
           "TWT Voice, Japan": {length: 6},
         },
         "Online Payment": {
           "INICIS": {length: 6},
           "Danal": {length: 6},
         },
         "System": {
           "ACE Golf": {length: 6},
           "호텔엔조이": {length: 6},
           "Korea Hotel, International": {length: 6},
           "삼성SDI Power Station": {length: 6},
         },
         "Media": {
           "The Korea Spirit": {length: 6},
           "Between": {length: 6},
           "Elle at Zine": {length: 6},
           "Elle at TV": {length: 6},
           "Elle Beauty Dic": {length: 6},
           "Magazine Builder": {length: 6},
           "매그레 시리즈": {length: 6},
         },
         "Service": {
           "라이브투어": {length: 6},
           "Between": {length: 6},
           "Magazine Builder": {length: 6},
           "TWT Voice, Japan": {length: 6},
         },
       }
     });
    
  });

})(this.jQuery);
