function netConnector(objDiv, netDoc, lines, horzLines, vertLines)
{
  var self = this;
  this.classType = "netConnector";
  
  var expandHorz = 0;
  var expandVert = 0;
  var deltaLeft = 0;
  var deltaTop = 0;
  var deltaBottom = 0;
  var deltaSps = 0;
  
  var boxChild = null;
  var boxLeft = null;
  var boxRight = null;
  
  var netConnectObjectsCreated = false;  
  var extendedMode = false;
  var vuppIndex = lshcro;

  var lineObjs = new Array(larray);
  var lineRects = new Array(larray);
  var rectThis = new netRect();
      
  this.parentDoc = netDoc;
  this.div = new netDivObject(objDiv, netDoc);

    {
      var divId = tagId(objDiv);
      var divs;
      var ids = divId.split("_");
      var i;
      var node;
      
      for (i = 0; i < larray; i++) {
        lineObjs[i] = null;
        lineRects[i] = null;
        }
        
      for (i = 1; (i < ids.length) && (i < 4); i++) {
        if (ids[i] != "null") {
          node = netDoc.getNodeByLId(parseInt(ids[i]));
          node.addConnector(this);
          if (i == 3) {
            boxChild = node;
            }
          else {
            if (boxLeft == null) boxLeft = node;
            else {
              if (boxLeft.div.getLeft() > node.div.getLeft()) {
                boxRight = boxLeft;
                boxLeft = node;
                }
              else {
                boxRight = node;
                }
              }
            }
          }
        }
        
      if (boxRight != null) {
        boxLeft.addSpouse(boxRight);
        }

      rectThis.fromDiv(this.div);

// find line divs
      divs = objDiv.getElementsByTagName("div");
      for (i = 0; i < divs.length; i++) {
        ids = tagId(divs[i]).split("_");
        var lineType = parseInt(ids[4]);
        
        lineObjs[lineType] = new netConnectObject(divs[i],lineType,this,netDoc);
        lineRects[lineType] = new netRect();
        lineRects[lineType].fromDiv(lineObjs[lineType].div);
        
        if (lineType == lshsht) extendedMode = true;
        }

      netConnectObjectsCreated = true;  
        
      lines.push(this);

      if (lineObjs[lshcro] != null) horzLines.push(lineObjs[lshcro]);
      if (lineObjs[lcvupp] != null) vertLines.push(lineObjs[lcvupp]);
      if (lineObjs[lcvmid] != null) vertLines.push(lineObjs[lcvmid]);
      if (lineObjs[lcvlow] != null) vertLines.push(lineObjs[lcvlow]);
      if (lineObjs[lchupp] != null) horzLines.push(lineObjs[lchupp]);
      if (lineObjs[lchlow] != null) horzLines.push(lineObjs[lchlow]);
      if (extendedMode) {
        if (lineObjs[lshsht] != null) horzLines.push(lineObjs[lshsht]);
        if (lineObjs[lsvsht] != null) vertLines.push(lineObjs[lsvsht]);
        if (lineObjs[lshmid] != null) horzLines.push(lineObjs[lshmid]);
        if (lineObjs[lsvcro] != null) vertLines.push(lineObjs[lsvcro]);
        }

      expandHorz = boxLeft.div.getLeft()-rectThis.left;
      expandVert = boxLeft.div.getTop()-rectThis.top;

      if (lineRects[lchupp] != null) {
        deltaLeft = lineRects[lcvmid].left-expandHorz;
        deltaTop = lineRects[lchupp].top-boxLeft.div.getHeight()-expandVert;
        }

      if (lineRects[lcvlow] != null) {
        deltaBottom = lineRects[lcvlow].height;
        }
        
      if (lineRects[lsvsht] != null) {
        deltaSps = lineRects[lsvsht].height-Math.floor(boxLeft.div.getHeight()/2);
        if (lineRects[lshsht].width > lineRects[lshcro].width) {
          vuppIndex = lshsht;
          }
        else {
          vuppIndex = lshcro;
          }
        }
    }
    
  this.registerLines = function()
    {
      if (lineObjs[lshcro] != null) netDoc.registerLineC(lineObjs[lshcro],null);
      if (lineObjs[lcvupp] != null) netDoc.registerLineC(null,lineObjs[lcvupp]);
      if (lineObjs[lcvmid] != null) netDoc.registerLineC(null,lineObjs[lcvmid]);
      if (lineObjs[lcvlow] != null) netDoc.registerLineC(null,lineObjs[lcvlow]);
      if (lineObjs[lchupp] != null) netDoc.registerLineC(lineObjs[lchupp],null);
      if (lineObjs[lchlow] != null) netDoc.registerLineC(lineObjs[lchlow],null);
      if (extendedMode) {
        if (lineObjs[lshsht] != null) netDoc.registerLineC(lineObjs[lshsht],null);
        if (lineObjs[lsvsht] != null) netDoc.registerLineC(null,lineObjs[lsvsht]);
        if (lineObjs[lshmid] != null) netDoc.registerLineC(lineObjs[lshmid],null);
        if (lineObjs[lsvcro] != null) netDoc.registerLineC(null,lineObjs[lsvcro]);
        }
    }
    
  this.box = function(objBox)
    {
      if (objBox == null) return "null";
      
      return objBox.getLId();
    };
    
  this.fullSubId = function(subId)
    {
      return this.box(boxLeft) + "_" + 
             this.box(boxRight) + "_" + 
             this.box(boxChild) + "_" + 
             subId;
    }

  this.calculateConnector = function(rectT)
    {
      if (boxChild != null) {
        if ((boxLeft.div.getLeft()-boxChild.div.getLeft()) > expandHorz) {
          expandHorz = boxLeft.div.getLeft()-boxChild.div.getLeft()+boxLeft.div.getWidth();
          }
        }
        
      if ((deltaLeft < 0) && ((Math.abs(deltaLeft)+boxLeft.div.getWidth()) > expandHorz)) {
        expandHorz = Math.abs(deltaLeft)+boxLeft.div.getWidth();
        }
        
      if ((Math.abs(deltaSps)+connectorDelta) > expandVert) {
        expandVert = Math.abs(deltaSps)+connectorDelta;
        }
/*        
      if ((Math.abs(deltaSps)+boxLeft.div.getHeight()) > expandVert) {
        expandVert = Math.abs(deltaSps)+boxLeft.div.getHeight();
        }
*/        
      rectT.left = boxLeft.div.getLeft()-expandHorz;
      rectT.top = boxLeft.div.getTop()-expandVert;
      
      var width = Math.max(boxLeft.div.getWidth(),deltaLeft);
      if (boxRight != null) width = Math.max(width,boxRight.div.getRight()-boxLeft.div.getLeft());
      if (boxChild != null) width = Math.max(width,boxChild.div.getRight()-boxLeft.div.getLeft());
      rectT.width = width + expandHorz + boxLeft.div.getWidth();
      
      var height = boxLeft.div.getHeight();
      if (boxChild != null) height = Math.max(height,boxChild.div.getBottom()-boxLeft.div.getTop());
      rectT.height = height + expandVert;
    };  
  
  this.calculateParentsLine = function(rects)
    {
      if (boxRight == null) {
        rects[lshcro].left = Math.floor(boxLeft.div.getWidth()/2) + expandHorz;
        rects[lshcro].width = 1;
        rects[lshcro].top = boxLeft.div.getHeight() + expandVert;
        }
      else {
        if (extendedMode) {
          rects[lshsht].left = boxLeft.div.getWidth() + expandHorz;
          rects[lshsht].top = Math.floor(boxLeft.div.getHeight()/2) + expandVert;
          rects[lshsht].width = Math.floor((((vuppIndex == lshsht) ? 3 : 1) * spouseSpace)/4);

          rects[lsvsht].left = rects[lshsht].left + rects[lshsht].width;
          rects[lsvsht].height = Math.floor((boxLeft.div.getHeight() / 2) + deltaSps);
          rects[lsvsht].top = rects[lshsht].top - rects[lsvsht].height;

          rects[lshmid].left = rects[lsvsht].left;
          rects[lshmid].width = boxRight.div.getLeft() - boxLeft.div.getRight() - spouseSpace;
          rects[lshmid].top = rects[lsvsht].top;
          
          rects[lsvcro].left = rects[lshmid].left + rects[lshmid].width;
          rects[lsvcro].height = rects[lsvsht].height;
          rects[lsvcro].top = rects[lsvsht].top;

          rects[lshcro].left = rects[lsvcro].left;
          rects[lshcro].width = Math.floor((((vuppIndex == lshcro) ? 3 : 1) * spouseSpace)/4);
          rects[lshcro].top = rects[lshsht].top;
          }
        else {
          rects[lshcro].left = boxLeft.div.getWidth() + expandHorz;
          rects[lshcro].top = Math.floor(boxLeft.div.getHeight()/2) + expandVert;
          rects[lshcro].width = boxRight.div.getLeft() - boxLeft.div.getRight();
          }
        }
    };  
  
  this.calculateLines = function(rectT,rects)
    {
      if (boxChild == null) return;
      
//reposition and resize lines
      rects[lcvupp].left = rects[vuppIndex].left + Math.floor(rects[vuppIndex].width / 2);
      rects[lcvupp].top = rects[vuppIndex].top;
      rects[lcvupp].height = ((boxRight == null) ? 0 : Math.floor(boxLeft.div.getHeight()/2))+deltaTop;
      
      rects[lchupp].left = Math.min(rects[lcvupp].left,expandHorz+deltaLeft);
      rects[lchupp].top = rects[lcvupp].bottom();
      rects[lchupp].width = Math.abs(expandHorz+deltaLeft-rects[lcvupp].left);
      
      rects[lcvmid].left = deltaLeft+expandHorz;
      rects[lcvmid].top = rects[lchupp].top;
      rects[lcvmid].height = boxChild.div.getTop()-boxLeft.div.getBottom()-deltaTop-deltaBottom;

      rects[lchlow].left = Math.min(rects[lcvmid].left,boxChild.div.getLeft()-rectT.left+Math.floor(boxChild.div.getWidth()/2));
      rects[lchlow].top = rects[lcvmid].bottom();
      rects[lchlow].width = Math.abs(deltaLeft+expandHorz-(boxChild.div.getLeft()-rectT.left+Math.floor(boxChild.div.getWidth()/2)));

      rects[lcvlow].left = boxChild.div.getLeft()-rectT.left+Math.floor(boxChild.div.getWidth()/2);
      rects[lcvlow].top = rects[lchlow].top;
      rects[lcvlow].height = deltaBottom;
    };
    
  this.positionConnector = function()
    {
      this.calculateConnector(rectThis);
      this.calculateParentsLine(lineRects);
      this.calculateLines(rectThis,lineRects);
        
      rectThis.toDiv(this.div);
      
      for (var i=0; i < larray; i++) {
        if (lineObjs[i] != null) {
          lineRects[i].toDiv(lineObjs[i].div);
          }
        }
    };  
    
  this.lineMoved = function(objLine)
    {
      if (objLine == lineObjs[lchupp]) {
        
        deltaTop = objLine.div.getTopC()-boxLeft.div.getBottom();
        if (deltaTop < 2) deltaTop = 2;
        }
      else if (objLine == lineObjs[lcvmid]) {
        deltaLeft = objLine.div.getLeftC()-boxLeft.div.getLeft();
        }
      else if (objLine == lineObjs[lchlow]) {
        deltaBottom = boxChild.div.getTop()-objLine.div.getTopC();
        if (deltaBottom < 2) deltaBottom = 2;
        }
      else if (objLine == lineObjs[lshmid]) {
        deltaSps = boxLeft.div.getTop()-objLine.div.getTopC();
        }
      else { // do nothing
        }      

      this.positionConnector();
      
      netDoc.registerConnectorC(this);
    };
    
  this.boxMoved = function(objBox)
    {
      this.positionConnector();
      
      netDoc.registerConnectorC(this);
    };

  this.lineObjFromId = function(id)
    {
      if (lineObjs[lshmid] != null)
        if (lineObjs[lshmid].div.getId() == id) return lineObjs[lshmid];

      if (lineObjs[lchupp] == null) return null;
      
      if (lineObjs[lchupp].div.getId() == id) return lineObjs[lchupp];
      if (lineObjs[lcvmid].div.getId() == id) return lineObjs[lcvmid];
      if (lineObjs[lchlow].div.getId() == id) return lineObjs[lchlow];
      
      return null;
    };
    
  this.addCrossings = function(other)
    {
      if (this.isSameParentPair(other)) return;

      if (netConnectObjectsCreated) {
        for (var i=0; i < larray; i++) { 
          if (lineObjs[i] != null) 
            other.processCrossings (lineObjs[i].isHorz(), lineObjs[i]);
          }
        }
      };

  this.processCrossings = function(isHorz, otherConnObj)
    {
      if (netConnectObjectsCreated) {
        for (var i=0; i < larray; i++) { 
          if (lineObjs[i] != null) {
            var isVert = lineObjs[i].isVert();
            if (isHorz == isVert) {
              this.processCrossingInternal (otherConnObj, lineObjs[i], isVert);
              }       
            }       
          }
        }
    };
    
  this.processCrossingInternal = function(otherConnObj, myConnObj, isVert)
    {
      if (crossMine == null) crossMine = new netRect();
      if (crossOther == null) crossOther = new netRect();
      
// no crossing at extended mode crossing point
      if (isVert) {
        if (((myConnObj.lineType == lsvsht) && (otherConnObj.lineType == lshcro)) ||
            ((myConnObj.lineType == lsvcro) && (otherConnObj.lineType == lshcro))) return;
        }
      else {
        if (((myConnObj.lineType == lshcro) && (otherConnObj.lineType == lsvsht)) ||
            ((myConnObj.lineType == lshcro) && (otherConnObj.lineType == lsvcro))) return;
        }  

      crossMine.copyC(myConnObj);
      crossOther.copyC(otherConnObj);

      var theyCross = crossMine.doCross(crossOther,true,isVert);

      if (!theyCross) return;

      var divId = cCrossings + "_" + otherConnObj.fullSubId() + "_" + myConnObj.fullSubId();

      if (isVert) {
        x = crossMine.left;
        y = crossOther.top;
        }
      else {
        x = crossOther.left;
        y = crossMine.top;
        }  

      var div = document.getElementById(divId);
      if (div != null) {
        div.style.left = (x - 1)+"px"; // - treeRoot.style.left;
        div.style.top = (y - 2 - ((getIsIE()) ? 7 : 0))+"px"; // - treeRoot.style.top;
        return;
        }
      
      divElem = self.parentDoc.createHtmlElement("div");
// important: id must be lower case !!!
      divElem.id = divId;
//      divElem.Id = divId;
      divElem.className = "crossing";
      divElem.style.left = (x - 1)+"px"; // - treeRoot.style.left;
      divElem.style.top = (y - 2 - ((getIsIE()) ? 7 : 0))+"px"; // - treeRoot.style.top;
      
      imgElem = document.createElement("img");
      imgElem.src = bridgeImgName;
      divElem.appendChild (imgElem);
      self.parentDoc.appendHtmlChild (divElem);
    };

  this.isConnectedBox = function(node)
    {
      if (boxLeft == node) return true;
      if (boxRight == node) return true;
      if (boxChild == node) return true;

      return false;
    };

  this.numParentBoxes = function()
    {
      return ((boxRight == null) ? 1 : 2);
    }

  this.isParentBox = function(node)
    {
      if (boxLeft.isEqual(node)) return true;
      if ((boxRight != null) && (boxRight.isEqual(node))) return true;
      return false;
    }

  this.parentPairString = function()
    {
      if (boxRight != null) {
        return boxLeft.caption()+"/"+boxRight.caption();
        }
      else {
        return boxLeft.caption();
        }
        
      return 'no parents';
    }
    
  this.isSameParentPair = function(other)
    {
      if (boxRight != null) {
        return ((other.isParentBox(boxLeft)) && (other.isParentBox(boxRight)));
        }
      else {
        return ((other.isParentBox(boxLeft)) && (other.numParentBoxes() == 1));
        }
    }

  this.isEqual = function(other)
    {
      return (this == other);
    };

  this.compare = function(other) 
    {
      return sgn(this.div.getLeft()-other.div.getLeft());
    };

  this.highlight = function(switchOn)
    {
      if (netConnectObjectsCreated) {
        this.div.movetofront(switchOn);
        for (var i=0; i < larray; i++) {
          if (lineObjs[i] != null) lineObjs[i].highlight(switchOn);
          }
        }
        
      boxLeft.highlight(switchOn,false);
      if (boxRight != null) boxRight.highlight(switchOn,false);
      if (boxChild != null) boxChild.highlight(switchOn,false);
    };

}


