Analyze dependencies of cargo projects
use charming::element::{ColorBy, ItemStyle, Label};
use charming::series::{Bar, Graph, GraphLayoutForce, Sankey, Series, Treemap};
use charming::{Chart, HtmlRenderer};

mod graph;
mod histogram;
mod sankey;
mod treemap;

#[derive(Clone, Copy, Debug)]
pub enum Style {
    Graph,
    Sankey,
    Histogram,
    Treemap,
}

pub fn for_style(style: Style, annotations: &crate::AnnotationGraph) {
    let series: Series = match style {
        Style::Graph => {
            Graph::new()
                // Use charming's force-directed layout, in combination with
                // `graph::layout()` using `forceatlas2`, as they seem to get the best results
                // when used together.
                .layout(charming::series::GraphLayout::Force)
                .force(GraphLayoutForce::new().layout_animation(false))
                .roam(true)
                .data(graph::data(annotations))
                .into()
        }
        Style::Sankey => Sankey::new()
            .nodes(sankey::nodes(annotations))
            .links(sankey::links(annotations))
            .into(),
        Style::Histogram => Bar::new()
            // TODO: charming does not support relative bar widths, but echarts does.
            // This is an exact value, NOT a percentage, and is wrong - each bar overlaps
            // itself. This is "fine" for a histogram, so leaving for now,
            // but should change eventually.
            .bar_width(100)
            .data(histogram::data(annotations))
            .into(),
        Style::Treemap => {
            let data = treemap::data(annotations, annotations.roots().collect::<Vec<_>>());
            Treemap::new()
                .data(data)
                .item_style(ItemStyle::new().border_width(5).gap_width(1))
                .visible_min(300_u64)
                .upper_label(Label::new().show(true))
                .color(treemap::color())
                // TODO: this is a hack that sets the levels to be a complete worst-case
                .levels(treemap::levels(annotations.edges().count()))
                .color_by(ColorBy::Series)
                .into()
        }
    };

    let mut chart = Chart::new().series(series);

    // Use custom axes for histogram
    if matches!(style, Style::Histogram) {
        let (x_axis, y_axis) = histogram::axes(annotations);
        chart = chart.x_axis(x_axis).y_axis(y_axis);
    }

    let mut renderer = HtmlRenderer::new("Cargo dependencies", 1000, 800);
    renderer.save(&chart, "target/dist/index.html").unwrap();
}