var winWidth = $(window).width(),
winHeight = $(window).height();

function RelationBrowser(properties) {
  Shared.Copy(properties, this);
  this.Init();
}

RelationBrowser.LogicalIDToInstanceMap = {};
RelationBrowser.GetInstance = function(id) {
  return RelationBrowser.LogicalIDToInstanceMap[id];
};

RelationBrowser.prototype = {
  Init:function(boolNotNewInit) {
    this.InputID = this.ID + "_Input";
    this.CanvasID = this.ID + "_Canvas";
    RelationBrowser.LogicalIDToInstanceMap[this.LogicalID] = this;
    var container = Shared.GetElementById(this.ID);
    if(boolNotNewInit==null || boolNotNewInit==false) {
      Shared.AddHandler(container, "click", Shared.CreateDelegate(this, this.ClickHandler));
      Shared.AddHandler(container, "dblclick", Shared.CreateDelegate(this, this.DoubleClickHandler));
    }
    Shared.SetInnerHTML(container, "<canvas id='" + this.CanvasID + "' width='" + this.Width + "' height='" + this.Height + "'></canvas><div id='" + this.InputID + "'></div>");
    if(boolNotNewInit==null || boolNotNewInit==false) {
      Shared.AddLoadHandler(Shared.CreateDelegate(this, function() { this.LoadData(); }));  
         $(window).resize({"RelationalBrowser": this}, function(e) {
           
           var OnResize = function(e) {
              var height = Shared.GetWindowHeight()*.75;
              var width = Shared.GetWindowWidth()*.75;
              e.data.RelationalBrowser.Width = width;
              e.data.RelationalBrowser.Height = height;
              e.data.RelationalBrowser.Init(true);
              e.data.RelationalBrowser.RenderLoaded(window.newData);
           };
           
           if(Shared.IsIE()) {
            /*var winNewWidth = $(window).width(),
            winNewHeight = $(window).height();
            var resizeTimeout=null;
            if(winWidth!=winNewWidth || winHeight!=winNewHeight)
            {
              window.clearTimeout(resizeTimeout);
              resizeTimeout = window.setTimeout(function(){OnResize(e)}, 10);
            }
            //Update the width and height
            winWidth = winNewWidth;
            winHeight = winNewHeight;*/
           } 
           else if(window.newData) {
             OnResize(e);
           }
        }                
       );
    }
    
   
  },
  ClickHandler:function(e) {
    Shared.CancelEvent(e);
    var target = Shared.GetTargetElement(e);
    if(target ==null) return;    
    if(!target.getAttribute("HasUrl")) { target = Shared.GetAncestor(target, function(ancestor) { return ancestor.getAttribute && ancestor.getAttribute("HasUrl"); }); }
    if(target ==null) return;    
    var url = target.getAttribute("Url") || target.parentNode.getAttribute("Url");
    //Patrick Changed
    var WSMethod = target.getAttribute("WSMethod") || target.parentNode.getAttribute("WSMethod");
    var WSParams = target.getAttribute("WSParams") || target.parentNode.getAttribute("WSParams");
    if(WSParams) {
        WSParams = eval(WSParams);
    }
    if(url && !target.getAttribute("ExternalUrl")) {
      this.LoadData(url,WSMethod,WSParams);
    } else {
      url = target.getAttribute("ExternalUrl") || target.parentNode.getAttribute("ExternalUrl");
      if(url) {
        OpenModal(e,{'url': url});
      }
    }
  },
  DoubleClickHandler:function(e) {
    Shared.CancelEvent(e);
    Shared.ClearTimeout(this.ClickHandlerTimeoutID);
    var target = Shared.GetTargetElement(e);
    if(!target.getAttribute("HasUrl")) { target = Shared.GetAncestor(target, function(ancestor) { return ancestor.getAttribute && ancestor.getAttribute("HasUrl"); }); }
    this.OpenExternalUrl(target);
  },
  OpenExternalUrl:function(target) {
    var url = target && target.getAttribute("ExternalUrl");
    if(url) {
      Shared.ActionTargetUrl(this, url, Shared.FRAME_TYPE_POPUP, "name" + new Date().getTime());
    }
  },
  LoadData:function(url,WSMethod,WSParams) {
    this.RenderLoading();
    //Patrick Chagned
    Shared.InvokeWebService(this.ID, this.ID, url || this.DefaultUrl, WSMethod || this.WSMethod, 0, 0, WSParams || this.WSParams, 0, 0, Shared.CreateDelegate(this, this.LoadDataCompleted));
  },
  LoadDataCompleted:function(handlerCallbackParams) {
    if(handlerCallbackParams.Succeeded) {
      try {
        //Patrick Changed
        var newData = eval(handlerCallbackParams.Result.d);
        window.newData = newData;
        this.RenderLoaded(newData);
      } catch(e) {
        //alert("Error in LoadDataCompleted:\r\n" + e.message);
      }
    } else {
       alert("Response Not Available!\r\nStatus Code: " +  handlerCallbackParams.StatusCode + "\r\nStatus Text: " +  handlerCallbackParams.StatusText);
    }
  },
  RenderLoading:function() {
  },
  GetTypeToCSSClassMap:function(node) {
    var css = this.CSS;
    var typeToCSSClassMap = {};
    typeToCSSClassMap[node.Type] = 0;
    if(node.Back) { typeToCSSClassMap[node.Back.Type] = 0; }
    if(node.More) { typeToCSSClassMap[node.More.Type] = 0; }
    Array.forEach(node.Relations, function(relation) { typeToCSSClassMap[relation.Type] = 0; });
    Shared.For(typeToCSSClassMap, function(type) {
      var cssClass = css.Node + type;
      typeToCSSClassMap[type] = {NodeContainer:cssClass + "_container", Node:css.Node + " " + cssClass};
    });
    return typeToCSSClassMap;
  },
  RenderLoaded:function(node) {
      var canvasElement = Shared.GetElementById(this.CanvasID);
      if(canvasElement.getContext) {
      var inputHTML = [];
        var canvasBounds = Shared.GetBounds(canvasElement);
      var canvasContext = canvasElement.getContext("2d");
        var canvasCenter = {x:canvasBounds.width / 2, y:canvasBounds.height / 2};
        var windowCenter = {x:canvasBounds.x + canvasCenter.x, y:canvasBounds.y + canvasCenter.y};
        var typeToCSSClassMap = this.GetTypeToCSSClassMap(node);
      var renderNode = function(node, nodeCenter) {
        var cssClass = typeToCSSClassMap[node.Type];
        node.Title= node.Title.replace("workforward","work<i>forward</i>");
         inputHTML.push("<div class='", cssClass.NodeContainer, "'  style='left:", nodeCenter.x, "px;top:", nodeCenter.y, "px;'><a  href='#", node.Title, "' class='", cssClass.Node, "' ExternalUrl='",  node.ExternalUrl, "' HasUrl='1'><span><span>",  node.Title, "</span></span></a></div>");
      };
      var renderRelation = function(relation, relationCenter, nodeCenter, canvasOffset, windowOffset) {
        var cssClass = typeToCSSClassMap[relation.Type];
        relation.Title= relation.Title.replace("workforward","work<i>forward</i>"); 
         inputHTML.push("<div class='", cssClass.NodeContainer, "'  style='left:", windowOffset.x + relationCenter.x, "px;top:",  windowOffset.y + relationCenter.y, "px;'><a href='#",  relation.Title, "' class='", cssClass.Node, "' Url='", relation.Url, "'  ExternalUrl='", relation.ExternalUrl, "' HasUrl='1'","' WSMethod='",  relation.WSMethod,"'  WSParams='",relation.WSParams,"'><span><span>",  relation.Title, "</span></span></a></div>");
        canvasContext.moveTo(nodeCenter.x, nodeCenter.y);
        if(relation.Type==4) {
          canvasContext.lineTo(canvasOffset.x + relationCenter.x-38.5, canvasOffset.y + relationCenter.y+42.5);    
        } else {
          canvasContext.lineTo(canvasOffset.x + relationCenter.x, canvasOffset.y + relationCenter.y);
        }
        
      };

      canvasContext.beginPath();
      canvasContext.lineWidth = 2;
      canvasContext.strokeStyle = "rgb(0,40,105)";
      canvasContext.clearRect(0, 0, canvasBounds.width, canvasBounds.height);

      if(node.L2R) {
        this.RenderL2R(node, canvasBounds, canvasCenter, windowCenter, renderNode, renderRelation);
      } else {
        this.RenderRadial(node, canvasBounds, canvasCenter, windowCenter, renderNode, renderRelation);
      }

      canvasContext.stroke();

      Shared.SetInnerHTML(this.InputID, inputHTML.join(""));
    }
  },
  RenderL2R:function(node, canvasBounds, canvasCenter, windowCenter, renderNode, renderRelation) {
    var parentNodeWindowCenter = {x:100, y:windowCenter.y + 85};
    var parentNodeCanvasCenter = {x:parentNodeWindowCenter.x - canvasBounds.x, y:parentNodeWindowCenter.y - canvasBounds.y};
    renderNode(node, parentNodeWindowCenter);
    this.RenderL2RRelations(node, canvasBounds, parentNodeCanvasCenter, parentNodeWindowCenter, renderRelation);
  },
  RenderL2RRelations:function(node, canvasBounds, parentNodeCanvasCenter, parentNodeWindowCenter, renderRelation) {
    if(!node.Relations) { return; }
    var cos = Math.cos;
    var sin = Math.sin;
    var relationsLength = node.Relations.length;
    var relationsDistance = Math.PI * (relationsLength === 4 ? 1.25 : 1);
    var halfRelationsDistance = relationsDistance / 2;
    var relationsRadius = relationsLength === 4 ? 225 : 150;
    var relationsSpacing = relationsDistance / (relationsLength + 1);
    Array.forEach(node.Relations, function(relation, i) {
      var childRelationAngleHack = 0;
      if(relation.Relations && node.Relations[i + 1].Relations) { childRelationAngleHack = halfRelationsDistance/10; }
      if(relation.Relations && node.Relations[i - 1].Relations) { childRelationAngleHack = -halfRelationsDistance/10; }

      var childRelationRadiusHack = 0;
       if(!relation.Relations && (!i || i === (relationsLength-1)  || node.Relations[i - 1].Relations || node.Relations[i + 1].Relations)) {  childRelationRadiusHack = (({2:30,3:30})[relationsLength] || 65); }

      var angle = ((i + 1) * relationsSpacing) - halfRelationsDistance - childRelationAngleHack;
       var relationWindowCenter = {x:cos(angle) * (relationsRadius -  childRelationRadiusHack), y:sin(angle) * (relationsRadius -  childRelationRadiusHack)};
      renderRelation(relation, relationWindowCenter, parentNodeCanvasCenter, parentNodeCanvasCenter, parentNodeWindowCenter);
       this.RenderL2RRelations(relation, canvasBounds,  {x:relationWindowCenter.x + parentNodeCanvasCenter.x,  y:relationWindowCenter.y + parentNodeCanvasCenter.y},  {x:relationWindowCenter.x + parentNodeWindowCenter.x,  y:relationWindowCenter.y + parentNodeWindowCenter.y}, renderRelation);
    }, this);
  },
  RenderRadial:function(node, canvasBounds, canvasCenter, windowCenter, renderNode, renderRelation) {
    renderNode(node, windowCenter);

    var cos = Math.cos;
    var sin = Math.sin;
    var relationsRadius = Math.min(canvasBounds.width, canvasBounds.height) / 2 * 0.75;
    var relationSpacing = Math.PI * 2 / node.Relations.length;

    Array.forEach(node.Relations, function(relation, i) {
      var relationCenter = {x:cos(i * relationSpacing) * relationsRadius, y:-sin(i * relationSpacing) * relationsRadius};
      renderRelation(relation, relationCenter, canvasCenter, canvasCenter, windowCenter);
    });

    if(node.Back || node.More) {
      var backMoreAngle = Math.PI/5;
      var backMoreRadius = relationsRadius * 1.5;
       if(node.Back) { renderRelation(node.Back, {x:(cos(backMoreAngle) *  backMoreRadius), y:(-sin(backMoreAngle) * backMoreRadius)},  canvasCenter, canvasCenter, windowCenter); }
       if(node.More) { renderRelation(node.More, {x:cos(backMoreAngle) *  backMoreRadius, y:sin(backMoreAngle) * backMoreRadius}, canvasCenter,  canvasCenter, windowCenter); }
    }
  }
};


