var margin = {top: 20, right: 0, bottom: 50, left: 85},
    svg_dx = 500, 
    svg_dy = 400,
    plot_dx = svg_dx - margin.right - margin.left,
    plot_dy = svg_dy - margin.top - margin.bottom;

var x = d3.scaleLinear().range([margin.left, plot_dx]),
    y = d3.scaleLinear().range([plot_dy, margin.top]);

var formatIncome = d3.format("$,"),
    formatHsGrad = d3.format(".1%"),
    formatHsGradAxis = d3.format(".0%");

var svg = d3.select("#block")
            .append("svg")
            .attr("width", svg_dx)
            .attr("height", svg_dy);

d3.csv("/data/states.csv", d => {

    var n = d.length;

    var d_extent_x = d3.extent(d, d => +d.income),
        d_extent_y = d3.extent(d, d => +d.hs_grad);

    x.domain(d_extent_x);
    y.domain(d_extent_y);

    var axis_x = d3.axisBottom(x)
                   .tickFormat(formatIncome),
        axis_y = d3.axisLeft(y)
                   .tickFormat(formatHsGradAxis);

    svg.append("g")
       .attr("id", "axis_x")
       .attr("transform", "translate(0," + (plot_dy + margin.bottom / 2) + ")")
       .call(axis_x);

    svg.append("g")
       .attr("id", "axis_y")
       .attr("transform", "translate(" + (margin.left / 2) + ", 0)")
       .call(axis_y);

    d3.select("#axis_x")
      .append("text")
      .attr("transform", "translate(360, -10)")
      .text("Per capita income (1974)");

    d3.select("#axis_y")
      .append("text")
      .attr("transform", "rotate(-90) translate(-20, 15)")
      .text("High-school graduates (1970)");

    var circles = svg.append("g")
                     .attr("id", "circles")
                     .selectAll("circle")
                     .data(d)
                     .enter()
                     .append("circle")
                     .attr("r", 5)
                     .attr("cx", (d) => x(+d.income))
                     .attr("cy", (d) => y(+d.hs_grad))
                     .attr("class", "non_brushed");


    function highlightBrushedCircles() {

        if (d3.event.selection != null) {

            // revert circles to initial style
            circles.attr("class", "non_brushed");

            var brush_coords = d3.brushSelection(this);

            // style brushed circles
            circles.filter(function (){

                       var cx = d3.select(this).attr("cx"),
                           cy = d3.select(this).attr("cy");

                       return isBrushed(brush_coords, cx, cy);
                   })
                   .attr("class", "brushed");
        }
    }

    function displayTable() {

        // disregard brushes w/o selections  
        // ref: http://bl.ocks.org/mbostock/6232537
        if (!d3.event.selection) return;

        // programmed clearing of brush after mouse-up
        // ref: https://github.com/d3/d3-brush/issues/10
        d3.select(this).call(brush.move, null);

        var d_brushed =  d3.selectAll(".brushed").data();

        // populate table if one or more elements is brushed
        if (d_brushed.length > 0) {
            clearTableRows();
            d_brushed.forEach(d_row => populateTableRow(d_row))
        } else {
            clearTableRows();
        }
    }

    var brush = d3.brush()
                  .on("brush", highlightBrushedCircles)
                  .on("end", displayTable); 

    svg.append("g")
       .call(brush);
});

function clearTableRows() {

    hideTableColNames();
    d3.selectAll(".row_data").remove();
}

function isBrushed(brush_coords, cx, cy) {

     var x0 = brush_coords[0][0],
         x1 = brush_coords[1][0],
         y0 = brush_coords[0][1],
         y1 = brush_coords[1][1];

    return x0 <= cx && cx <= x1 && y0 <= cy && cy <= y1;
}

function hideTableColNames() {
    d3.select("table").style("visibility", "hidden");
}

function showTableColNames() {
    d3.select("table").style("visibility", "visible");
}

function populateTableRow(d_row) {

    showTableColNames();

    var d_row_filter = [d_row.state, 
                        formatIncome(d_row.income), 
                        formatHsGrad(d_row.hs_grad)];

    d3.select("table")
      .append("tr")
      .attr("class", "row_data")
      .selectAll("td")
      .data(d_row_filter)
      .enter()
      .append("td")
      .attr("align", (d, i) => i == 0 ? "left" : "right")
      .text(d => d);
}