<% if(n_total > 0) { %>
<details><summary>Dependency plot</summary>
<br>
<% tmp_file = tempfile(fileext = ".png")
  if(nrow(downstream_tb) > 0) {
    png(tmp_file, width = 1200*1.5, height = 500*1.5, res = 72*2)
    l = df$package == pkg$package
    repo = ifelse(grepl("bioconductor", df$repository), "Bioconductor", "CRAN")
    color = ifelse(l, "highlight", "others")
    suppressMessages(suppressWarnings({
      p1 = ggplot2::ggplot(df, ggplot2::aes(n_downstream, heaviness_on_downstream, pch = repo, color = color, label = ifelse(l, df$package, ""))) +
        ggplot2::geom_point() + 
        ggplot2::scale_color_manual(values = c("highlight" = "red", "others" = "grey")) +
        ggplot2::scale_shape_manual(values = c("Bioconductor" = 16, "CRAN" = 4)) +
        ggplot2::scale_x_continuous(trans='log10') +
        ggrepel::geom_text_repel(min.segment.length = 0, box.padding = 0.5, max.overlaps = Inf, show.legend = FALSE, size =3) +
        ggplot2::labs(x = "Number of downstream packages", y = "Heaviness") +
        ggplot2::ggtitle("Heaviness on downstream packages for all CRAN/Bioconductor packages")

      p2 = ggplot2::ggplot(mapping = ggplot2::aes(all_heaviness)) + geom_histogram() +
        ggplot2::labs(x = "Heaviness on downstream packages", y = "Frequency") +
        ggplot2::ggtitle(qq("Histogram of heaviness of '@{pkg$package}' on its downstream packages"))

      print(cowplot::plot_grid(p1, p2, rel_widths = c(1.2, 1)))
    }))
     dev.off() 
  } else {
    png(tmp_file, width = 600*1.5, height = 500*1.5, res = 72*2)
    l = df$package == pkg$package
    repo = ifelse(grepl("bioconductor", df$repository), "Bioconductor", "CRAN")
    color = ifelse(l, "highlight", "others")
    suppressWarnings({
      p1 = ggplot2::ggplot(df, ggplot2::aes(n_downstream, heaviness_on_downstream, pch = repo, color = color, label = ifelse(l, df$package, ""))) +
        ggplot2::geom_point() + 
        ggplot2::scale_color_manual(values = c("highlight" = "red", "others" = "grey")) +
        ggplot2::scale_shape_manual(values = c("Bioconductor" = 16, "CRAN" = 4)) +
        ggplot2::scale_x_continuous(trans='log10') +
        ggrepel::geom_text_repel(min.segment.length = 0, box.padding = 0.5, max.overlaps = Inf, show.legend = FALSE, size =3) +
        ggplot2::labs(x = "Number of downstream packages", y = "Heaviness") +
        ggplot2::ggtitle("Heaviness on downstream packages for all CRAN/Bioconductor packages")
      ggplot2:::print.ggplot(p1)
    })
    dev.off() 
  }
 %>
<%= img(tmp_file, style="height:500px")%>
<% file.remove(tmp_file) %>


</details>

<style>
details summary {
    cursor: pointer;
}
summary {
    display: list-item;
}
details > summary:first-of-type {
    display: list-item;
    counter-increment: list-item 0;
    list-style: inside disclosure-closed;
}
details[open] > summary:first-of-type {
    list-style-type: disclosure-open;
}
</style>

<% if(nrow(downstream_tb) > 0) { %>
<br>
<p>In total, <span class="package"><%=pkg$package%></span> has <%=n_total%> downstream dependency packages. Only <%=n_used%> downstream packages with heaviness on <span class="package"><%=pkg$package%></span> larger than 10
<% if( !( (min_depth == 0 && max_depth == 0) || (min_depth == global_min_depth && max_depth == global_max_depth) ) ) { %>
also with dependency path depth within <code>[<%=min_depth%>, <%=max_depth%>]</code>,
<% } %>
are listed in the following table.</p>
<p><b>Dependency path:</b> the shortest path from <span class="package"><%=pkg$package%></span> to a downstream package in the global dependency graph. The form of <span style="display:inline-block;vertical-align:top;color:#c7254e;">A</span><span style="display:inline-block;vertical-align:top;padding:0px 4px;color:#c7254e;">→<br><span style="font-size:0.8em;color:#c7254e;">k</span></span><span style="display:inline-block;vertical-align:top;color:#c7254e;">B</span> means package A contributes a direct heaviness of <i>k</i> on package B.</p>
<p><b>Heaviness of <span class="package"><%=pkg$package%></span> on downstream package:</b> Denote $n_{1k}$ as the number of strong dependencies of the downstream package. Since <span class="package"><%=pkg$package%></span> can affect the downstream pacakge in an indirect manner, we recalculate the global dependency relations for all packages after moving <span class="package"><%=pkg$package%></span> to all its child packages' <code>Suggests</code>. Then we denote $n_{2k}$
as the number of strong dependencies of the downstream pacakge in the reduced dependency graph. The heaviness from <span class="package"><%=pkg$package%></span> on that downstream pacakge is calculated as $n_{1k} - n_{2k}$.</p>
<p>The full table can be obtained by <code>downstream_dependency('<%=pkg$package%>')</code>.</p>

<% 
  el = downstream_dependency(pkg$package)
  g = igraph::graph.edgelist(as.matrix(unique(el[, 1:2])))
    
for(i in seq_len(nrow(downstream_tb))) {

      sp = igraph::all_shortest_paths(g, pkg$package, downstream_tb[i, 1])$res
      downstream_tb[i, "path"] = paste(sapply(sp, function(x) {
        p = names(x)
        txt = paste0("<div><span style='display:inline-block;vertical-align:top;'><a href='package?package=", p[i], "'>", p[1], "</a></span>")
        for(i in seq_len(length(p) - 1)) {
          txt = paste0(txt, "<span style='display:inline-block;vertical-align:top;padding:0px 4px;'>", "&#8594;<br><span style='font-size:0.8em;'>", df[["hv_downstream_values"]][[ p[i] ]][ p[i+1] ], "</span></span><span style='display:inline-block;vertical-align:top;'><a href='package?package=", p[i+1], "'>", p[i+1], "</a></span>")
        }
        paste0(txt, "</div>")
      }), collapse = "")
      downstream_tb[i, "path_len"] = max(sapply(sp, length))
    }
downstream_tb$package = qq("<a href='?package=@{downstream_tb$package}'>@{downstream_tb$package}</a>", collapse = FALSE)
    
%>

<% if(global_min_depth < global_max_depth) { %>
<div class="form-box" style="padding:20px 10px;">
<div style="display: inline-grid;">
<div style="grid-column-start:1;"><span style="padding-right:10px; position:relative; top:25px;">Adjust range of the dependency depth:</span></div>
<div style="width:<%=max((length(depth_tb) - 1)*75, 300)%>;grid-column-start:2;padding-right:10px;">
<input type="text" id="downstream-dep-depth-slider" name="downstream_dep_depth_range" value="" />
</div>

<div style="grid-column-start:3;">
<% n_col = ceiling(length(depth_tb) / 3) 
  depth_html_tb = matrix("", nrow = 3, ncol = n_col)
for(i in seq_along(depth_tb)) { 
    i_col = ceiling(i/3 - 0.1)
    i_row = (i-1) %% 3 + 1
  depth_html_tb[i_row, i_col] = qq('<p>Depth = @{names(depth_tb)[i]}: <span style="background-color:#003eff;">@{strrep("&nbsp;", max(1, round(depth_tb[i]/max(depth_tb)*20)))}</span> @{depth_tb[i]} path@{ifelse(depth_tb[i] == 1, "", "s")}')
} %>
<%=kable(depth_html_tb, format = "html", row.names = FALSE, escape = FALSE, table.attr = "id='depth-table'")%>
</div>

<style type="text/css">
#depth-table {
  margin-left: 40px;
} 
#depth-table td {
  padding: 0px 10px;
}
</style>
</div>
</div>
<br>
<script type="text/javascript">
  var depth_tb = {
    <%=paste(qq("'@{names(depth_tb)}':@{depth_tb}", collapse = FALSE), collapse = ", ")%>
  };
 $("#downstream-dep-depth-slider").ionRangeSlider({
        skin: "round",
        type: "double",
        min: <%=global_min_depth%>,
        max: <%=global_max_depth%>,
        from: <%=min_depth%>,
        to: <%=max_depth%>,
        onFinish: function(data) {
          update_ajax_table("downstream_dependency", "<%=pkg$package%>", 1, <%=records_per_page%>, {min_depth:data[["from"]],max_depth:data[["to"]]});
        }
    });

</script>
<% } %>

<%= as.character(knitr::kable(downstream_tb, format = "html", row.names = FALSE, escape = FALSE, col.names = c("Downstream package", "Dependency path", "Dependency depth", qq("Heaviness of <span class='package'>@{pkg$package}</span> on downstream package")), table.attr = "class='table table-striped'")) %>


<div>
<form method="get" class="form-inline">
<select id="downstream_dep_records_per_page" class="form-control" aria-label="Records per page" name="records_per_page">
  <option value="20" <%= ifelse(records_per_page == 20, 'selected', '') %>>20</option>
  <option value="50" <%= ifelse(records_per_page == 50, 'selected', '') %>>50</option>
  <option value="100" <%= ifelse(records_per_page == 100, 'selected', '') %>>100</option>
</select> records per page, showing <%=(page-1)*records_per_page+1%> to <%=min(page*records_per_page, n_used)%> of <%=n_used%> downstream pacakges.
</form>

 <script type="text/javascript">

  $(function() {
    $('#downstream_dep_records_per_page').change(function() {
        update_ajax_table("downstream_dependency", "<%=pkg$package%>", 1, $('#downstream_dep_records_per_page').val(), {min_depth:<%=min_depth%>,max_depth:<%=max_depth%>});
    });
});
</script>

  <% nr = n_used
  if(nr > records_per_page) { %>
    <%= page_select2(page, ceiling(nr/records_per_page), "downstream_dependency", pkg$package, records_per_page, qq("&min_depth=@{min_depth}&max_depth=@{max_depth}")) %>
  <% } %>

<% n_nodes = length(unique(c(nt[, 1], nt[, 2]))) %>

<style>
#cy-downstream-dep {
  border: 1px solid #c5c5c5;
  width: 100%;
  height: <%=ifelse(n_nodes > 100, 1000, 500)%>px;
}
</style>


<hr>
<p>Dependency paths in the table are merged into the following graph with <%=n_nodes%> nodes and <%=nrow(nt)%> edges. 
<% if(!(min_depth == global_min_depth && max_depth == global_max_depth)) { %>
Dependency depth ranges between <%=min_depth%> and <%=max_depth%>. 
<% } %>
<% if(n_nodes <= 30) { %>

    <span><a class='fake-link' onclick="$('#cy-downstream-dep').html('');load_downstream_dep_nt('LR');$('#graph-downstream-horizontal-layout').hide();$('#graph-downstream-vertical-layout').show();$('#cy-downstream-dep').resizable('destroy');$('#cy-downstream-dep').resizable();" style="font-size: 0.8em;">Reset graph</a></span> | 
    <span><a class='fake-link' id="graph-downstream-vertical-layout" onclick="$('#cy-downstream-dep').html('');load_downstream_dep_nt('TB');$('#graph-downstream-horizontal-layout').show();$(this).hide();$('#cy-downstream-dep').resizable('destroy');$('#cy-downstream-dep').resizable();" style="font-size: 0.8em;">Vertical layout</a></span>
    <span><a class='fake-link' id="graph-downstream-horizontal-layout" onclick="$('#cy-downstream-dep').html('');load_downstream_dep_nt('LR');$('#graph-downstream-vertical-layout').show();$(this).hide();$('#cy-downstream-dep').resizable('destroy');$('#cy-downstream-dep').resizable();" style="font-size: 0.8em; display: none;">Horizontal layout</a></span>

<% } else { %>

 <span><a class='fake-link' onclick="$('#cy-downstream-dep').html('');load_downstream_dep_nt();$('#cy-downstream-dep').resizable('destroy');$('#cy-downstream-dep').resizable();" style="font-size: 0.8em;">Reset graph</a></span>

<% } %>
</p>

<% 
  knee_finder2 = function (x) {

    if(length(x) < 2) {
      return(c(NA, NA))
    }

    y = sort(x)
    x = seq_along(y)
    n = length(x)
    a = (y[n] - y[1])/(x[n] - x[1])
    b = y[1] - a * x[1]
    d = a * x + b - y
    x1 = x[which.min(d)]
    x2 = max(x[d >= max(d) - diff(range(d))*0.01])
    if (all(d >= 0))
        x1 = NA
    if (all(d <= 0))
        x2 = NA
    
    return(c(x1, x2))
}

betweenness = sort(nt[, "betweenness"])
ind = knee_finder2(betweenness)
if(is.na(ind[2])) {
  betweenness_cutoff = 9999999999
} else {
  betweenness_cutoff = betweenness[ind[2]]

  if(betweenness_cutoff/(min(betweenness)+2) < 3) {
    betweenness_cutoff = 9999999999
  }
}

# if n_nodes is too high, > 500, child nodes are grouped
if(n_nodes > 500) {
  l = !nt[, 2] %in% nt[, 1]
  leaves = length(unique(nt[l, 2]))
  nt2 = nt[!l, , drop = FALSE]
  n_leaves = tapply(nt[l, 2], nt[l, 1], length)
  n_leaves_mean_heaviness = round(tapply(nt[l, 3], nt[l, 1], mean))
  n_leaves_mean_betweenness = round(tapply(nt[l, 4], nt[l, 1], mean))

  l = n_leaves > 1
  nt2 = rbind(nt2, data.frame(from = names(n_leaves)[l], 
                         to = paste0(names(n_leaves), ": ", n_leaves, " leaves")[l], 
                         heaviness = n_leaves_mean_heaviness[l],
                         betweenness = n_leaves_mean_betweenness[l]))
  if(any(!l)) {
    single_leaf_parents = names(n_leaves[!l])
    nt2 = rbind(nt2, nt[ nt[, 1] %in% single_leaf_parents, , drop = FALSE])
  }
  nt = nt2
}

%>


<p>Legends (if there are such):</p>
<ul>
  <li><b>Orange dot:</b> The package <b><%=pkg$package%></b>.</li>
  <li><b>Green dots:</b> To reduce the size of the graph for visualization, leaf nodes sharing the same parent are grouped and colored in green. </li>
  <li><b>Red arrows:</b> Edges with high betweenness. The cutoff of betweenness is selected as the 'elbow' of the curve of sorted betweenness of all edges in the graph.</li>
</ul>

<ul>
<li>The number on an edge only corresponds to the direct heaviness from a parent on its child. It does not necessarily mean all the heaviness are inherited to the very downstream nodes. E.g. for a dependency path: <span style="display:inline-block;vertical-align:top;color:#c7254e;">A</span><span style="display:inline-block;vertical-align:top;padding:0px 4px;color:#c7254e;">→<br><span style="font-size:0.8em;color:#c7254e;">k1</span></span><span style="display:inline-block;vertical-align:top;color:#c7254e;">B</span><span style="display:inline-block;vertical-align:top;padding:0px 4px;color:#c7254e;">→<br><span style="font-size:0.8em;color:#c7254e;">k2</span></span><span style="display:inline-block;vertical-align:top;color:#c7254e;">C</span>, the <code>k1</code> heaviness from <i>A</i> to <i>B</i> is not necessarily all passed to package <i>C</i>, because it might be diluted by <i>C</i>'s other parents.</li>
  <li>The graph is only a union of the shortest paths from upstream packages to <b><%=pkg$package%></b>, thus it does not include all the dependency relations from upstream of <b><%=pkg$package%></b> in the global dependency graph.</li>
</ul>



<div id='cy-downstream-dep' style="position:relative;">
    <span style="top:100px;left:50%;position:absolute;"><a class='fake-link' onclick="load_downstream_dep_nt('LR');$(this).remove();" style="font-size: 1.5em;">Load graph</a></span>
</div>

<script type='text/javascript'>

load_downstream_dep_nt = function(rankDir = "TB") {

  <%=network_in_json(nt)%>

  var layout;
  if(nt.nodes.length > 30) {
    layout = {
      name: 'euler',
      springLength: edge => 100,
      randomize: true,
      animate: false
    };
  } else {
    layout = {
      name: 'dagre',
      nodeSep: 5,
      rankDir: rankDir
    };
  }

  var cy = cytoscape({
    container: document.getElementById('cy-downstream-dep'),
    boxSelectionEnabled: false,
    autounselectify: true,
    elements: nt,
    layout: layout,
    style: [
      {
        selector: 'node',
        style: {
          "width": 30,
          "height": 30,
          'content': 'data(id)',
          'text-valign': 'center',
          'text-halign': 'center',
          'background-color': '#74ADD1'
        }
      },

      {
        selector: 'edge',
        style: {
          'width': function(ele){ return ele.data("weight")/8; },
          "label": "data(weight)",
          'target-arrow-shape': 'triangle',
          'line-color': '#9dbaea',
          'target-arrow-color': '#9dbaea',
          'curve-style': 'bezier'
        }
      },

      {
        selector: "#<%=pkg$package%>",
        style: {
          'background-color': 'orange',
        }
      },

      {
        selector: "[group = 'leafgroup']",
        style: {
          'background-color': '#4CC26C',
          'content': 'data(label)'
        }
      },

      {
        selector: "[betweenness > <%=betweenness_cutoff%>]",
        style: {
          'width': 4,
          "label": "data(weight)",
          'target-arrow-shape': 'triangle',
          'line-color': 'red',
          'target-arrow-color': 'red',
          'curve-style': 'bezier'
        }
      }
    ]
  });
  
  cy.$('node').one('click', function(e){
    var ele = e.target;
    if(/\d+\s+leaves$/.test(ele.id())) {

    } else {
      window.open('package?package=' + ele.id(), '_self')
    }
  });

}

$('#cy-downstream-dep').resizable();
</script>


<% } else { %>

<p>In total there are <%=n_total%> downstream dependencies, but no package on which <%=pkg$package%> has heaviness larger than 10.</p>

<% } %>

<% } else { %>

<p>No downstream dependency found.</p>

<% } %>
