extends layout

include mixins

block scripts
  script(type='text/javascript', src='jquery.autocomplete.js')

block customMenu
  div#connectionsMenu
    label(for='graphSize') Query Size:
    select(id='graphSize')
      option(value="100") 100
      option(value="500") 500
      option(value="1000",selected) 1000
      option(value="5000") 5000
      option(value="10000") 10000
      option(value="100000") 100000
    label(for='srcField') Src:
    +fieldsSelect("srcField", "", true)
    label(for='dstField') Dst:
    +fieldsSelect("dstField", "", true, [{dbField: "ip.dst:port", exp: "ip.dst:port"}])
    label(for='minConn') Min Connections:
    select(id='minConn')
      option(value="1") 1
      option(value="2") 2
      option(value="3") 3
      option(value="4") 4
    button#unlock Unlock

block content
  //input#networkZoom(type="range", value=100, min=25, max=600)
  div#bsqErr
  div#networkLabel
  div#network
  script(type='text/javascript').
    var initialDisplayLength = 100;
    var doPushState = 1;
    var svg;
    var svgMain;
    var force;
    var zoom;
    var trans=[0,0];
    var scale=1;
    var popupTimer;
    var colors = ["", "green", "red", "purple"];

    function handleParams() {
      params = handleUrlParams();

      if (params.srcField !== undefined) {
        $("#srcField").val(params.srcField);
      } else {
        $("#srcField").val(molochSettings.connSrcField || "a1");
      }

      if (params.dstField !== undefined) {
        $("#dstField").val(params.dstField);
      } else {
        $("#dstField").val(molochSettings.connDstField || "ip.dst:port");
      }

      if (params.minConn !== undefined) {
        $("#minConn").val(params.minConn);
      } else {
        $("#minConn").val(molochSettings.connMinConn || "1");
      }
    }

    $("#srcField,#dstField,#minConn,#graphSize").change (function() {
      initialDisplayLength = +$("#graphSize").val();
      loadData();
      return false;
    });


    $(window).bind('popstate', function(e) {
      if (window.history.ready) {
        doPushState = 0;
        handleParams();

        loadData();
        return false;
      }
    });

    setTimeout(function () {window.history.ready = true;}, 500);

    $(window).resize(function(e) {
      expressionResize();

      var width = $(window).width() - 4;
      var height = $(window).height() - $("#headers").height() - 4;

      svgMain.attr("width", width)
             .attr("height", height)
             ;

      if (force) {
        force.size([width, height]);
      }
    });

    $('#searchForm').submit(function() {
      loadData();
      return false;
    });

    function redraw() {
      //store the last event data
      trans=d3.event.translate;
      scale=d3.event.scale;  

      //transform the vis
       svg.attr("transform", "translate(" + trans + ")" + " scale(" + scale + ")");  
    }

    function hideNode(node) {
      $('#networkLabel').hide();
      svg.select("#id"+node.replace(/[:\.]/g,"_")).remove();
      svg.selectAll(".link")
         .filter(function(d, i) {
           return d.source.id === node || d.target.id === node;
         })
         .remove();
    }

    function hideLink(t,s) {
      $('#networkLabel').hide();
      svg.selectAll(".link")
         .filter(function(d, i) {
           return d.source.id === t && d.target.id === s;
         })
         .remove();
    }

    function exprLookup(expr) {
      if (expr === "ip.dst:port") {
        return "ip.dst";
      }
      return expr;
    }

    var currentNode = null;
    function gAddNode(op) {
      var expr = $("#srcField option:selected").text();
      if (currentNode.type === 2) {
        expr = $("#dstField option:selected").text();
      }

      addExpression(exprLookup(expr) + "==" + currentNode.id, op);
    }

    var currentLink = null;
    function gAddLink(op) {
      var srcExpr = exprLookup($("#srcField option:selected").text());
      var dstExpr = exprLookup($("#dstField option:selected").text());

      addExpression("(" + srcExpr + " == " + currentLink.source.id + " && " + dstExpr + " == " + currentLink.target.id + ")", op);
    }

    function showNodePopup(that, d) {
      currentNode = d;
      var content = d.id + "<br>" + 
                    "Type: " + ["", "Source", "Target", "Both"][d.type] + "<br>" + 
                    "Links: " + d.weight + "<br>" +
                    "Sessions: " + numberWithCommas(d.sessions) + "<br>" +
                    "Bytes: " + numberWithCommas(d.by) + "<br>" +
                    "Databytes: " + numberWithCommas(d.db) + "<br>" +
                    "Packets: " + numberWithCommas(d.pa) + "<br>" +
                    "Expression: <a href='javascript:gAddNode(\" && \")'>&amp;&amp;</a> " +
                                "<a href='javascript:gAddNode(\" || \")'>||</a><br>" +
                    "<a href='javascript:hideNode(\"" + d.id + "\")'>Hide Node</a>";
      $('#networkLabel').html(content)
                        .css({ left: trans[0] + (d.px*scale) + 25,
                                top: trans[1] + (d.py*scale) + $('#networkLabel').height()/2 + 25
                            })
                        .show()
                        ;
    }

    function showLinkPopup(that, d, mouse) {
      currentLink = d;
      $('#networkLabel').html("Link<br>" + 
                        d.source.id + "<br>" + 
                        d.target.id + "<br>" + 
                        "Sessions: " + numberWithCommas(d.value) + "<br>" +
                        "Bytes: " + numberWithCommas(d.by) + "<br>" +
                        "Databytes: " + numberWithCommas(d.db) + "<br>" +
                        "Packets: " + numberWithCommas(d.pa) + "<br>" +
                        "Expression: <a href='javascript:gAddLink(\" && \")'>&amp;&amp;</a> " +
                                    "<a href='javascript:gAddLink(\" || \")'>||</a><br>" +
                        "<a href='javascript:hideLink(\"" + d.source.id + "\",\"" + d.target.id + "\")'>Hide Link</a>")
                        .css({ left: trans[0] + (mouse[0]*scale) + 25,
                                top: trans[1] + (mouse[1]*scale) + $('#networkLabel').height()/2 + 25
                            })
                        .show()
                        ;
    }

    function loadData() {
      $('#networkLabel').hide();

      svg.selectAll(".link")
          .remove();

      svg.selectAll(".node")
          .remove();

      var params = buildParams();
      params.push({name:'srcField', value:$("#srcField").val()});
      params.push({name:'dstField', value:$("#dstField").val()});
      params.push({name:'minConn', value:$("#minConn").val()});
      var state = $.param(params);

      var url = "connections.json?" + state;
      if (doPushState && state !== window.location.search.substring(1) && 'pushState' in history) {
        history.pushState({}, this.title || '', "connections?" + state);
      } else {
        doPushState = 1;
      }

      d3.json(url, function(json) {
        var doConvert = 0;
        doConvert |= (db2FieldType($("#srcField").val()) === "seconds")?1:0;
        doConvert |= (db2FieldType($("#dstField").val()) === "seconds")?2:0;

        if (doConvert) {
          for (var i = 0; i < json.nodes.length; i++) {
            var node = json.nodes[i];
            if (doConvert & node.type) {
              node.id = dateString(node.id, " ");
            }
          }
        }

        $("#actionsForm").data("moloch-visible", +$("#graphSize").val())
                         .data("moloch-all", json.iTotalDisplayRecords);
        updateHealth(json.health);
        updateString("#bsqErr", json.bsqErr);
        force
            .nodes(json.nodes)
            .links(json.links)
            .start();

        var link = svg.selectAll(".link")
            .data(json.links)
            .enter().append("line")
            .attr("class", "link")
            .style("stroke-width", function(d) { return Math.min(1 + Math.log(d.value), 12);})
            .on("mouseover",function(d) {
              if (popupTimer) {
                window.clearTimeout(popupTimer);
              }
              popupTimer = window.setTimeout(showLinkPopup, 800, this, d, d3.mouse(this));
            }).on("mouseout",function(d){
              window.clearTimeout(popupTimer);
            })
            ;  
        var drag = d3.behavior.drag()
          .origin(function(d) { return d; })
          .on("dragstart", function (d) {
            $('#networkLabel').hide();
            d3.event.sourceEvent.stopPropagation(); 
            d3.select(this).classed("dragging", true);
            d.fixed |= 1;
          })
          .on("drag", function (d) {d.px = d3.event.x; d.py = d3.event.y; force.resume();})
          .on("dragend", function (d) {
            d3.select(this).classed("dragging", false);
          });

        var node = svg.selectAll(".node")
            .data(json.nodes)
            .enter().append("g")
            .attr("class", "node")
            .attr("id", function(d) {return "id" + d.id.replace(/[:\.]/g,"_");})
            //.attr("y", function (d,i) {return i;})
            .call(drag)
            .on("mouseover",function(d) {
              if (d3.select(this).classed("dragging")) {
                return;
              }

              if (popupTimer) {
                window.clearTimeout(popupTimer);
              }
              popupTimer = window.setTimeout(showNodePopup, 800, this, d);
            }).on("mouseout",function(d){
              window.clearTimeout(popupTimer);
            })
            ;  

        node.append("svg:circle")
          .attr("class", "node")
          .attr("r", function(d) { return Math.min(3+Math.log(d.sessions), 12); })
          .style("fill", function(d) { return colors[d.type];})
          ;



        node.append("svg:text")
            .attr("dx", 12)
            .attr("dy", ".35em")
            .attr("class", "connshadow")
            .text(function(d) { return d.id;});

        node.append("svg:text")
            .attr("dx", 12)
            .attr("dy", ".35em")
            .text(function(d) { return d.id;});

        force.on("tick", function() {
          link.attr("x1", function(d) { return d.source.x; })
              .attr("y1", function(d) { return d.source.y; })
              .attr("x2", function(d) { return d.target.x; })
              .attr("y2", function(d) { return d.target.y; });

          node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
        });
      });
    }

    $("#unlock").on('click', function() {
      svg.selectAll(".node circle").each(function(d) {d.fixed = 0;});
      force.resume();
    });

    /*d3.select("#networkZoom").on("change", function() {
       console.log("scroll", zoom.center(), zoom.scale(), zoom.translate(), zoom.size());
       zoom.scale(this.value/100);
       zoom.event(svg);
    });*/


    $(document).ready(function() {
      handleParams();

      var width = $(window).width() - 4;
      var height = $(window).height() - $("#headers").height() - 4;

      zoom = d3.behavior.zoom()
          .translate([0,0])
          .scale(1)
          .scaleExtent([0.25,6])
          .on("zoom", redraw);

      svgMain = d3.select("#network").append("svg:svg")
          .attr("width", width)
          .attr("height", height);

      svg = svgMain.append('svg:g')
          .call(zoom)
          .append('svg:g')
          ;

      svg.append('svg:rect')
        .attr('width', $("#network").width() + 1000)
        .attr('height', $("#network").height() + 1000)
        .attr('fill', 'white')
        .attr('id', 'zoomCanvas')
        .on("mousedown", function(){
          $('#networkLabel').hide();
        })
        ;

      force = d3.layout.force()
          .gravity(0.05)
          .distance(120)
          .charge(-300)
          .size([width, height])
          ;

      loadData();
      expressionResize();
    });
