').detailView(
              $.extend(true, {}, cloudStack.vpc.tiers.detailView, {
                section: 'networks',
                $browser: $browser,
                context: context,
                onActionComplete: function() {
                  $tier.closest('.vpc-network-chart').trigger('reload');
                }
              })
            );
            $detailView.appendTo($panel);
          }
        });
      });
      $cidrLabel.html('CIDR: ');
      $cidr.html(tier.cidr);
      $title.find('span').html(tier.displayname ? tier.displayname : tier.name);
      $header.append($title, $detailLink);
      $info.append($cidrLabel, $cidr);
      $content.append($dashboard, $info);
      $tier.append($header, $content);
      return $tier;
    },
    connectorLine: function(args) {
      var $connector = $('
').addClass('connector-line');
      var $router = args.$router;
      var $tier = args.$tier;
      var isHighlighted = args.isHighlighted;
      var $connectorStart = $('
').addClass('connector-start');
      var $connectorMid = $('
').addClass('connector-mid');
      var $connectorEnd = $('
').addClass('connector-end');
      $connector.append($connectorStart, $connectorMid, $connectorEnd);
      if (isHighlighted) {
        $connector.addClass('highlighted');
      }
      var posStartOffsetLeft = 5;
      var posStartOffsetTop = 10;
      var posStart = {
        top: $router.position().top + ($router.outerHeight() / 2 + ($tier.index() * posStartOffsetTop)),
        left: $router.position().left + $router.outerWidth()
      };
      var posStartWidth = 60 - ($tier.index() > 2 ? (($tier.index() + 1) * posStartOffsetLeft) : 0);
      var posEndOffset = 15;
      var posEndWidthOffset = 3;
      var posEnd = {
        top: $tier.position().top + ($tier.outerHeight() / 2),
        left: posStart.left + posStartWidth + posEndOffset
      };
      var posEndWidth = Math.abs($tier.position().left -
                                 (posStart.left + posStartWidth)) + posEndWidthOffset;
      // Start line (next to router)
      $connectorStart.css({
        top: posStart.top,
        left: posStart.left
      });
      $connectorStart.width(posStartWidth);
      // End line (next to tier)
      $connectorEnd.css({
        top: posEnd.top,
        left: posEnd.left
      });
      $connectorEnd.width(posEndWidth);
      // Mid line (connect start->end)
      if (posStart.top > posEnd.top) { // Tier above router
        $connectorMid.css({
          top: posEnd.top,
          left: posEnd.left
        });
        $connectorMid.height(posStart.top - posEnd.top);
      } else { // Tier below router
        $connectorMid.css({
          top: posStart.top,
          left: posStart.left + posStartWidth + posEndOffset
        });
        $connectorMid.height(posEnd.top - posStart.top);
      }
      return $connector;
    },
    router: function(args) {
      var $router = elems.tier({
        context: args.context,
        tier: {
          name: 'Router',
        },
        dashboardItems: args.dashboardItems
      }).addClass('router');
      $router.find('.info, .detail-link').remove();
      $router.find('.header').prepend($('
').addClass('icon').html(' '));
      return $router;
    },
    tierPlaceholder: function(args) {
      var context = args.context;
      var $placeholder = $('
').addClass('tier-placeholder');
      $placeholder.append($('
').append('Create network'));
      $placeholder.click(function() {
        addTierDialog({
          context: context,
          $placeholder: $placeholder
        });
      });
      return $placeholder;
    },
    dashboard: function(args) {
      var $dashboard = $('').addClass('dashboard');
      var context = args.context;
      var tier = context.networks[0];
      $(args.dashboardItems).map(function(index, dashboardItem) {
        var $dashboardItem = $('
').addClass('dashboard-item');
        var $name = $('
').addClass('name').append($('
'));
        var $total = $('').addClass('total').append($('
'));
        var id = dashboardItem.id;
        $name.find('span').html(dashboardItem.name);
        if (dashboardItem.totalMultiLine) {
          $total.find('span').html(dashboardItem.totalMultiLine);
          $total.addClass('multiline');
        } else {
          $total.find('span').html(dashboardItem.total ? dashboardItem.total : 0);
        }
        $dashboardItem.append($total, $name);
        $dashboardItem.appendTo($dashboard);
        if (dashboardItem._disabled) {
          $dashboardItem.addClass('disabled');
        }
        $dashboardItem.click(function() {
          if ($dashboardItem.is('.disabled')) {
            return false;
          }
          
          var section = cloudStack.vpc.sections[id];
          var $section = $('');
          var $loading = $('
').addClass('loading-overlay');
          if ($.isFunction(section)) {
            section = cloudStack.vpc.sections[id]();
          }
          var before = section.before;
          var load = function() {
            $('#browser .container').cloudBrowser('addPanel', {
              title: tier.name + ' - ' + dashboardItem.name,
              maximizeIfSelected: true,
              complete: function($panel) {
                if (section.listView) {
                  $section.listView($.extend(true, {}, section, {
                    onActionComplete: function() {
                      $dashboardItem.closest('.vpc-network-chart').trigger('reload');
                    },
                    context: context
                  }));
                }
                $section.appendTo($panel);
              }
            });
          };
          if (before) {
            before.check({
              context: context,
              response: {
                success: function(result) {
                  // true means content exists
                  if (result) {
                    load();
                  } else {
                    cloudStack.dialog.confirm({
                      message: before.messages.confirm,
                      action: function() {
                        $loading.appendTo($dashboardItem.closest('.vpc-network-chart'));
                        before.action({
                          context: context,
                          response: {
                            success: function() {
                              $loading.remove();
                              $dashboardItem.closest('.vpc-network-chart').trigger('reload');
                              load();
                            }
                          }
                        });
                      }
                    })
                  }
                }
              }
            });
          } else {
            load();
          }
        });
      });
      return $dashboard;
    }
  };
  cloudStack.modules.vpc = function(module) {
    var vpc = cloudStack.vpc;
    var vpcSection = cloudStack.sections.network.sections.vpc;
    var listConfigureAction = vpcSection.listView.actions.configureVpc.action;
    var detailsConfigureAction = vpcSection.listView.detailView.actions.configureVpc.action;
    var vpcChart = function(args) {
      var context = args.context;
      var vpcItem = context.vpc[0];
      var chart = function(args) {
        args = args ? args : {};
        var $chart = $('
').addClass('vpc-network-chart');
        var $tiers = $('
').addClass('tiers');
        var $toolbar = $('
').addClass('toolbar');
        var $info = $('
').addClass('info-box');
        $toolbar.appendTo($chart);
        $tiers.appendTo($chart);
        // Get tiers
        var $loading = $('
').addClass('loading-overlay').prependTo($chart);
        vpc.tiers.dataProvider({
          context: context,
          response: {
            success: function(data) {
              var tiers = data.tiers;
              var $router;
              var $placeholder = elems.tierPlaceholder({
                context: context
              });
              // Router
              $router = elems.router({
                context: context,
                dashboardItems: data.routerDashboard
              }).appendTo($chart);
              $(tiers).map(function(index, tier) {
                var $tier = elems.tier({
                  context: context,
                  tier: tier,
                  dashboardItems: tier._dashboardItems
                });
                $tier.appendTo($tiers);
                // Connect tier to router via line
                //
                // -- Needs to execute after chart generation is complete,
                //    so that chart elements have positioning in place.
                $chart.bind('cloudStack.vpc.chartReady', function() {
                  elems.connectorLine({
                    $tier: $tier,
                    $router: $router,
                    isHighlighted: tier._highlighted
                  }).appendTo($chart);
                });
              });
              // Add placeholder tier
              $tiers.append($placeholder);
              $loading.remove();
              if (!tiers.length) {
                addTierDialog({
                  context: context,
                  $placeholder: $placeholder
                });
              }
              if (args.complete) {
                args.complete($chart);
              }
              if ($chart.find('.connector-line.highlighted').size()) {
                $info.appendTo($chart).append(
                  $('').addClass('color-key'),
                  $('').html('= Contains a public network')
                );
              }
            }
          }
        });
        $chart.bind('reload', function() {
          chart({
            complete: function($newChart) {
              $chart.replaceWith($newChart);
              $newChart.trigger('cloudStack.vpc.chartReady');
            }
          });
        });
        return $chart;
      };
      $('#browser .container').cloudBrowser('addPanel', {
        title: vpcItem.displaytext ? vpcItem.displaytext : vpcItem.name,
        maximizeIfSelected: true,
        complete: function($panel) {
          var $chart = chart({
            complete: function($chart) {
              $chart.trigger('cloudStack.vpc.chartReady');
            }
          });
          $chart.appendTo($panel);
        }
      });
    };
    listConfigureAction.custom = vpcChart;
    detailsConfigureAction.custom = vpcChart;
  };
}(jQuery, cloudStack));