var network;
var allNodes;
var allEdges;
var highlightActive = false;
var foundNodes;

var nodesDataset;
var edgesDataset = edges;
var show_network=0;
var network_max_level=1;
function toggle_network() {
  show_network ^= 1;

  var container = document.getElementById("mynetwork");
  var toggle_btn = document.getElementById("toggle_button");
  if( show_network ) {
    container.style.display="";
    toggle_btn.innerHTML="&#x25B2Hide dependency graph&#x25B2";
  } else {
    container.style.display="none";
    toggle_btn.innerHTML="&#x25BCShow dependency graph&#x25BC";
  }

}

function redrawAll() {
  var container = document.getElementById('mynetwork');
  var options = {
    autoResize:true,
    interaction: {
      tooltipDelay: 100,
      hideEdgesOnDrag: true
    },
    layout : {
      randomSeed:7,
      improvedLayout:false,
    },
    physics: {
      enabled:false,
      barnesHut: {
        gravitationalConstant:-6000,
        damping:0.4,
      },
      stabilization: {
        enabled:true,
        iterations:1,
        updateInterval:100,
      },
      timestep:0.7,
    },
    configure: {
      enabled:false,
      filter: function(option, path) {
        return path.indexOf('physics') !== -1;
      },
      container: document.getElementById('config'),
      showButton:false,
    },
  };

  // if package_buildinfo exists, set the color.
  if( typeof package_buildinfo !== 'undefined' ) {
    var yellow_color = { border: "#FFA500", background: "#FFFF00", highlight: { border: "#FFA500", background: "#FFFFA3" }, hover: { border: "#FFA500", background: "#FFFFA3" }}; // yellow
    var green_color = { border: "#41A906", background: "#7BE141", highlight: { border: "#41A906", background: "#A1EC76" }, hover: { border: "#41A906", background: "#A1EC76" } }; // green
    var grey_color =  { border: "#646464", background: "#808080", highlight: { border: "#646464", background: "#808080"}, hover: { border: "#646464", background: "#808080"} }; // grey
    var red_color =  { border: "#FA0A10", background: "#FB7E81", highlight: { border: "#FA0A10", background: "#FFAFB1" }, hover: { border: "#FA0A10", background: "#FFAFB1" } }; // red
    var blue_color = { border: "#2B7CE9", background: "#97C2FC", highlight: { border: "#2B7CE9", background: "#D2E5FF" }, hover: { border: "#2B7CE9", background: "#D2E5FF" } }; // blue
    var purple_color = { border: "#7C29F0", background: "#AD85E4", highlight: { border: "#7C29F0", background: "#D3BDF0" }, hover: { border: "#7C29F0", background: "#D3BDF0" } }; // 5: purple
    var color_switch = {
      'building': yellow_color,
      'failed': red_color,
      'scheduled': blue_color,
      'blocked': purple_color,
      'succeeded': green_color,
      'other': grey_color,
    };
    for( var i in nodes ) {
      if( nodes[i].label in package_buildinfo ) {
        var color = grey_color;
        var build_status = package_buildinfo[nodes[i].label];
        if( build_status in color_switch ) {
          color = color_switch[build_status];
        }
        nodes[i].color = color;
        nodes[i].set_color = color;
        nodes[i].title = nodes[i].label + ": " + build_status;
      } else {
        var color = grey_color;
        nodes[i].color = color;
        nodes[i].set_color = color;
        nodes[i].title = nodes[i].label + ": unknown";
      }
    }
  }
  nodesDataset = new vis.DataSet(nodes);

  var data = {nodes:nodesDataset, edges:edgesDataset}

  network = new vis.Network(container, data, options);

  // get a JSON object
  allNodes = nodesDataset.get({returnType:"Object"});
  allEdges = edgesDataset.get({returnType:"Object"});

  if (document.getElementById('max_build_level') ) {
    var pkg_count=0;
    var level_packages=new Array();
    for(var nodeId in allNodes) {
      var myLevel = allNodes[nodeId].level;
      if(!level_packages[myLevel]) level_packages[myLevel]=new Array();
      level_packages[myLevel].push(allNodes[nodeId].label);
      if( network_max_level < myLevel) {
        network_max_level = myLevel;
      }
      pkg_count++;
    }

    document.getElementById('max_build_level').innerHTML=network_max_level;
    document.getElementById('total_packages').innerHTML=pkg_count;
    AddPackagesIntoTable(level_packages);
  }

  network.on("click",neighbourhoodHighlight);
  network.on("doubleClick",MoveToThePackage);
}

function AddPackagesIntoTable(level_packages) {
  var tbl = document.getElementById('level_packages');
  tbl.setAttribute('border', '1');
  var tbody = document.createElement('tbody');
  for( var i = 0; i < level_packages.length; ++i ) {
    var tr = document.createElement('tr');
    var header_td = document.createElement('td');

    var package_string="";
    var last_string=null;
    var count=0;
    for( var j = 0; j < level_packages[i].length; ++j ) {
      if(last_string != null) {
        package_string+=last_string+", ";
      }
      last_string=MakeALink(level_packages[i][j]);
      count=count+1;
    }
    package_string+=last_string;

    header_td.appendChild(document.createTextNode('Level'+i+' Packages ('+count+')'));
    tr.appendChild(header_td);

    var pkgs_td = document.createElement('td');
    pkgs_td.innerHTML=package_string;
    tr.appendChild(pkgs_td);
    tbody.appendChild(tr);
  }
  tbl.appendChild(tbody);
}

function focusNode(nodeId) {
  var options = {
    // position: {x:positionx,y:positiony}, // this is not relevant when focusing on nodes
    scale: 2,
    offset: {x:0,y:0},
    animation: {
      duration: 1000,
      easingFunction: 'easeInOutQuad',
    }
  };
  network.focus(nodeId, options);
}

function neighbourhoodHighlight(params) {
  highlightNode(params.nodes);
}

function getAllPackagesBuildTriggered(node) {
  var connectedNodes = network.getConnectedNodes(node);
  var allPackages = {};

  for( var i = 0; i < connectedNodes.length; ++i ) {

    if( allNodes[connectedNodes[i]].level < allNodes[node].level )
      continue;

    var label = allNodes[connectedNodes[i]].label;

    if( label === undefined ) {
      label = allNodes[connectedNodes[i]].hiddenLabel;
    }
    allPackages[label] = 1;

    var nextPackages = getAllPackagesBuildTriggered(connectedNodes[i]);

    for(var j in nextPackages) {
      allPackages[j] = 1;
    }
  }

  return allPackages;
}

function highlightNode(nodes)
{
  // if something is selected:
  if (nodes.length > 0) {
    highlightActive = true;
    var i,j;
    var selectedNode = nodes[0];
    var degrees = 2;

    // set the value to the package name
    if(document.getElementById('pkg_name') && nodes[0]) {
      if( allNodes[selectedNode].label === undefined ) {
        document.getElementById('pkg_name').innerHTML=MakeALink(allNodes[selectedNode].hiddenLabel);
      } else {
        document.getElementById('pkg_name').innerHTML=MakeALink(allNodes[selectedNode].label);
      }
      document.getElementById('build_level').innerHTML=allNodes[selectedNode].group;
    }

    // mark all nodes as hard to read.
    for (var nodeId in allNodes) {
      allNodes[nodeId].color = 'rgba(200,200,200,0.2)';
      if (allNodes[nodeId].hiddenLabel === undefined) {
        allNodes[nodeId].hiddenLabel = allNodes[nodeId].label;
        allNodes[nodeId].label = undefined;
      }
    }

    // mark all edges as hard to read.
    for (var edgeId in allEdges) {
      allEdges[edgeId].color = 'rgba(200,200,200,0.2)';
    }
    var connectedNodes = network.getConnectedNodes(selectedNode);
    var connectedEdges = network.getConnectedEdges(selectedNode);
    //var allConnectedNodes = [];

    // get the second degree nodes
    //for (i = 1; i < degrees; i++) {
      //for (j = 0; j < connectedNodes.length; j++) {
        //allConnectedNodes = allConnectedNodes.concat(network.getConnectedNodes(connectedNodes[j]));
      //}
    //}

    // all second degree nodes get a different color and their label back
    //      for (i = 0; i < allConnectedNodes.length; i++) {
    //        allNodes[allConnectedNodes[i]].color = 'rgba(150,150,150,0.75)';
    //        if (allNodes[allConnectedNodes[i]].hiddenLabel !== undefined) {
    //          allNodes[allConnectedNodes[i]].label = allNodes[allConnectedNodes[i]].hiddenLabel;
    //          allNodes[allConnectedNodes[i]].hiddenLabel = undefined;
    //        }
    //      }

    var packages_build_triggers=[];
    var packages_build_triggered=[];
    // all first degree nodes get their own color and their label back
    for (i = 0; i < connectedNodes.length; i++) {
      if( allNodes[connectedNodes[i]].set_color === undefined ) {
        allNodes[connectedNodes[i]].color = undefined;
      } else {
        allNodes[connectedNodes[i]].color = allNodes[connectedNodes[i]].set_color;
      }

      if (allNodes[connectedNodes[i]].hiddenLabel !== undefined) {
        allNodes[connectedNodes[i]].label = allNodes[connectedNodes[i]].hiddenLabel;
        allNodes[connectedNodes[i]].hiddenLabel = undefined;

        if( allNodes[selectedNode].level <= allNodes[connectedNodes[i]].level ) {
          packages_build_triggered.push(allNodes[connectedNodes[i]].label);
        } else {
          packages_build_triggers.push(allNodes[connectedNodes[i]].label);
        }
      }
    }

    // the main node gets its own color and its label back.
    if( allNodes[selectedNode].set_color === undefined )
      allNodes[selectedNode].color = undefined;
    else
      allNodes[selectedNode].color = allNodes[selectedNode].set_color;

    if (allNodes[selectedNode].hiddenLabel !== undefined) {
      allNodes[selectedNode].label = allNodes[selectedNode].hiddenLabel;
      allNodes[selectedNode].hiddenLabel = undefined;
    }

    // all first degree edges get their own color and their label back
    for (i = 0; i < connectedEdges.length; i++) {
      allEdges[connectedEdges[i]].color = {inherit: 'from'};
    }

    if( document.getElementById("build_triggers") ) {
      // set table contents.
      document.getElementById("build_triggers").innerHTML="Packages build-triggers "+
        allNodes[selectedNode].label+"("+packages_build_triggers.length+")";
      document.getElementById("packages_build_triggers").innerHTML=packages_build_triggers.join();
      document.getElementById("build_triggered").innerHTML="Packages build-triggered by "+
        allNodes[selectedNode].label+"("+packages_build_triggered.length+")";
      document.getElementById("packages_build_triggered").innerHTML=packages_build_triggered.join();
    }

    if( document.getElementById("build_triggered_transitively") ) {
      var all_packages_build_triggered = Object.keys(getAllPackagesBuildTriggered(selectedNode));

      document.getElementById("build_triggered_transitively").innerHTML="Packages build-triggered transitively by "+
        allNodes[selectedNode].label+"("+all_packages_build_triggered.length+")";
      document.getElementById("packages_build_triggered_transitively").innerHTML = all_packages_build_triggered.join();
    }

  }
  else if (highlightActive === true) {
    // reset all nodes
    for (var nodeId in allNodes) {
      if( allNodes[nodeId].set_color === undefined )
        allNodes[nodeId].color = undefined;
      else
        allNodes[nodeId].color = allNodes[nodeId].set_color;
      if (allNodes[nodeId].hiddenLabel !== undefined) {
        allNodes[nodeId].label = allNodes[nodeId].hiddenLabel;
        allNodes[nodeId].hiddenLabel = undefined;
      }
    }

    // reset all edges
    for (var edgeId in allEdges) {
      allEdges[edgeId].color = {inherit: 'from'};
    }
    highlightActive = false;
  }

  // transform the object into an array
  var updateArray = [];
  for (var edgeId in allEdges) {
    if (allEdges.hasOwnProperty(edgeId)) {
      updateArray.push(allEdges[edgeId]);
    }
  }
  edgesDataset.update(updateArray);

  // transform the object into an array
  updateArray = [];
  for (nodeId in allNodes) {
    if (allNodes.hasOwnProperty(nodeId)) {
      updateArray.push(allNodes[nodeId]);
    }
  }
  nodesDataset.update(updateArray);
}

function FindNodesByName(node_name) {
  var filtered_nodes = nodesDataset.getIds({
    filter: function(item) {
      return item.label == node_name || item.hiddenLabel == node_name;
    }
  });
  return filtered_nodes;
}

function FocusNode() {
  var node_name = document.getElementById('node_name').value;
  FocusNodeByName(node_name);
}

function FocusNodeByName(name) {
  foundNodes=FindNodesByName(name);
  if( foundNodes.length == 0 ) {
    alert( node_name + ": No such node name.");
    return false;
  }

  highlightNode(foundNodes);

  if( foundNodes.length == 1) {
    focusNode(foundNodes[0]);
  }
}

function OnKeyPress_node_name(e) {
  if( e.keyCode==13 ) {
    FocusNode();
    return false;
  }
  return true;
}

function ShowNodes(min_level, max_level) {

  // show all edges
  for(var edgeId in allEdges) {
    allEdges[edgeId].hidden = false;
  }

  for (var nodeId in allNodes) {
    if( min_level <= allNodes[nodeId].level && allNodes[nodeId].level <= max_level ) {
      allNodes[nodeId].hidden = false;
    } else {
      allNodes[nodeId].hidden = true;

      // hide all edges connected to hidden nodes.
      var edges = network.getConnectedEdges(nodeId);
      for(var i=0; i < edges.length; ++i) {
        allEdges[edges[i]].hidden=true;
      }
    }
  }

  // transform the object into an array
  var updateNodes = [];
  var updateEdges = [];
  for (nodeId in allNodes) {
    if (allNodes.hasOwnProperty(nodeId)) {
      updateNodes.push(allNodes[nodeId]);
    }
  }
  for (edgeId in allEdges) {
    if( allEdges.hasOwnProperty(edgeId)) {
      updateEdges.push(allEdges[edgeId]);
    }
  }
  nodesDataset.update(updateNodes);
  edgesDataset.update(updateEdges);
}

redrawAll();

