text: /* Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  var NORMAL_STROKE = 2;
  var SEQUENCEFLOW_STROKE = 2;
  var ASSOCIATION_STROKE = 2;
  var TASK_STROKE = 2;
  var TASK_HIGHLIGHT_STROKE = 4;
  var CALL_ACTIVITY_STROKE = 4;
  var ENDEVENT_STROKE = 4;
  
  var COMPLETED_COLOR = "#2632aa";
  var TEXT_COLOR = "#373e48";
  var CURRENT_COLOR = "#017501";
  var HOVER_COLOR = "#666666";
  var ACTIVITY_STROKE_COLOR = "#000000";
  var ACTIVITY_FILL_COLOR = "#ffffff";
  var MAIN_STROKE_COLOR = "#585858";
  
  var TEXT_PADDING = 3;
  var ARROW_WIDTH = 4;
  var MARKER_WIDTH = 12;
  
  var TASK_FONT = {font: "11px Arial", opacity: 1, fill: Raphael.rgb(0, 0, 0)};
  
  // icons
  var ICON_SIZE = 16;
  var ICON_PADDING = 4;
  
  var INITIAL_CANVAS_WIDTH;
  var INITIAL_CANVAS_HEIGHT;
  
  var paper;
  var viewBox;
  var viewBoxWidth;
  var viewBoxHeight;
  
  var canvasWidth;
  var canvasHeight;
  
  var modelDiv = jQuery('#bpmnModel');
  var modelId = modelDiv.attr('data-model-id');
  var historyModelId = modelDiv.attr('data-history-id');
  var processDefinitionId = modelDiv.attr('data-process-definition-id');
  var modelType = modelDiv.attr('data-model-type');
  var isDebuggerEnabled = angular.element(document.querySelector('#bpmnModel')).scope().model.isDebuggerEnabled;
  
  // Support for custom background colors for activities
  var customActivityColors = modelDiv.attr('data-activity-color-mapping');
  if (customActivityColors !== null && customActivityColors !== undefined && customActivityColors.length > 0) {
      // Stored on the attribute as a string
      customActivityColors = JSON.parse(customActivityColors);
  }
  
  var customActivityToolTips = modelDiv.attr('data-activity-tooltips');
  if (customActivityToolTips !== null && customActivityToolTips !== undefined && customActivityToolTips.length > 0) {
      // Stored on the attribute as a string
      customActivityToolTips = JSON.parse(customActivityToolTips);
  }
  
  // Support for custom opacity for activity backgrounds
  var customActivityBackgroundOpacity = modelDiv.attr('data-activity-opacity');
  
  var elementsAdded = new Array();
  var elementsRemoved = new Array();
  var selectedElement = undefined;
  
  var collapsedItemNavigation = new Array();
  var bpmnData;
  
  function _showTip(htmlNode, element)
  {
  
      // Custom tooltip
      var documentation = undefined;
      if (customActivityToolTips) {
          if (customActivityToolTips[element.name]) {
              documentation = customActivityToolTips[element.name];
          } else if (customActivityToolTips[element.id]) {
              documentation = customActivityToolTips[element.id];
          } else {
              documentation = ''; // Show nothing if custom tool tips are enabled
          }
      }
  
      // Default tooltip, no custom tool tip set
      if (documentation === undefined) {
          var documentation = "";
          if (element.name && element.name.length > 0) {
              documentation += "<b>Name</b>: <i>" + element.name + "</i><br/><br/>";
          }
  
          if (element.properties) {
              for (var i = 0; i < element.properties.length; i++) {
                  var propName = element.properties[i].name;
                  if (element.properties[i].type && element.properties[i].type === 'list') {
                      documentation += '<b>' + propName + '</b>:<br/>';
                      for (var j = 0; j < element.properties[i].value.length; j++) {
                          documentation += '<i>' + element.properties[i].value[j] + '</i><br/>';
                      }
                  }
                  else {
                      documentation += '<b>' + propName + '</b>: <i>' + element.properties[i].value + '</i><br/>';
                  }
              }
          }
      }
  
      var text = element.type + " ";
      if (element.name && element.name.length > 0)
      {
          text += element.name;
      }
      else
      {
          text += element.id;
      }
  
      htmlNode.qtip({
          content: {
              text: documentation,
              title: {
                  text: text
              }
          },
          position: {
              my: 'top left',
              at: 'bottom center',
              viewport: jQuery('#bpmnModel')
          },
          hide: {
              fixed: true, delay: 500,
              event: 'click mouseleave'
          },
          style: {
              classes: 'ui-tooltip-kisbpm-bpmn'
          }
      });
  }
  
  function _expandCollapsedElement(element) {
      if (bpmnData.collapsed) {
          for (var i = 0; i < bpmnData.collapsed.length; i++) {
              var collapsedItem = bpmnData.collapsed[i];
              if (element.id == collapsedItem.id) {
                  paper.clear();
                  
                  var modelElements = collapsedItem.elements;
                  for (var i = 0; i < modelElements.length; i++) {
                      var subElement = modelElements[i];
                      var drawFunction = eval("_draw" + subElement.type);
                      drawFunction(subElement);
                  }
                  
                  if (collapsedItem.flows) {
                      for (var i = 0; i < collapsedItem.flows.length; i++) {
                          var subFlow = collapsedItem.flows[i];
                          _drawFlow(subFlow);
                      }
                  }
                  
                  var collapsedName;
                  if (element.name) {
                      collapsedName = element.name;
                  } else {
                      collapsedName = 'sub process ' + element.id;
                  }
                  
                  collapsedItemNavigation.push({
                      "id": element.id,
                      "name": collapsedName
                  });
                  
                  _buildNavigationTree();
                  
                  break;
              }
          }
      }
  }
  
  function _navigateTo(elementId) {
      var modelElements = undefined;
      var modelFlows = undefined;
      newCollapsedItemNavigation = new Array();
      
      if (elementId == 'FLOWABLE_ROOT_PROCESS') {
          modelElements = bpmnData.elements;
          modelFlows = bpmnData.flows;
          
      } else {
      
          for (var i = 0; i < bpmnData.collapsed.length; i++) {
              var collapsedItem = bpmnData.collapsed[i];
              
              var collapsedName = undefined;
              for (var j = 0; j < collapsedItemNavigation.length; j++) {
                  if (elementId == collapsedItemNavigation[j].id) {
                      collapsedName = collapsedItemNavigation[j].name;
                      break;
                  }
              }
          
              if (!collapsedName) {
                  continue;
              }
              
              newCollapsedItemNavigation.push({
                  "id": collapsedItem.id,
                  "name": collapsedName
              });
              
              if (elementId == collapsedItem.id) {
                  modelElements = collapsedItem.elements;
                  modelFlows = collapsedItem.flows;
                  break;
              }
          }
      }
      
      if (modelElements) {
          paper.clear();
                      
          for (var i = 0; i < modelElements.length; i++) {
              var subElement = modelElements[i];
              var drawFunction = eval("_draw" + subElement.type);
              drawFunction(subElement);
          }
          
          if (modelFlows) {
              for (var i = 0; i < modelFlows.length; i++) {
                  var subFlow = modelFlows[i];
                  _drawFlow(subFlow);
              }
          }
          
          collapsedItemNavigation = newCollapsedItemNavigation;
          
          _buildNavigationTree();
      }
  }
  
  function _buildNavigationTree() {
      var navigationUrl = '| <a href="javascript:_navigateTo(\'FLOWABLE_ROOT_PROCESS\')">Root</a>';
                  
      for (var i = 0; i < collapsedItemNavigation.length; i++) {
          navigationUrl += ' > <a href="javascript:_navigateTo(\'' + collapsedItemNavigation[i].id + '\')">' + 
              collapsedItemNavigation[i].name + '</a>';
      }
      
      $('#navigationTree').html(navigationUrl);
  }
  
  function _addHoverLogic(element, type, defaultColor)
  {
      var strokeColor = _bpmnGetColor(element, defaultColor);
      var topBodyRect = null;
      if (type === "rect")
      {
          topBodyRect = paper.rect(element.x, element.y, element.width, element.height);
      }
      else if (type === "circle")
      {
          var x = element.x + (element.width / 2);
          var y = element.y + (element.height / 2);
          topBodyRect = paper.circle(x, y, 15);
      }
      else if (type === "rhombus")
      {
          topBodyRect = paper.path("M" + element.x + " " + (element.y + (element.height / 2)) +
              "L" + (element.x + (element.width / 2)) + " " + (element.y + element.height) +
              "L" + (element.x + element.width) + " " + (element.y + (element.height / 2)) +
              "L" + (element.x + (element.width / 2)) + " " + element.y + "z"
          );
      }
  
      var opacity = 0;
      var fillColor = "#ffffff";
      if (jQuery.inArray(element.id, elementsAdded) >= 0)
      {
          opacity = 0.2;
          fillColor = "green";
      }
  
      if (jQuery.inArray(element.id, elementsRemoved) >= 0)
      {
          opacity = 0.2;
          fillColor = "red";
      }
  
      topBodyRect.attr({
          "opacity": opacity,
          "stroke" : "none",
          "fill" : fillColor
      });
      _showTip(jQuery(topBodyRect.node), element);
  
      topBodyRect.mouseover(function () {
          paper.getById(element.id).attr({"stroke": HOVER_COLOR});
      });
  
      topBodyRect.mouseout(function () {
          paper.getById(element.id).attr({"stroke": _bpmnGetColor(element, defaultColor)});
      });
  
      if (isDebuggerEnabled) {
          if (element.current || element.brokenExecutions) {
              topBodyRect.click(function () {
                  if (selectedElement != element.id) {
                      paper.getById(element.id).attr({"stroke": "green"});
                      selectedElement = element.id;
                      paper.getById(element.id).attr({"stroke": "red"});
                      _executionClicked(element.id);
                  } else {
                      selectedElement = undefined;
                      paper.getById(element.id).attr({"stroke": "green"});
                      var scope = angular.element(document.querySelector('#bpmnModel')).scope();
                      modelDiv.attr("selected-execution", scope.model.processInstance.id);
                      scope.model.selectedExecution = scope.model.processInstance.id;
                      angular.element(document.querySelector('#variablesUi')).scope().loadVariables();
                  }
              });
          }
      }
  }
  
  function _executionClicked(activityId) {
      var executions = angular.element(document.querySelector('#bpmnModel')).scope().model.executions;
      for (var i in executions) {
          if (executions[i]["activityId"] == activityId) {
              var activityToUnselect = modelDiv.attr("selected-activity");
              if (activityToUnselect) {
                  var rectangleToUnselect = paper.getById(activityToUnselect);
                  if (rectangleToUnselect) {
                      rectangleToUnselect.attr({"stroke": "green"});
                  }
              }
              modelDiv.attr("selected-execution", executions[i].id);
              modelDiv.attr("selected-activity", activityId);
              if (activityId) {
                  paper.getById(activityId).attr({"stroke": "red"});
              }
  
              var scope = angular.element(document.querySelector('#bpmnModel')).scope();
              if (scope.gridExecutions.data) {
                  for (var j = 0; j < scope.gridExecutions.data.length; j++) {
                      if (executions[i].id == scope.gridExecutions.data[j].id) {
                          scope.gridExecutionsApi.selection.selectRow(scope.gridExecutions.data[j]);
                          j = scope.gridExecutions.data.length;
                      }
                  }
              }
              scope.loadVariables();
              return;
          }
      }
  }
  
  function _breakpointRestCall(actionType, activityId) {
      $.ajax({
          type: actionType,
          url: '../app/rest/debugger/breakpoints',
          contentType: 'application/json; charset=utf-8',
          data: JSON.stringify({
              activityId: activityId
          }),
          success: function () {
              paper.clear();
              angular.element(document.querySelector('#bpmnModel')).scope().getEventLog();
              _showProcessDiagram();
          }
      })
  }
  
  function _drawBreakpoint(element, breakpoints) {
  
      var circle = paper.circle(element.x + 10, element.y - 10, 7);
  
      var breakpointFillColor = "white";
      var breakpointStrokeColor = "gray";
      var breakpointTipText = "Inactive element";
      if (element.current) {
          breakpointFillColor = "red";
          breakpointTipText = "Active execution"
      }
  
      if (element.breakpoint) {
          breakpointTipText = breakpointTipText + "<br/> Click to remove breakpoint";
          breakpointStrokeColor = "red";
          circle.click(function () {
              _breakpointRestCall("DELETE", element.id);
          });
  
      } else {
          breakpointTipText = breakpointTipText + "<br/> Click to add breakpoint";
          circle.click(function () {
              _breakpointRestCall("POST", element.id);
          });
      }
  
      circle.attr("stroke", breakpointStrokeColor);
      circle.attr("stroke-width", "3");
      circle.attr("fill", breakpointFillColor);
  
  
      var circleHtmlNode = jQuery(circle.node);
      circleHtmlNode.qtip({
          content: {
              text: breakpointTipText,
              button: false
          },
          position: {
              my: 'top left',
              at: 'bottom center',
              viewport: jQuery('#bpmnModel')
          },
          hide: {
              fixed: true, delay: 500,
              event: 'click mouseleave'
          },
          style: {
              classes: 'ui-tooltip-kisbpm-bpmn'
          }
      });
  
  }
  
  function _zoom(zoomIn) {
      var tmpCanvasWidth, tmpCanvasHeight;
      if (zoomIn) {
          tmpCanvasWidth = canvasWidth * (1.0 / 0.90);
          tmpCanvasHeight = canvasHeight * (1.0 / 0.90);
      }
      else {
          tmpCanvasWidth = canvasWidth * (1.0 / 1.10);
          tmpCanvasHeight = canvasHeight * (1.0 / 1.10);
      }
  
      if (tmpCanvasWidth != canvasWidth || tmpCanvasHeight != canvasHeight) {
          canvasWidth = tmpCanvasWidth;
          canvasHeight = tmpCanvasHeight;
          paper.setSize(canvasWidth, canvasHeight);
      }
  }
  
  var modelUrl;
  
  if (modelType == 'runtime') {
      if (historyModelId) {
          modelUrl = FLOWABLE.CONFIG.contextRoot + '/app/rest/process-instances/history/' + historyModelId + '/model-json';
      } else if (isDebuggerEnabled) {
          modelUrl = FLOWABLE.CONFIG.contextRoot + '/app/rest/process-instances/debugger/' + modelId + '/model-json';
      } else {
          modelUrl = FLOWABLE.CONFIG.contextRoot + '/app/rest/process-instances/' + modelId + '/model-json';
      }
  } else if (modelType == 'design') {
      if (historyModelId) {
          modelUrl = FLOWABLE.CONFIG.contextRoot + '/app/rest/models/' + modelId + '/history/' + historyModelId + '/model-json';
      } else {
          modelUrl = FLOWABLE.CONFIG.contextRoot + '/app/rest/models/' + modelId + '/model-json';
      }
  } else if (modelType == 'process-definition') {
      modelUrl = FLOWABLE.CONFIG.contextRoot + '/app/rest/process-definitions/' + processDefinitionId + '/model-json';
  }
  
  function _drawContinueExecution(x, y , executionId, activityId) {
      var arrow = paper.path("M "+ x +" "+ y + " L "+ (x+8) +" "+ (y+4) +" "+ x +" "+ (y+8) +" z");
  
      arrow.click(function () {
              $.ajax({
                  type: 'PUT',
                  url: '../app/rest/debugger/breakpoints/' + executionId + '/continue',
                  contentType: 'application/json; charset=utf-8',
                  success: function () {
                      paper.clear();
                      var processInstanceId = angular.element(document.querySelector('#bpmnModel')).scope().model.processInstance.id;
                      modelDiv.attr("selected-execution", processInstanceId);
                      angular.element(document.querySelector('#bpmnModel')).scope().model.selectedExecution = processInstanceId;
                      angular.element(document.querySelector('#bpmnModel')).scope().getExecutions();
                      angular.element(document.querySelector('#bpmnModel')).scope().model.variables = undefined;
                      angular.element(document.querySelector('#bpmnModel')).scope().loadVariables();
                      angular.element(document.querySelector('#bpmnModel')).scope().getEventLog();
                      _showProcessDiagram();
                  },
                  error: function () {
                      alert("error");
                  }
              })
          }
      );
      arrow.attr("stroke", "green");
      arrow.attr("stroke-width", "3");
      arrow.attr("fill", "green");
  
      var arrowHtmlNode = jQuery(arrow.node);
      arrowHtmlNode.qtip({
          content: {
              text: "Fire execution "+ executionId+", activity " + activityId,
              button: false
          },
          position: {
              my: 'top left',
              at: 'bottom center',
              viewport: jQuery('#bpmnModel')
          },
          hide: {
              fixed: true, delay: 500,
              event: 'click mouseleave'
          },
          style: {
              classes: 'ui-tooltip-kisbpm-bpmn'
          }
      });
  
  }
  
  function _showProcessDiagram() {
      var request = jQuery.ajax({
          type: 'get',
          url: modelUrl + '?nocaching=' + new Date().getTime()
      });
  
      request.success(function (data, textStatus, jqXHR) {
  
          if ((!data.elements || data.elements.length == 0) && (!data.pools || data.pools.length == 0)) return;
  
          INITIAL_CANVAS_WIDTH = data.diagramWidth;
  
          if (modelType == 'design') {
              INITIAL_CANVAS_WIDTH += 20;
          } else {
              INITIAL_CANVAS_WIDTH += 30;
          }
  
          INITIAL_CANVAS_HEIGHT = data.diagramHeight + 50;
          canvasWidth = INITIAL_CANVAS_WIDTH;
          canvasHeight = INITIAL_CANVAS_HEIGHT;
          viewBoxWidth = INITIAL_CANVAS_WIDTH;
          viewBoxHeight = INITIAL_CANVAS_HEIGHT;
  
          if (modelType == 'design') {
              var headerBarHeight = 170;
              var offsetY = 0;
              if (jQuery(window).height() > (canvasHeight + headerBarHeight)) {
                  offsetY = (jQuery(window).height() - headerBarHeight - canvasHeight) / 2;
              }
  
              if (offsetY > 50) {
                  offsetY = 50;
              }
  
              jQuery('#bpmnModel').css('marginTop', offsetY);
          }
  
          jQuery('#bpmnModel').width(INITIAL_CANVAS_WIDTH);
          jQuery('#bpmnModel').height(INITIAL_CANVAS_HEIGHT);
          paper = Raphael(document.getElementById('bpmnModel'), canvasWidth, canvasHeight);
          paper.setViewBox(0, 0, viewBoxWidth, viewBoxHeight, false);
          paper.renderfix();
  
          if (data.pools) {
              for (var i = 0; i < data.pools.length; i++) {
                  var pool = data.pools[i];
                  _drawPool(pool);
              }
          }
  
          var modelElements = data.elements;
  
          for (var i = 0; i < modelElements.length; i++) {
              var element = modelElements[i];
  //            try {
              var drawFunction = eval("_draw" + element.type);
              drawFunction(element);
              if (isDebuggerEnabled) {
                  _drawBreakpoint(element);
  
                  if (element.brokenExecutions) {
                      for (var j = 0; j < element.brokenExecutions.length; j++) {
                          _drawContinueExecution(element.x + 25 + j * 10, element.y - 15, element.brokenExecutions[j], element.id);
                      }
                  }
              }
  //            } catch(err) {console.log(err);}
          }
  
          if (data.flows) {
              for (var i = 0; i < data.flows.length; i++) {
                  var flow = data.flows[i];
                  if (flow.type === 'sequenceFlow') {
                      _drawFlow(flow);
                  } else if (flow.type === 'association') {
                      _drawAssociation(flow);
                  }
              }
          }
          
          bpmnData = data;
      });
  
      request.error(function (jqXHR, textStatus, errorThrown) {
          alert("error");
      });
  }
  
  _showProcessDiagram();
  