var React = require('react');
var Support = require('../lib/support');
var d3 = require('d3');

var VBarChart = React.createClass({
  chart: function (selection) {
    var {
      margin,
      width,
      height,
      xRoundBands,
      names,
      values,
      xAxisBottom,
      duration,
      color,
      enterBar,
      updateBar,
      exitBar,
      style
    } = Support.getProps(this, 'chart', {
      margin: Support.types.Object({
        top: Support.types.Number(10),
        right: Support.types.Number(10),
        bottom: Support.types.Number(20),
        left: Support.types.Number(50)
      }),
      width: Support.types.Number(-1),
      height: Support.types.Number(420),
      xRoundBands: Support.types.Number(0.2),
      names: Support.types.Function(function (d) {
        return d[0];
      }),
      values: Support.types.Function(function (d) {
        return d[1];
      }),
      duration: Support.types.Number(500),
      color: Support.types.Function(false),
      enterBar: Support.types.Function(function (bar) {
        bar = bar.append('rect')
          .attr('class', function (d, i) {
            return values(d) < 0 ? 'negative' : 'positive';
          });
        if (color) {
          bar.style('fill', function (d) {
            return color(names(d));
          });
        }
      }),
      updateBar: Support.types.Function(function (bar) {
        bar.select('rect')
          .attr('class', function (d) {
            return values(d) < 0 ? 'negative' : 'positive';
          })
          .attr('x', function (d) {
            return X(d);
          })
          .attr('y', function (d) {
            return values(d) < 0 ? Y0() : Y(d);
          })
          .attr('width', xScale.rangeBand())
          .attr('height', function (d, i) {
            return Math.abs(Y(d) - Y0());
          });
      }),
      exitBar: Support.types.Function(function (bar) {}),
      style: Support.types.Object(false)
    });
    var X = function (d) {
      return xScale(names(d));
    };
    var Y0 = function () {
      return yScale(0);
    };
    var Y = function (d) {
      return yScale(values(d));
    };
    var scaleO = xScale = d3.scale.ordinal();
    var scaleL = yScale = d3.scale.linear();
    var yAxis = d3.svg.axis().scale(scaleL).orient('left');
    var xAxis = d3.svg.axis().scale(scaleO);
    var xAxisBottom = d3.svg.axis().scale(scaleO);
    height = parseInt(height);
    width = parseInt(width);
    duration = parseInt(duration);

    selection.each(function (data) {
      var w = width === -1 ? this.offsetWidth : width;
      // Update the x-scale.
      xScale
        .domain(data.map(names))
        .rangeRoundBands([0, w - margin.left - margin.right], parseFloat(xRoundBands));

      var ys = d3.extent(data.map(values));
      if (ys[0] > 0) {
        ys[0] = 0;
      }

      // Update the y-scale.
      yScale
        .domain(ys)
        .range([height - margin.top - margin.bottom, 0])
        .nice();

      // Select the svg element, if it exists.
      var svg = d3.select(this).selectAll('svg').data([data]);

      // Otherwise, create the skeletal chart.
      var gEnter = svg.enter().append('svg').append('g');
      gEnter.append('g').attr('class', 'bars');
      gEnter.append('g').attr('class', 'y axis');
      gEnter.append('g').attr('class', 'x axis bottom');
      gEnter.append('g').attr('class', 'x axis zero');

      // Update the outer dimensions.
      svg.attr('width', w)
        .attr('height', height);

      // Update the inner dimensions.
      var g = svg.select('g')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

      // Update the bars.
      var bars = svg.select('.bars'); //.selectAll('.bar');//.data(data);
      var bar = bars.selectAll('g.bar').data(data);

      var barEnter = bar.enter()
        .append('g')
        .attr('class', 'bar');
      enterBar(barEnter);
      updateBar(bar.transition().duration(duration));
      var barExit = bar.exit()
        .remove();
      exitBar(barExit);

      // x axis at the bottom of the chart
      g.select('.x.axis.bottom')
        .attr('transform', 'translate(0,' + (height - margin.top - margin.bottom) + ')')
        .call(xAxisBottom.orient('bottom'));
      // zero line
      g.select('.x.axis.zero')
        .attr('transform', 'translate(0,' + Y0() + ')')
        .call(xAxis.tickFormat('').tickSize(0));

      // Update the y-axis.
      g.select('.y.axis')
        .call(yAxis);
      g.selectAll('.axis line')
        .attr('style', 'shape-rendering: crispEdges; stroke: black; fill: none;');
      g.selectAll('.axis path')
        .attr('style', 'shape-rendering: crispEdges; stroke: black; fill: none;');

      if (style) {
        Object.keys(style).forEach(function (key) {
          svg.selectAll(key).attr('style', style[key]);
        });
      }
    });
  },
  renderChart: function (data) {
    if (!data) {
      return;
    }
    var container = this.getDOMNode();
    d3.select(container)
      .datum(data)
      .call(this.chart);
  },
  componentDidMount: function () {
    return this.renderChart(this.props.data);
  },
  componentDidUpdate: function () {
    return this.renderChart(this.props.data);
  },
  render: function () {
    var classNames = Support.classList(this, {
      'bar-chart': true
    });
    return <div className={classNames} />;
  }
});

var HBarChart = React.createClass({
  chart: function (selection) {
    var {
      margin,
      width,
      height,
      names,
      values,
      duration,
      color,
      enterBar,
      updateBar,
      exitBar,
      style
    } = Support.getProps(this, 'chart', {
      margin: Support.types.Object({
        top: Support.types.Number(0),
        right: Support.types.Number(10),
        bottom: Support.types.Number(20),
        left: Support.types.Number(50)
      }),
      width: Support.types.Number(-1),
      height: Support.types.Number(420),
      names: Support.types.Function(function (d) {
        return d[0];
      }),
      values: Support.types.Function(function (d) {
        return d[1];
      }),
      duration: Support.types.Number(500),
      color: Support.types.Function(d3.scale.category10()),
      enterBar: Support.types.Function(function (bar) {
        bar = bar.append('rect')
          .attr('class', 'bar');
        if (color) {
          bar.style('fill', function (d) {
            return color(names(d));
          });
        }
      }),
      updateBar: Support.types.Function(function (bar) {
        bar.select('rect')
          .attr('x', function (d) {
            return margin.left;
          })
          .attr('y', function (d) {
            return Y(d);
          })
          .attr('width', function (d) {
            return X(d);
          })
          .attr('height', yScale.rangeBand());
      }),
      exitBar: Support.types.Function(function (bar) {}),
      style: Support.types.Object(false)
    });
    var xScale = d3.scale.linear();
    var yScale = d3.scale.ordinal();
    var X = function (d) {
      return xScale(values(d));
    };
    var Y = function (d) {
      return yScale(names(d)) + margin.top;
    };

    selection.each(function (data) {
      var w = width === -1 ? this.offsetWidth : width;
      var maxChartHeight = height - margin.top - margin.bottom;

      if (color && color.domain) {
        var cnames = data.map(names);
        color.domain(cnames);
      }

      var svg = d3.select(this).selectAll('svg').data([data]);
      svg.enter().append('svg')
        .attr('width', w)
        .attr('height', height);

      var maxValue = d3.max(data, values);
      yScale.domain(data.map(names));
      xScale.range([0, w - margin.left - margin.right]).domain([0, maxValue]).nice();
      yScale.rangeBands([0, maxChartHeight], 0.1, 0.25);

      var yAxis = d3.svg.axis().scale(yScale).orient('left');
      var xAxis = d3.svg.axis().scale(xScale).orient('bottom');

      var bars = svg.selectAll('.bar')
        .data(data);
      var barEnter = bars.enter()
        .append('g')
        .attr('class', 'bar');
      enterBar(barEnter);
      updateBar(bars.transition().duration(duration));

      var barExit = bars.exit()
        .remove();
      exitBar(barExit);

      //append x axis
      svg.append("g")
        .attr("transform", "translate(" + margin.left + ", " + (maxChartHeight + margin.top) + ")")
        .attr("text-anchor", "middle")
        .attr("font-family", "sans-serif")
        .attr("font-size", "10px")
        .style("stroke", "black")
        .style("fill", "none")
        .style("stroke-width", 1)
        .style("shape-rendering", "crispEdges")
        .call(xAxis)
        .selectAll("text")
        .attr("stroke", "none")
        .attr("fill", "black");

      //append y axis
      svg.append("g")
        .attr("transform", "translate(" + margin.left + ", " + margin.top + ")")
        .attr("text-anchor", "middle")
        .attr("font-family", "sans-serif")
        .attr("font-size", "10px")
        .style("stroke", "black")
        .style("fill", "none")
        .style("stroke-width", 1)
        .style("shape-rendering", "crispEdges")
        .call(yAxis)
        .selectAll("text")
        .attr("stroke", "none")
        .attr("fill", "black");

      if (style) {
        Object.keys(style).forEach(function (key) {
          svg.selectAll(key).attr('style', style[key]);
        });
      }
    });
  },
  renderChart: function (data) {
    if (!data) {
      return;
    }
    var container = this.getDOMNode();
    d3.select(container)
      .datum(data)
      .call(this.chart);
  },
  componentDidMount: function () {
    return this.renderChart(this.props.data);
  },
  componentDidUpdate: function () {
    return this.renderChart(this.props.data);
  },
  componentWillReceiveProps: function(props) {
    console.log('got new props');
    return this.renderChart(props.data);
  },
  render: function () {
    var classNames = Support.classList(this, {
      'bar-chart': true
    });
    return <div className={classNames} />;
  }
});

module.exports={
  VBarChart: VBarChart,
  HBarChart: HBarChart
};
