﻿// JScript File

var BWorks = null;

var g_nodes = null;
var g_edges = null;
var g_nodeLabels = null;
var g_setCmds = null;

var g_divNodes = null;
 
var g_layoutRootId = null;

// customizable defaults
var g_MaxNeighbors = 700;
var g_depth = 0;
var g_maxDepth = 2;

var g_domUpdateScene = null;
var g_nodeMapDom = null;
var g_nodeMap = null;

g_nodeMapDom = createXMLDomDocument();
g_nodeMapDom.async = false;

g_nodeMap = g_nodeMapDom.createElement("NodeMap");

function nodeExists(nodeId)
{
    var exists = false;

    // currently basing this on the existence of an element in the document
    // probably should base it on an element in the RadiaTree dom.
    var model = null;

    var browser = whichBrowser();

    //alert (nodeId)

    switch (browser)
    {
    case 'N':
    {
        model = document.evaluate("//*[@name='" + nodeId + "']", g_nodes, null, XPathResult.ANY_TYPE,null);
        model = model.iterateNext();
    }
    break;
    case 'M':
    {
        model = g_nodes.selectNodes("//*[@name='" + nodeId + "']").item(0);
    }	       
    break;
    default:
    break;
    }

    if (model != null)
    {
        exists = true;
    }
    //alert (nodeId + " = " + exists + " model = " + model);
    return exists;
}

    /**
    * Creates the Bridgeworks XML and page HTML for given nodeId
    * @param nodeId - the name of the Node to be created
    * @param currDepth - the Node's depth within the graph (used for styles)
    */
function createNode(nodeId, currDepth)
{
    var nodeCreated = false;

    //alert (g_nodes);

    if (!g_nodes) return nodeCreated;

    if (nodeExists(nodeId) == false)
    {				    
        var divNode = document.createElement("div");
        divNode.setAttribute("id", nodeId);    
        
        // TODO:  move this - it creates the clickable list version of the network
	    var aTag = document.createElement("a");
	    aTag.setAttribute("href", "javascript:Locate('" + nodeId + "');");
	    aTag.appendChild(document.createTextNode(nodeId));
	    aTag.appendChild(document.createElement("br"));
    	
	    divNode.appendChild(aTag);
	    g_divNodes.appendChild(divNode);	

        // Should be a cloneNode based on a template
        // in the XML dom?
	    var node = g_domUpdateScene.createElement("Model");
	    node.setAttribute("enableSharing", "false");
	    node.setAttribute("name", nodeId);
	    node.setAttribute("url", "objects/Cylinder.lwo");
	    //node.setAttribute("label", nodeId);
    	
	    var label = g_domUpdateScene.createElement("Label");
	    label.setAttribute("name", "Label_" + nodeId);
	    label.setAttribute("parent", nodeId);
	    label.setAttribute("text", nodeId);
	    label.setAttribute("fontSize", "18");
	    label.setAttribute("fontStyle", "Bold");
	    label.setAttribute("textBorderWidth", "2");
    	
    	// TODO:  Move to default graph and clone the node
	    var textColor = g_domUpdateScene.createElement("textColor");
	    textColor.setAttribute("r", ".8");
	    textColor.setAttribute("g", ".8");
	    textColor.setAttribute("b", ".8");
	    textColor.setAttribute("a", "1");
	    label.appendChild(textColor);
    	
	    var textBorderColor = g_domUpdateScene.createElement("textBorderColor");
	    textBorderColor.setAttribute("r", ".1");
	    textBorderColor.setAttribute("g", ".1");
	    textBorderColor.setAttribute("b", ".1");
	    textBorderColor.setAttribute("a", "1");
	    label.appendChild(textBorderColor);
 
    	
	    g_nodeLabels.appendChild(label);
    	
	    var scale = g_domUpdateScene.createElement("scale");
	    scale.setAttribute("x", "4");
	    scale.setAttribute("y", "4");
	    scale.setAttribute("z", "4");
	    node.appendChild(scale);
    	
	    g_nodes.appendChild(node);
	    //g_setCmds.appendChild(setCmd);
    					
	    nodeCreated = true;

    }

    return nodeCreated;
}

    /**
    * Returns true if there is an edge from n1 to n2
    * @param n1 - Edge source Node
    * @param n2 - Edge target Node
    */
function edgeExists(n1, n2)
{
    var exists = false;

    if (!g_edges) return exists;

    var edgeName = n1 + "_" + n2;
    var reverseEdgeName = n2 + "_" + n1; 

    var browser = whichBrowser();

    //alert (browser)
    var edge1 = null;
    var edge2 = null;

    switch (browser)
    {
    case 'N':
    {
        edge1 = document.evaluate("//*[@id='" + edgeName + "']", g_domUpdateScene, null, XPathResult.ANY_TYPE,null);//g_domUpdateScene.getElementById(edgeName);
        if (edge1)
        {
            edge1 = edge1.iterateNext();
        }
        edge2 = document.evaluate("//*[@id='" + reverseEdgeName + "']", g_domUpdateScene, null, XPathResult.ANY_TYPE,null);//g_domUpdateScene.getElementById(reverseEdgeName);
        if (edge2)
        {
            edge2 = edge2.iterateNext();
        }
    }
    break;
    case 'M':
    {
        edge1 = g_domUpdateScene.selectNodes("//edge[@id='" + edgeName + "']").item(0);
        edge2 = g_domUpdateScene.selectNodes("//edge[@id='" + reverseEdgeName + "']").item(0);
    }	       
    break;
    default:
    break;
    }


    //  Edges are named node1_node2
    if (edge1 || edge2)
    {
        exists = true;
    } 
    //alert (exists);
    return exists; 
}

    /**
    * Creates the Bridgeworks XML and page HTML for an edge from n1 to n2
    * @param n1 - Edge source Node
    * @param n2 - Edge target Node
    */
function createEdge(n1, n2)
{
    var edgeCreated = false;

    if (!g_edges) return edgeCreated;


    //  Edges are named node1_node2
    if (n1 != n2 && (edgeExists(n1, n2) == false))
    {
        var edgeName = n1 + "_" + n2;
        var reverseEdgeName = n2 + "_" + n1;
        
	    var aTag = document.createElement("a");
	    aTag.setAttribute("id", edgeName);
	    aTag.appendChild(document.createTextNode(edgeName));
	    aTag.appendChild(document.createElement("br"));
	    var e = document.getElementById(n1);
	    if (e) e.appendChild(aTag);

	    var edge = g_domUpdateScene.createElement("edge");
	    edge.setAttribute("id", edgeName);
	    edge.setAttribute("source", n1);
	    edge.setAttribute("target", n2);
	    g_edges.appendChild(edge);
    	
	    edgeCreated = true;
    }
    return edgeCreated;
}

/**
* Returns a comma-separated list of the given source's neighbors
* @param source - the Node for which the neighbors are to be returned
*/
function getNeighbors(source)
{
    var neighbors = null;
    
    if (parseInt(source) > 0) return;

    var cachedRow = g_nodeMap.getAttribute(source);

    if (cachedRow)
    {
        neighbors = cachedRow.split(",");
        window.status = "using cache:  " + neighbors;
    }
    else
    {
        neighbors = getNetworkForSource(source);
        if (neighbors)
        {
            g_nodeMap.setAttribute(source, neighbors);
        }
    }
        
    return neighbors;
}

/**
* Recursively build a graph from currNodeId up to maxDepth children
* (or leaves, whichever is encountered first).
* @param currNodeId - the "universal" identifier for the Node to be created and added to the Graph
* @param currDepth - the Node's depth in the Graph, used to compare against maxDepth
* @param maxDepth - the maximum depth for any Node, used to prevent arbitrarily deep graphs
*/
function buildNetworkGraph(currNodeId, currDepth, maxDepth)
{

    // can't do anything without a source
    if (!currNodeId) return;

    // capture the first source to set the RadialTree's layoutRoot
    if (!g_layoutRootId)
    {
	    g_layoutRootId = currNodeId;
    }

    // create a node in the dom
    createNode(currNodeId, currDepth);

    // evaluate the depth condition
    if (currDepth >= maxDepth) return;

    //alert (currDepth + ", " + maxDepth);

    // get all edge neighbors for this source node
    var neighbors = getNeighbors(currNodeId);

    if (neighbors && neighbors.length > 1)
    {
        var neighbor = "";
        var len = neighbors.length;
        var i = 0;
	    for (i = 0; i < len; i++)
	    {
	        neighbor = neighbors[i];
	        //alert (neighbor);
	        if (neighbor && neighbor != "undefined")
	        {
	            neighbor = neighbor.replace("\"", "");
                neighbor = neighbor.replace("\"", "");
        	    
                // check to see if we've already visited this relationship
                if (!edgeExists(currNodeId, neighbor))
                {
                    // create an edge between the current node and this neighbor
                    createEdge(currNodeId, neighbor);
                }

                if (len <= g_MaxNeighbors)
                {
                    buildNetworkGraph(neighbor, currDepth+1, maxDepth);
                }
            }
	    }
    }

}

function buildGraphForUrl(url, currDepth, maxDepth)
{
    var taggers = getTaggersForUrl(url);
    createNode(url, currDepth);
    //alert (taggers);
    var tagger = "";
    for (i = 0; i < taggers.length; ++i)
    {
        tagger = taggers[i];
        createEdge(url, tagger);
        buildNetworkGraph(tagger, currDepth, maxDepth);
    }
}

function centerGraph()
{
    if (BWorks == null)
    {
        BWorks = GetBridgeworks();
    }
    if (BWorks != null) 
    {
        BWorks.UpdateScene("CenterGraph.xml");
    }
    else alert ("BWorks is null!");
}

/**
* Initializes Attributes of the GraphLayout and 
* passes the graph XML to Bridgeworks.UpdateScene
*/
function evaluateGraph(center)
{

    //alert (g_domUpdateScene.xml);
    if (g_nodes == null || g_nodes.length < 2) return;

    var selectGraphTemplate = document.getElementById("selectGraphTemplate");
    var graphTemplate = "GraphDiagram_" + selectGraphTemplate.options[selectGraphTemplate.selectedIndex].text + ".xml";

    document.getElementById("fieldDebug").value = g_domUpdateScene.xml;
    if (BWorks == null)
    {
        BWorks = GetBridgeworks();
    }
    if (BWorks != null) 
    {
        BWorks.UpdateScene(graphTemplate);
        if (center) setTimeout("centerGraph()", 1000);
    }
    else alert ("BWorks is null!");
}

// gets the del.icio.us network for the given user
// constrained by max depth and max fans
function getNetwork(userId)
{
    Bridgeworks.UpdateScene("GraphDiagram.xml");
    
    g_domUpdateScene = createXMLDomDocument();
    g_domUpdateScene.async = false;
    
    // initialize views
    document.title = "social dna: " + userId + "'s Network...";  // page title
    //document.all["divCurrentSelection"].innerHTML = userId + "'s network.";  // info panel
    document.getElementById("divNetworkList").innerHTML = "";   // info panel

    // get the depth value from the form
    var selectMaxDepth = document.getElementById("selectMaxDepth");
    g_maxDepth = parseInt(selectMaxDepth.options[selectMaxDepth.selectedIndex].text);
   
    g_domUpdateScene.loadXML("<Update/>");
    
    var setCmd = g_domUpdateScene.createElement("Set");
    setCmd.setAttribute("target", "NodeMgr");
    setCmd.setAttribute("sgPointer", "Graph");
    g_domUpdateScene.documentElement.appendChild(setCmd);

    g_nodes = g_domUpdateScene.createElement("UpdateNodes");
    g_domUpdateScene.documentElement.appendChild(g_nodes);

    setCmd = g_domUpdateScene.createElement("Set");
    setCmd.setAttribute("target", "GraphData");
    g_domUpdateScene.documentElement.appendChild(setCmd);

    g_edges = g_domUpdateScene.createElement("edges");

    setCmd.appendChild(g_edges);


    /////////
    
    setCmd = g_domUpdateScene.createElement("Set");
    setCmd.setAttribute("target", "NodeMgr");
    setCmd.setAttribute("sgPointer", "Labels");
    g_domUpdateScene.documentElement.appendChild(setCmd);

    g_nodeLabels = g_domUpdateScene.createElement("UpdateLabels");
    g_domUpdateScene.documentElement.appendChild(g_nodeLabels);

    var locateCmd = g_domUpdateScene.createElement("Locate");
    locateCmd.setAttribute("target", "Root");
    //g_domUpdateScene.documentElement.appendChild(locateCmd);

    // create a new div to hold the nodes (every time?  better way to do this?)
    g_divNodes = document.createElement("div");
    g_divNodes.setAttribute("id", "divNodes"); 
    document.getElementById("divNetworkList").appendChild(g_divNodes); 

    // build and evaluate the graph from the given layout root
    // (the user id entered into the form)
    g_layoutRootId = userId;
    g_depth = 0;

    setCmd = g_domUpdateScene.createElement("Set");
    setCmd.setAttribute("target", "GraphData");
    setCmd.setAttribute("layoutRoot", g_layoutRootId);

    Bridgeworks.UpdateScene(setCmd.xml);
    
    if (g_layoutRootId.indexOf("http") != -1)
    {
        buildGraphForUrl(g_layoutRootId, g_depth, g_maxDepth);
    }
    else
    {
        buildNetworkGraph(g_layoutRootId, g_depth, g_maxDepth);
    }

    //g_edges.setAttribute("size", g_edges.childNodes.length);

    Bridgeworks.UpdateScene(g_domUpdateScene.xml);
    Bridgeworks.UpdateScene("ConnectGraph.xml");

    evaluateGraph();

    var btnGetTraffic = document.getElementById("btnGetTraffic");
    if (btnGetTraffic != null) btnGetTraffic.disabled=false;

    //alert (g_domUpdateScene.xml);

    document.getElementById("divScene").style.zIndex = 100010;
    document.getElementById("FrameTagCloud").style.zIndex = 100000;

}
