var setup_graph;
var nodes = [];

(function($){

  var graph_renderer = function(canvas, opts){
    var options = opts;
    var canvas = $(canvas).get(0);
    var ctx = canvas.getContext("2d");
    var graph;
    var node_handler = null;

    var renderer = {
      selected_node: null,
      node_boxes: {},

      on_node_clicked: function(handler) {
        node_handler = handler;
      },

      init: function(system) {
        graph = system;
        graph.screenSize(canvas.width, canvas.height) ;
        graph.screenPadding(20); 
        renderer.initMouseHandling();
      },

      draw_edge: function(ctx, edge, pt1, pt2) {
        var head = pt1;
        var tail = pt2;
        ctx.save();
        ctx.strokeStyle = opts.edge_stroke;
        ctx.lineWidth = 1.0;
        ctx.beginPath();
        ctx.moveTo(tail.x, tail.y);
        ctx.lineTo(head.x, head.y);
        ctx.stroke();
        ctx.restore();
      },

      draw_node: function(ctx, node, pt) {
        var radius = 7;
        pt.x = Math.floor(pt.x)
        pt.y = Math.floor(pt.y)
        var alpha = Math.min(node.data.age++, 1000) * 0.001;
        var stroke = opts.node_stroke + alpha.toString() + ")";

        ctx.save();
        ctx.lineWidth = 3;
        ctx.beginPath();
        ctx.arc(pt.x, pt.y, radius, 0, 360, false);
        ctx.strokeStyle = stroke;
        ctx.stroke();
        ctx.fillStyle = opts.node_fill;
        ctx.fill();
        ctx.closePath();
        ctx.restore();
      },

      redraw: function() {
        ctx.save();
        ctx.fillStyle = "#fff";
        ctx.fillRect(0,0, canvas.width, canvas.height)
        ctx.restore();
        
        graph.eachEdge(function(edge, start, end){
          renderer.draw_edge(ctx, edge, start, end);
        });

        graph.eachNode(function(node, pt) {
          renderer.draw_node(ctx, node, pt);
        });
      },
      
      initMouseHandling: function(){
        // no-nonsense drag and drop (thanks springy.js)
        var dragged = null;

        // set up a handler object that will initially listen for mousedowns then
        // for moves and mouseups while dragging
        var handler = {
          clicked: function(e){
            var pos = $(canvas).offset();
            _mouseP = arbor.Point(e.pageX-pos.left, e.pageY-pos.top)
            dragged = graph.nearest(_mouseP);

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

              renderer.selected_node = dragged.node.name;
              if(node_handler) {
                node_handler(dragged.node);
              }
            }

            $(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 = graph.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)
            _mouseP = null
            return false
          }
        }
        
        // start listening
        $(canvas).mousedown(handler.clicked);
      },
    }

    return renderer;
  }    
  
  rand_int = function(max) {
    return Math.round((Math.random() * max));
  }

  choose = function(ary) {
    return ary[rand_int(ary.length - 1)];
  }

	setup_graph = function() {
    var options = {
      edge_stroke: "rgba(48, 66, 125, 0.2)",
      node_stroke: "rgba(46, 46, 46,", // 0.6)",
      node_fill:   "rgba(255, 255, 255, 1)",
    }

    // repulsion, stiffness, friction
    var model = arbor.ParticleSystem(1300, 700, 0.99);
    //model.parameters({gravity:true}); // center-gravity to make the graph settle
    model.renderer = graph_renderer("#graph-view", options);

    var n_nodes = rand_int(7) + 3;
    for(i = 0; i < n_nodes; i++) {
      nodes.push(i.toString());
    }

    var edges = [];

    for(n in nodes) {
      var peers = rand_int(2) + 1;
      for(i = 0; i < peers; i++) {
        var p;
        do {
          p = choose(nodes);
        } while(p == n)

        edges.push([n, p])
      }
    }

    var counter = 0;
    var edge_adder = function() {
      var edge = edges[counter++];
      if(model.getEdges(edge[0], edge[1]).length == 0) {
        if(!model.getNode(edge[0])) {
            model.addNode(edge[0], {age: 0})
        }
        if(!model.getNode(edge[1])) {
            model.addNode(edge[1], {age: 0})
        }

        model.addEdge(edge[0], edge[1]);
      }

      if(counter < edges.length) {
        setTimeout(edge_adder, 5000);
      }
    }

    edge_adder();
		return model;
  }
})(this.jQuery)

