/**
 * web.js ist die zentrale JavaScript Datei f�r die aktiven Komponenten des 
 * HHLA-WebPublishers. Dies Produkt basiert auf den MagicDraw WebPublisher 2.0
 * (author Siri Chongasamethaworn (siri_c@nomagicasia.com), 2.0, 11/2008) 
 * 
 * @author Hans-Christoph B�rger/IA1, Siegfried Nolte/IA1,
 *         unterst�tzt durch Peter Friese (itemis)
 * @version 1.1 01/2009
 * 
 */

var nonamedNode = '< >';
var nonamedLink = '';
var resourcesLocation = 'index_files';

// der contextPath wird in treenavigation.html global gesetzt
if(typeof (contextPath)!="undefined") { resourcesLocation = contextPath; }

// Wird eigentlich schon in treenavigation gemacht; besser ist es aber hier
// ... und durch das Setzen von resourcesLocation oben ist der Wert Stets 
// "index_files". D.h. f�r web.js wird diese Variable local gesetzt und 
// nie ge�ndert. In anderen Worten, das Ermitteln von "resourcesLocation" 
// in index.html ist f�r die JavaScripte eigentlich nicht relevant. 
if (resourcesLocation!='' && !/\/$/.test(resourcesLocation))
      resourcesLocation = resourcesLocation + '/';

/*
* tree ist eine globale Variable, die in web.js eingefuehrt wird:
* tree.elementType ergibt sich aus dem XMI-Targetnamen. 
*    (Ist dieser identisch mit 'nodeName ?)
* tree.name repraesentiert z.B. den Namen des Modellelementes (gemae� dem 
* Wert der Property 'name' des entsprechenden XMI-targets).
* tree.refId repraesentiert den Wert des eindeutigen synthetischen Schluessels.
* tree.humanType ist das XMI-Property, welches die Bezeichnung des Elementes
* in der jeweiligen Landessprache enthaelt.
* etc.
*/
var tree;          // wird benutzt im renderBrowser und im buildTree
var currentPageId; // wird benutzt in showSpec

/**
 * repaint ist eine zentrale Methode, die immer, dann aufgerufen wird, wenn sich
 * an dem Zustand des Baumes etwas �ndert. 
 *  
 * @return
 */
function repaint()
{
   var divs      = document.getElementsByTagName('div');
   for (var i=0; i<divs.length; i++)
   {
      var className = divs[i].className + ' ';
      if (className.indexOf("thead") != -1)
      {
         var headerText = divs[i].innerHTML;
         var contentNode = nextSibling(divs[i]);
         if (divs[i].hasChildNodes() && contentNode.id)
         {
            var img = document.createElement('img');
            img.src = Content.imgShow;
            img.alt = '';
            img.style.margin = '.1em';
            img.contentId = contentNode.id;
            img.onclick = function()
            {
               Content.showHide(this, this.contentId);
            };
            divs[i].insertBefore(img, divs[i].childNodes[0]);
         }
      }
   }
}

/**
 * isHiddenNode pr�ft, ob ein Modellelement das Merkmal hat, "hidden" zu sein. 
 * In dem Fall wird der Knoten nicht in den Baum geh�ngt (vgl. unsere Variante
 * mit dem ausgezeichneten Package names "Hidden").
 * 
 * @param node
 * @return
 */
function isHiddenNode(node)
{
   if (node.nodeType==1)
   {
      // do not display hidden element
      var isHidden = node.getAttribute('isHidden');
      if (isHidden == 'true') return true;
      return false;
   }
   return true;
}

/**
 * buildTree beginnt mit dem root-Knoten (li) und baut sukzessive den gesamten Baum auf.
 * Bei dem Aufbau des Baumes, vereinzelt in den Knoten, wird bereits abh�ngig von der 
 * Art des UML-Elementes eine bestimmte Manipulationen vorgenommen, z.B. hier die Aktion, 
 * dass "Hidden" Packages nicht im Baum aufgenommen werden. 
 */
function buildTree(li)
{
   var model = li.data;
   if (model == null) return;
   var childNodes = model.childNodes;
   
   for (var c=0; c<childNodes.length; c++)
   {
      if (childNodes[c].tagName == 'ownedElement')
      {
         var members = childNodes[c].childNodes;
         for (var m = 0; m<members.length; m++)
         {
            if (isHiddenNode(members[m])) continue;
            
            var emptyUL = document.createElement('ul');

            emptyUL.onExpand = function() 
            {
               var node = this.parentNode;
               if (this.hasChildNodes()) { return; }
               
               var childNodes = node.data.childNodes;
               for (var c=0; c<childNodes.length; c++)
               {
                  if (childNodes[c].tagName == 'ownedElement')
                  {
                     var groupMap = new Array();
                     var members = childNodes[c].childNodes;
                     for (var p = 0; p<members.length; p++)
                     {
                        if (members[p].nodeType==1)
                        {
                           // TODO ???
                           if (isHiddenNode(members[p]) || members[p].tagName == 'diagram') continue;

                           // display element, icon
                           var icon = members[p].getAttribute('icon');
                           var childNode = null;

                           if (members[p].getAttribute('isRelationship')=='true')
                           {
                               // Relationship-Elemente werden nicht im Baum aufgenommen
                           }
                           else
                           {
                              if ( members[p].tagName=='package' &&  members[p].getAttribute('name')=='Hidden')
                              {
                                  // Packages namens 'Hidden' sollen im Baum nicht aufgenommen werden
                              }
                              else
                              {
                                // f�r alle anderen member gilt: keine relationships, keine hidden packages  

                            	  var groupBy = members[p].getAttribute('groupBy');
                                 if (groupBy)
                                 {
                                   // TODO ???
                                    if (!groupMap[groupBy]) groupMap[groupBy] = new Array();
                                    groupMap[groupBy][groupMap[groupBy].length] = members[p];
                                 }
                                 else
                                 {
                                    var name;
                                    
                                    if (members[p].getAttribute('name'))
                                       name = members[p].getAttribute('name');
                                    else 
                                      // nonamedNode ist eine "Klassenvariable"
                                       name = nonamedNode || nonamedNode == '' ? nonamedNode : members[p].getAttribute('humanType');
                                    
                                    childNode = addNode(this, name, "javascript: showSpec('"+members[p].getAttribute('refid')+"');", icon);
                                    childNode.data  = members[p];
                                    childNode.refid = members[p].getAttribute('refid');
                                    
                                    if (groupMap)
                                    {
                                      var childGroup = groupMap[childNode.refid];
                                       if (childGroup)
                                       {
                                          var tmpOwnedElement;
                                          var tmpChildNodes = childNode.data.childNodes;
                                          for (var tmp=0; tmp<tmpChildNodes.length; tmp++)
                                          {
                                             if (tmpChildNodes[tmp].tagName=='ownedElement')
                                             {
                                                tmpOwnedElement = tmpChildNodes[tmp];
                                                break;
                                             }
                                          }
                                          if (typeof(tmpOwnedElement)=='undefined')
                                          {
                                             tmpOwnedElement = createElement('ownedElement');
                                             childNode.data.appendChild(tmpOwnedElement);
                                          }
                                          if (tmpOwnedElement)
                                          {
                                             for (var g=0; g<childGroup.length; g++)
                                             {
                                                childGroup[g].removeAttribute('groupBy');
                                                tmpOwnedElement.appendChild(childGroup[g]);
                                             }
                                          }
                                       }
                                    }
                                 }
                              }
                           }
                           // Abstieg in die n�chste Ebene
                           if (childNode != null) buildTree(childNode);
                        }
                     }
                  } // childNodes == ownedElement
                  else if (childNodes[c].tagName == 'ownedDiagram')
                  {
                     var members = childNodes[c].childNodes;
                     for (var m = 0; m<members.length; m++)
                     {
                        if (members[m].nodeType==1)
                        {
                           var icon = members[m].getAttribute('icon');
                           var name = members[m].getAttribute('name');
                           var childNode = addNode(this, name, "javascript: showSpec('"+members[m].getAttribute('refid')+"');", icon);
                           childNode.data = members[m];
                           childNode.refid = members[m].getAttribute('refid');
                           // comment below and uncomment buildTree(childNode) to see diagram inner node
                           tree.renderNode(childNode);
                           // buildTree(childNode);
                        }
                     }
                  }
               }
            };
            
            li.appendChild(emptyUL);
            
            break;
         } //endfor
      } // endif
   } // endfor

   tree.renderNode(li);
}

/**
 * Search and return tree node from refid
 * 
 * findNode sucht nach einem Knoten, der im Diagramm angeklickt worden ist, im Baum.
 * Geliefert wird eine Referenz auf den Knoten. findNode wird zur Zeit nicht gebraucht;
 * TODO Anforderung: Anklicken im Diagramm und �ffnen des Baumes an der Stelle des Knotens. 
 * 
 * @param refid
 * @return LI tree node
 */ 
function findNode(refid)
{
   var searchResults = new Array(0);
   var dataModel = tree.root.firstChild.data;
   var regx = new RegExp(refid, 'i');
   match(dataModel, 'refid', regx, searchResults);
   if (searchResults.length == 1)
   {
      var parentNode = searchResults[0];
      var nodePath = new Array();
      while (parentNode.tagName != 'magicdraw') 
      { 
         if (parentNode.nodeType==1)
         {
            var refid = parentNode.getAttribute('refid');
            if (refid)
               nodePath[nodePath.length] = refid;
            parentNode = parentNode.parentNode; 
         }
      }
      var rootTree = document.getElementById(tree.treeId);
      expandPath(nodePath);
      searchResults = new Array(0);
      match(rootTree, 'refid', regx, searchResults);
      return searchResults[0];
   }
   return null;
}

/**
 * Select node on containment tree

 * selectNode selektiert den Knoten im Baum. selectNode wird zur Zeit nicht gebraucht;
 * TODO Anforderung: Anklicken im Diagramm und �ffnen des Baumes an der Stelle des Knotens. 

 * @param node LI or A element of tree node
 */
function selectNode(node)
{
   if (node)
   {
      if (node.tagName == 'LI')
      {
         var childNodes = node.childNodes;
         for (var i=0; i<childNodes.length; i++)
         {
            if (childNodes[i].name == 'anchorNode')
            {
               var root = document.getElementById(tree.treeId);
               var nodes = root.getElementsByTagName('li');
               for (var n=0; n<nodes.length; n++)
               {
                  var anchorNodes = nodes[n].childNodes;
                  for (var a=0; a<anchorNodes.length; a++)
                  {
                     if (anchorNodes[a].name == 'anchorNode')
                        anchorNodes[a].style.backgroundColor = '';
                  }
               }
               childNodes[i].style.backgroundColor = '#99CCFF';
            }
         }
      }
      else if (node.tagName == 'A')
      {
         if (node.name == 'anchorNode')
         {
            var root = document.getElementById(tree.treeId);
            var nodes = root.getElementsByTagName('li');
            for (var n=0; n<nodes.length; n++)
            {
               var anchorNodes = nodes[n].childNodes;
               for (var a=0; a<anchorNodes.length; a++)
               {
                  if (anchorNodes[a].name == 'anchorNode')
                     anchorNodes[a].style.backgroundColor = '';
               }
            }
            node.style.backgroundColor = '#99CCFF';
         }
      }
   }   
}

/**
 * Jeder Knoten entspricht einem Element des Dokumentes.
 * D.h. mit addNode wird dem Dokument ein neues Element hinzugef�gt,
 * und zwar ein List-item. Das Element f�r die "Unordered List" an sich
 * ist der Root-Knoten.
 */
function addNode(ul, nodeName, href, icon)
{
   var node = document.createElement('li');
   node.elementName = nodeName;
   var anchor = document.createElement('a');
   anchor.appendChild(document.createTextNode(nodeName));
   anchor.name = 'anchorNode';
   anchor.href = href;
   anchor.style.verticalAlign = 'middle';
   anchor.style.marginLeft = '4px';
   anchor.style.marginRight = '4px';
   anchor.onclick = function() {  selectNode(this);  };

   node.appendChild(anchor);

   if (icon)
   {
      var imgAnchor = document.createElement('a');
      imgAnchor.href = href;
      imgAnchor.style.verticalAlign = 'middle';
      imgAnchor.onclick = anchor.onclick;
      var img = document.createElement('img');
      img.src = icon;
      img.alt = '';
      img.border = '0';
      img.height = '16';
      img.width = '16';
      img.style.verticalAlign = 'middle';
      imgAnchor.appendChild(img);
      node.insertBefore(imgAnchor, anchor);
   }
   ul.appendChild(node);
   return node;
}

/**
 * Shortcut to create HTML element with link
 * @param parentNode link container
 * @param linkToElement DOM element
 */
function createLink(parentNode, linkToElement)
{
   var refid = linkToElement.getAttribute('refid');
   var name = linkToElement.getAttribute('name');
   var icon = linkToElement.getAttribute('icon');
   if (icon)
   {
      var fieldAnchor = document.createElement('a');
      fieldAnchor.href = "javascript: showSpec('"+refid+"');";
      var fieldImage = document.createElement('img');
      fieldImage.alt = '';
      fieldImage.border = '0';
      fieldImage.height = '16';
      fieldImage.width = '16';
      fieldImage.src = icon;
      fieldAnchor.appendChild(fieldImage);
      parentNode.appendChild(fieldAnchor);
   }
   if (!name) name = nonamedLink||nonamedLink==''?nonamedLink:linkToElement.tagName;
   if (refid && name != '')
   {
      var fieldAnchor = document.createElement('a');
      fieldAnchor.href = "javascript: showSpec('"+refid+"');";
      fieldAnchor.style.marginLeft = '4px';
      fieldAnchor.style.marginRight = '4px';
      fieldAnchor.appendChild(document.createTextNode(name));
      parentNode.appendChild(fieldAnchor);
   }
   else
   {
      parentNode.appendChild(document.createTextNode(name));
   }
   var additionalText = linkToElement.getAttribute('text');
   if (additionalText)
   {
      var cite = document.createElement('cite');
      cite.style.marginLeft = '4px';
      cite.style.marginRight = '4px';
      renderValueText(cite, additionalText);
      parentNode.appendChild(cite);
   }
}

/**
 * Value node renderer
 * @param value a HTML element containing value
 * @param element DOM element
 */
function renderValueNode(value, element)
{
   var text = nodeValue(element);
   renderValueText(value, text);
}

/**
 * Value text renderer
 * @param value a HTML element containing value
 * @param text text to display
 */
function renderValueText(value, text)
{
   if (text && text.indexOf('<html>')==0)
   {
      var startBodyIndex = text.indexOf('<body>');
      var endBodyIndex = text.indexOf('</body>', startBodyIndex);
      if (startBodyIndex>0 && endBodyIndex > 0)
      {
         var htmlContent = text.substring(startBodyIndex, endBodyIndex);
         value.innerHTML = htmlContent;
      }
   }
   else
   {
      var tokens = (' ' + text).split(/(\r\n|[\r\n])/g);
      if (tokens.length > 1)
      {
         for (var t=0; t<tokens.length; t++)
         {
            if (tokens[t].indexOf('http://')==1 || tokens[t].indexOf('file://')==1)
            {
               var anchor = document.createElement('a');
               anchor.href = tokens[t];
               anchor.target = '_blank';
               anchor.appendChild(document.createTextNode(tokens[t]));
               value.appendChild(anchor);
            }
            else
               value.appendChild(document.createTextNode(tokens[t]));
            value.appendChild(document.createElement('br'));
         }
      }
      else
      {
         if (tokens[0].indexOf('http://')==1 || tokens[0].indexOf('file://')==1)
         {
            var anchor = document.createElement('a');
            anchor.href = tokens[0];
            anchor.target = '_blank';
            anchor.appendChild(document.createTextNode(tokens[0]));
            value.appendChild(anchor);
         }
         else
            value.appendChild(document.createTextNode(tokens[0]));
      }
   }
}
/**
 * renderBrowser baut den gesamten Baum als interne Struktur auf, die unter
 * der globalen Variable "tree" zur Verf�gung steht. 
 * 
 * Render browser tree
 * @param responseXML a xml
 */
function renderBrowser(responseXML)
{
   // Das gesamte Modell wird von einer XML-Struktur namens "magicdraw"
   // umgeben <=> es handelt sich um ein Magicdraw-Modell. Diese XML
   // Struktur wird der JavaScript Variablen "magicdraw" zugewiesen. 
   var magicdraw = responseXML.getElementsByTagName('magicdraw')[0];
   
   if (magicdraw != null)
   {
      showLoading();
      var root = document.createElement('ul');
      root.id = 'tree';
      
      tree = new Tree(root.id); // Struktur in tree.js
      tree.image.plus  = resourcesLocation + '/images/tree/plus.gif';
      tree.image.minus = resourcesLocation + '/images/tree/minus.gif';
      tree.root = root;

      // Die Funktion firstChild ist in magiccat definiert. Sie liefert das erste
      // Kindelement der �bergebenen Struktur.
      // Innerhalb von magicdraw befindet sich als erstes Strukturelement das 
      // Modell. Dies ist gewisserma�en das �u�erste Paket. Das Modell wird
      // an die Variable dataModel �bergeben. 
      var dataModel = firstChild(magicdraw); 

      // Die Knoten repr�sentieren die Elemente des Modells, die im Baum 
      // angezeigt werden sollen. Diese Elemente enthalten bereits die 
      // Referenzen auf die Properties, die im infoframe angezeigt werden 
      // sollen.
      var node = addNode (    root, 
                        dataModel.getAttribute('name'), 
                        "javascript: showSpec('" + dataModel.getAttribute('refid') + "');", 
                        dataModel.getAttribute('icon')
                       );
      node.data = dataModel;
      node.setAttribute('refid', dataModel.getAttribute('refid'));
      buildTree(node);

      // Hier wird in der Datei treenavigation.html ein Element mit dem Nameb "browser" gesucht 
      // (es handelt sich dabei um ein div-Element).
      // In dieses Element wird nun die soeben aufgebaute Struktur aus UL/LI-Knoten eingeh�ngt.
      var browser = document.getElementById('browser');
      browser.appendChild(root);
      
      // Die erste Ebene des Baums aufklappen:
      tree.expand(node);
      
      // Fortschrittsbalken ausblenden:
      hideLoading();
   }
}

/**
 * renderModel
 * @param responseXML ist ein spezielles Element im Modell
 * 
 * renderModel nimmt das aktuelle Element des Modellbaumes und bereitet dies 
 * mittels 'renderDiagram' oder 'renderElement' f�r eine Anzeige im Browser auf.
 * Diagramme, Packages und sonstige Elemente werden dabei unterschiedlich behandelt.   
 */
function renderModel(responseXML)
{
   var magicdraw = responseXML.getElementsByTagName('magicdraw')[0];
   if (magicdraw == null)
   {
      alert('This element was not generated from project.');
      return;
   }

   // firstChild liefert die erste Ebene der DOM-Struktur, das ist im Fall von
   // magicdraw-Modellen stets das Element an sich, also erst kommt die <magicdraw>-
   // Ebene, dann das Element, <package>, <model> etc. 
   var model = firstChild(magicdraw);
   if (model.tagName == 'diagram')     renderDiagram(model);
   else if (model.tagName =='package') renderPackage(model);
        else renderElement(model);
   repaint();
}

/**
 * Aufbereitung von Packages - Packages sollen zun�chst wie sonstige Elemente
 * behandelt werden, also Anzeige ihrer Eigenschaften im infoframe (renderElement). 
 * Falls es ein ContentDiagramm mit demgleichen Namen wie der des Packages gibt, 
 * soll dies im diagrammframe angezeigt werden, aber nicht dessen Eigenschaften im
 * Infoframe.  
 *   
 * @param model ist ein Package [<refid>.xml]
*/
function renderPackage(model)
{
    // Zuerst den Namen des Packages ermitteln. Dieser ergibt sich aus dem 
	// Childknoten mit Tag-Namen "name".
    var packagename = "";
    var childNodes = model.childNodes;
    for (var c = 0; c < childNodes.length; c++) 
    {
       if (childNodes[c].tagName == 'name') 
       {
         packagename = childNodes[c].text;
         break;
       }
    }

    if ( packagename == "" ) { alert ("Package ohne Namen  " ); return; }

    var diagram = null;
    // Suche nach Diagrammen, insbesondere nach einem ContentDiagram  
    // mit dem Namen des Packages.  
    for (var c = 0; c < childNodes.length; c++) 
    {
       // Diagramm sind in der Gruppe der ownedElements, also erst die Gruppe ermitteln ...   
       if (childNodes[c].tagName == 'ownedElement') 
       {
          var members = childNodes[c].childNodes;
          for (var m = 0; m<members.length; m++) 
          {
              // ...  dann darin das entsprechende Diagramm, das mit demgleichen Namen,
        	  // wie das Package.
             if ( members[m].tagName == 'diagram' 
               && packagename == members[m].getAttribute("name") ) 
             {
                diagram = members[m];
                elementId = diagram.getAttribute("refid");
                //XML.load(resourcesLocation + '/xml/' + elementId + '.xml', renderModel);
                XML.load(resourcesLocation + '/xml/' + elementId + '.xml', renderPackageDiagram);
             }
          }
       }
    }
    // Anzeige der Attribute des Packages 
    renderElement(model);
}

/**
 * renderPackageDiagram ist eine Hilfsfunktion f�r renderPackage. Sie dient
 * ausschlie�lich dazu, zu Packages das ContentDiagram mit gleichem Namen 
 * anzuzeigen, wenn dies existiert. (vgl. renderModel)
 *  
 *  @param model ist ein Package [<refid>.xml]
 */
function renderPackageDiagram(responseXML)
{
   var magicdraw = responseXML.getElementsByTagName('magicdraw')[0];
   if (magicdraw == null)
   {
      alert('This element was not generated from project.');
      return;
   }
   var model = firstChild(magicdraw);
   if (model.getAttribute ("diagramType") == "Content Diagram")
   {
      var diagrammframe = parent.diagrammframe;
      var location = currentDir() + "/" + "diagram/" + model.getAttribute("id") + ".html";
      diagrammframe.location.href = location;
   }
   
   // Wieso werden hier Diagramm und Diagramminfos angezeigt?
}
/**
 * renderElement bereitet ein konkretes Modellelement auf, welches nicht Diagramm 
 * oder Package ist. Alle Elemente sind zun�chst in einer entsprechenden xml-Datei 
 * spezifiziert. Zudem gibt es je Modellelement in dem Unterverzeichnis des 
 * Elementtyps (z.B. activity) eine entsprechende HTML-Datei <refid>.html. Der
 * Inhalt dieser Datei wird im infoframe angezeigt. F�r relations gilt, diese 
 * Eigenschaftsdateien befinden sich grunds�tzlich im Verzeichnis "relation".
 *
 * @param model ist ein Package [<refid>.xml]
 */
function renderElement(model)
{
   var infoframe = parent.infoframe;
   var modelNodeName = model.nodeName;

   /*
    * Wenn es sich bei dem Knoten um einen Beziehungstyp handelt, dann soll
    * im Verzeichnis 'relation' die HTML-Datei der Beziehung referenziert werden. 
    * Ansonsten wird die 'content.html' Datei aus dem entsprechenden Verzeichnis
    * des Knotens referenziert. Ein offenes Problem ist noch, wie mit dem 
    * Knoten 'associationclass' verfahren werden soll. Zur Zeit wird die Datei
    * in dem Verzeichnis 'relation' ausgew�hlt. Die Frage stellt sich allerdings 
    * noch nicht, da beide Dateien durch Auskommentierung einen identischen Inhalt 
    * anzeigen. 
    * Folgende komplexe Abfrage, in der alle template-Dateien des Verzeichnisses
    * 'relation' abgefragt werden, kann ggf. durch die Methode isRelationship 
    * ersetzt werden.  
    */
   if ( model.nodeName == 'abstraction' )          modelNodeName = 'relation';  
   if ( model.nodeName == 'association' )          modelNodeName = 'relation';  
   if ( model.nodeName == 'associationclass' )     modelNodeName = 'relation';  
   if ( model.nodeName == 'communicationpath' )    modelNodeName = 'relation';  
   if ( model.nodeName == 'componentrealization' ) modelNodeName = 'relation';  
   if ( model.nodeName == 'connector' )            modelNodeName = 'relation';  
   if ( model.nodeName == 'controlflow' )          modelNodeName = 'relation';  
   if ( model.nodeName == 'dependency' )           modelNodeName = 'relation';  
   if ( model.nodeName == 'deployment' )           modelNodeName = 'relation';  
   if ( model.nodeName == 'elementimport' )        modelNodeName = 'relation';  
   if ( model.nodeName == 'exceptionhandler' )     modelNodeName = 'relation';  
   if ( model.nodeName == 'extend' )               modelNodeName = 'relation';  
   if ( model.nodeName == 'extension' )            modelNodeName = 'relation';  
   if ( model.nodeName == 'generalization' )       modelNodeName = 'relation';  
   if ( model.nodeName == 'include' )              modelNodeName = 'relation';  
   if ( model.nodeName == 'interfacerealization' ) modelNodeName = 'relation';  
   if ( model.nodeName == 'manifestation' )        modelNodeName = 'relation';  
   if ( model.nodeName == 'objectflow' )           modelNodeName = 'relation';  
   if ( model.nodeName == 'packageimport' )        modelNodeName = 'relation';  
   if ( model.nodeName == 'packagemerge' )         modelNodeName = 'relation';  
   if ( model.nodeName == 'protocoltransition' )   modelNodeName = 'relation';  
   if ( model.nodeName == 'realization' )          modelNodeName = 'relation';  
   if ( model.nodeName == 'relation-content' )     modelNodeName = 'relation';  
   if ( model.nodeName == 'relation-frame' )       modelNodeName = 'relation';  
   if ( model.nodeName == 'substitution' )         modelNodeName = 'relation';  
   if ( model.nodeName == 'templatebinding' )      modelNodeName = 'relation';  
   if ( model.nodeName == 'transition' )           modelNodeName = 'relation';  
   if ( model.nodeName == 'usage' )                modelNodeName = 'relation';  

   var location = currentDir() + "/" + modelNodeName + "/" + model.getAttribute("id") + ".html";
   infoframe.location.href = location;
}

/**
 * Zu Diagrammen wird auf der einen Seite die Information des Diagrammes angezeigt
 * (vgl. renderElement) und auf der anderen Seite das Diagramm selbst im 
 * diagrammframe. 
 * @param model ist ein Package [<refid>.xml]
 */
function renderDiagram(model)
{
   var diagrammframe = parent.diagrammframe;
   var location = currentDir() + "/" + "diagram/" + model.getAttribute("id") + ".html";
   diagrammframe.location.href = location;
}

/**
 * Show element linked page
 * @elementId element id
 */
function showElementLink(elementId, keepStack)
{
   XML.load(resourcesLocation + '/xml/' + elementId + '.xml', renderModel);
}

/**
 * showSpec ist die Methode, die mit dem Element im Baum verkn�pft wird. 
 * D.h. wenn dort ein Element angeklickt wird, dann wird explizit showSpec
 * auferufen und damit implizit renderModel. 
 * 
 * @elementId element id
*/
function showSpec(elementId )
{
   XML.load(resourcesLocation + '/xml/' + elementId + '.xml', renderModel);
   currentPageId = elementId;
}

/**
 * Expand node path
 */
function expandPath(nodePath)
{
   stopexpand = false;
   var rootTree = document.getElementById(tree.treeId);
   var path = nodePath.length - 1;
   internalExpandPath(rootTree, nodePath, path);
}

/** we already found node stop searching and collapse investigating node */
var stopexpand = false;
function internalExpandPath(rootNode, nodePath, path)
{
   if (path < 0 || stopexpand) return;
   var childNodes = rootNode.childNodes;
   var content = document.getElementById('content');
   if (childNodes)
   {
      for (var c=0; c<childNodes.length; c++)
      {
         if (childNodes[c].tagName == 'UL')
            internalExpandPath(childNodes[c], nodePath, path);
         else if (childNodes[c].tagName == 'LI')
         {
            var refid = childNodes[c].getAttribute('refid');
            childNodes[c].internalExpand = false;
            if (refid == 'relations')
            {
               // if node already expand, left it expand
               if (childNodes[c].lastChild && !childNodes[c].lastChild.isExpanded)
               {
                  tree.expand(childNodes[c]);
                  // mark as node is expanded for investigating                  
                  childNodes[c].internalExpand = true;
               }
               internalExpandPath(childNodes[c], nodePath, path);
            }
            else if (refid == nodePath[path])
            {
               // if node already expand, left it expand
               if (childNodes[c].lastChild && !childNodes[c].lastChild.isExpanded)
               {
                  tree.expand(childNodes[c]);
                  // mark as node is expanded for investigating                  
                  childNodes[c].internalExpand = true;
               }
               internalExpandPath(childNodes[c], nodePath, --path);
            }
            // if found target node then stop expanding
            if (path == -1)
               stopexpand = true;
            if (!stopexpand)
            {
               // collapse node that use for investigating.                  
               if (childNodes[c].internalExpand)
                  tree.collapse(childNodes[c]);
            }
         }
      }
   }
}

//---------------------------------------------------------------------
// Funktionen f�r die Search-Option
//---------------------------------------------------------------------

/**
 * Trim string
 * @param input string
 * @return output string
 */
function trim(aB){return aB.replace(/^\s*|\s*$/g,'');}

/**
 * Test matches node with regular expression
 */
function match(node, regx, searchResults)
{
   if (node.tagName == 'ownedDiagram')
      return;
   if (node.nodeType==1)
   {
      var name = node.getAttribute('name');
      if ((name=='' || name) && regx.test(name))
         searchResults[searchResults.length] = node;
   }
   if (node.hasChildNodes)
   {
      var childNodes = node.childNodes;
      for (var i=0; i<childNodes.length; i++)
         match(childNodes[i], regx, searchResults);
   }
}

/**
 * Test matches node with regular expression
 */
function match(node, attr, regx, searchResults)
{
   if (node.tagName == 'ownedDiagram')
      return;
   if (node.nodeType==1)
   {
      var name = node.getAttribute(attr);
      if ((name=='' || name) && regx.test(name))
         searchResults[searchResults.length] = node;
   }
   if (node.hasChildNodes())
   {
      var childNodes = node.childNodes;
      for (var i=0; i<childNodes.length; i++)
         match(childNodes[i], attr, regx, searchResults);
   }
}

/**
 * Search function. Regular expression can be used with element name.
 * @param elementName name of element being search.
 */
function search(elementName)
{
   if (tree.root)
   {
      showLoading();
      var dataModel = tree.root.firstChild.data;
      var regx; 
      try
      {
         regx = new RegExp(trim(elementName), 'i');
      }
      catch (e)
      {
         alert('Invalid search pattern \nReason: ' 
        	  + e.message 
        	  + '\nPlease validate regular expression syntax in search text');
      }
      if (regx)
      {
         var searchResults = new Array(0);
//         match(dataModel, regx, searchResults);
         match(dataModel, 'name', regx, searchResults);
         
         // Fenster zum Anzeigen der Suchergebnisse
         searchWindow = window.open
         ( currentDir() + "/empty.htm",
           "searchResult",
           "width=600,"
         + "height=400,"
         + "screenX=0,"
         + "screenY=0,"
         + "resizable=yes,"
         + "dependent=yes,"
         + "scrollbars=yes"
         );

         // var doc = top.diagrammframe.document;
         var doc = searchWindow.document;

         doc.write('<html><head><title>Suchergebnisse</title>'
               + '<link rel ="stylesheet" type="text/css" href="'
               + currentDir() + '/stylesheet.css" title="style">'
               + '</head><body>');
         doc.write("<h4>Suchergebnisse</h4><br>");
         
         if (searchResults.length > 0)
         {
            for (var p=0; p<searchResults.length; p++)
            {
               var linkToElement = searchResults[p];
               if (linkToElement.nodeType==1)
               {
                  var refid = linkToElement.getAttribute('refid');
                  var name = linkToElement.getAttribute('name');
                  var icon = top.navigationsframe.currentDir() + "/" + linkToElement.getAttribute('icon');
                  var humanType = linkToElement.getAttribute('humanType');
                  var href = "javascript: top.navigationsframe.showSpec('" + refid + "');";
                  doc.write("<img src='" + icon + "'> <a href=\"" + href + "\" target='diagrammframe'>" + name + " (" + humanType + ")</a><br/>");
               }
            }
         }
         else
         {
            doc.write("(keine Treffer)");
         }
         doc.write("</body></html>");
         searchWindow.focus();
      }
   }
   hideLoading();
}

//---------------------------------------------------------------------
// generelle Funktionen 
//---------------------------------------------------------------------

function showHelp ()
{
     helpWindow = window.open
      ( currentDir() + "/HelpDiagram.html",
        "helpwindow",
        "width=600,"
      + "height=800,"
      + "screenX=5000,"
      + "screenY=50,"
      + "resizable=yes,"
      + "dependent=yes,"
      + "scrollbars=yes"
      );
     helpWindow.focus();
}

/**
 * Funktion liefert die Top-URL (Ort der index.html).
 * @param elementName name of element being search.
 */
function currentDir() 
{
   var href= top.navigationsframe.location.href;
   var slash = href.lastIndexOf("/");
   var path = href.substring(0, slash);
   return path;
}