'use strict';

var React = require("react");
var d3 = require("d3");

module.exports = React.createClass({displayName: "ExtendingArcs",
  getDefaultProps: function() {
    return {
      width: 640,
      height: 480,
      data: []
    };
  },
  componentDidMount: function() {
    var that = this;
    that.m = [30, 10, 10, 10];
    that.w = that.props.width - that.m[1] - that.m[3];
    that.h = that.props.height - that.m[0] - that.m[2];

    that.x = d3.scale.ordinal().rangePoints([0, that.w], 1);
    that.y = {};
    that.dragging = {};

    that.line = d3.svg.line();
    that.axis = d3.svg.axis().orient("left");

    that.svg = d3.select(this.getDOMNode()).append("svg") 
        .attr("width", that.w + that.m[1] + that.m[3])
        .attr("height", that.h + that.m[0] + that.m[2])
      .append("g")
        .attr("transform", "translate(" + that.m[3] + "," + that.m[0] + ")");

    // Add grey background lines for context.
    that.background = that.svg.append("g")
       .attr("class", "background");

    that.foreground = that.svg.append("g")
      .attr("class", "foreground");

  },

  componentDidUpdate: function() {
      var that = this;
      // Extract the list of dimensions and create a scale for each.
      that.x.domain(that.dimensions = d3.keys(that.props.data[0]).filter(function(d) {
        return d !== "name" && (that.y[d] = d3.scale.linear()
            .domain(d3.extent(that.props.data, function(p) { return +p[d]; }))
            .range([that.h, 0]));
      }));
        
      that.bgPaths = that.background.selectAll("path")
          .data(that.props.data);

        that.bgPaths.enter().append("path")
          .attr("d", path);
        that.bgPaths.exit().remove();

      // Add blue foreground lines for focus.
      that.fgPaths = that.foreground.selectAll("path")
          .data(that.props.data);

      that.fgPaths.enter().append("path")
          .attr("d", path);

      that.fgPaths.exit().remove();

      // Add a group element for each dimension.
      that.g = that.svg.selectAll(".dimension")
          .data(that.dimensions);
    
      that.g.enter().append("g")
          .attr("class", "dimension")
          .attr("transform", function(d) { return "translate(" + that.x(d) + ")"; })

          .call(d3.behavior.drag()
            .on("dragstart", function(d) {
              that.dragging[d] = this.__origin__ = that.x(d);
              that.bgPaths.attr("visibility", "hidden");
            })
            .on("drag", function(d) {
              that.dragging[d] = Math.min(that.w, Math.max(0, this.__origin__ += d3.event.dx));
              that.fgPaths.attr("d", path);
              that.dimensions.sort(function(a, b) { return position(a) - position(b); });
              that.x.domain(that.dimensions);
              that.g.attr("transform", function(d) { return "translate(" + position(d) + ")"; });
            })
            .on("dragend", function(d) {
              delete this.__origin__;
              delete that.dragging[d];
              transition(d3.select(this)).attr("transform", "translate(" + that.x(d) + ")");
              transition(that.fgPaths)
                  .attr("d", path);
             that.bgPaths 
                  .attr("d", path)
                  .transition()
                  .delay(500)
                  .duration(0)
                  .attr("visibility", null);
            }));

      that.g.selectAll(".axis").remove(); 
      // Add an axis and title.
      that.g.append("g")
          .attr("class", "axis")
          .each(function(d) {  d3.select(this).call(that.axis.scale(that.y[d])); })
        .append("text")
          .attr("text-anchor", "middle")
          .attr("y", -9)
          .text(String);

      that.g.selectAll(".brush").remove();

      // Add and store a brush for each axis.
      that.g.append("g")
          .attr("class", "brush")
          .each(function(d) { d3.select(this).call(that.y[d].brush = d3.svg.brush().y(that.y[d]).on("brushstart", brushstart).on("brush", brush)); })
        .selectAll("rect")
          .attr("x", -8)
          .attr("width", 16);


    function position(d) {
      var v = that.dragging[d];
      var output = v == null ? that.x(d) : v;
      return output;
    }

    function transition(g) {
      return that.g.transition().duration(500);
    }

    // Returns the path for a given data point.
    function path(d) {
      return that.line(that.dimensions.map(function(p) { 
          return [position(p), that.y[p](d[p])]; 
      }));
    }

    // When brushing, don’t trigger axis dragging.
    function brushstart() {
      d3.event.sourceEvent.stopPropagation();
    }

    // Handles a brush event, toggling the display of foreground lines.
    function brush() {
      var actives = that.dimensions.filter(function(p) { return !that.y[p].brush.empty(); });
      var extents = actives.map(function(p) { return that.y[p].brush.extent(); });
      that.fgPaths.style("display", function(d) {
        return actives.every(function(p, i) {
          return extents[i][0] <= d[p] && d[p] <= extents[i][1];
        }) ? null : "none";
      });
    }
  },
  
  render: function() {
     return ( <div className="ExtendingArcs"></div> ) ;
  },
});