content: /*
   * SonarQube
   * Copyright (C) 2009-2016 SonarSource SA
   * mailto:contact AT sonarsource DOT com
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 3 of the License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public License
   * along with this program; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   */
  import d3 from 'd3';
  import React from 'react';
  import { ResizeMixin } from './../mixins/resize-mixin';
  import { TooltipsMixin } from './../mixins/tooltips-mixin';
  
  export const BarChart = React.createClass({
    propTypes: {
      data: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
      xTicks: React.PropTypes.arrayOf(React.PropTypes.any),
      xValues: React.PropTypes.arrayOf(React.PropTypes.any),
      height: React.PropTypes.number,
      padding: React.PropTypes.arrayOf(React.PropTypes.number),
      barsWidth: React.PropTypes.number.isRequired,
      onBarClick: React.PropTypes.func
    },
  
    mixins: [ResizeMixin, TooltipsMixin],
  
    getDefaultProps () {
      return {
        xTicks: [],
        xValues: [],
        padding: [10, 10, 10, 10]
      };
    },
  
    getInitialState () {
      return { width: this.props.width, height: this.props.height };
    },
  
    handleClick (point) {
      this.props.onBarClick(point);
    },
  
    renderXTicks (xScale, yScale) {
      if (!this.props.xTicks.length) {
        return null;
      }
      const ticks = this.props.xTicks.map((tick, index) => {
        const point = this.props.data[index];
        const x = Math.round(xScale(point.x) + xScale.rangeBand() / 2);
        const y = yScale.range()[0];
        const d = this.props.data[index];
        const tooltipAtts = {};
        if (d.tooltip) {
          tooltipAtts['title'] = d.tooltip;
          tooltipAtts['data-toggle'] = 'tooltip';
        }
        return (
            <text
                key={index}
                className="bar-chart-tick"
                x={x}
                y={y}
                dy="1.5em"
                onClick={this.props.onBarClick && this.handleClick.bind(this, point)}
                style={{ cursor: this.props.onBarClick ? 'pointer' : 'default' }}
                {...tooltipAtts}>
              {tick}
            </text>
        );
      });
      return <g>{ticks}</g>;
    },
  
    renderXValues (xScale, yScale) {
      if (!this.props.xValues.length) {
        return null;
      }
      const ticks = this.props.xValues.map((value, index) => {
        const point = this.props.data[index];
        const x = Math.round(xScale(point.x) + xScale.rangeBand() / 2);
        const y = yScale(point.y);
        const d = this.props.data[index];
        const tooltipAtts = {};
        if (d.tooltip) {
          tooltipAtts['title'] = d.tooltip;
          tooltipAtts['data-toggle'] = 'tooltip';
        }
        return (
            <text
                key={index}
                className="bar-chart-tick"
                x={x}
                y={y}
                dy="-1em"
                onClick={this.props.onBarClick && this.handleClick.bind(this, point)}
                style={{ cursor: this.props.onBarClick ? 'pointer' : 'default' }}
                {...tooltipAtts}>
              {value}
            </text>
        );
      });
      return <g>{ticks}</g>;
    },
  
    renderBars (xScale, yScale) {
      const bars = this.props.data.map((d, index) => {
        const x = Math.round(xScale(d.x));
        const maxY = yScale.range()[0];
        const y = Math.round(yScale(d.y)) - /* minimum bar height */ 1;
        const height = maxY - y;
        const tooltipAtts = {};
        if (d.tooltip) {
          tooltipAtts['title'] = d.tooltip;
          tooltipAtts['data-toggle'] = 'tooltip';
        }
        return (
            <rect
                key={index}
                className="bar-chart-bar"
                {...tooltipAtts}
                x={x}
                y={y}
                width={this.props.barsWidth}
                height={height}
                onClick={this.props.onBarClick && this.handleClick.bind(this, d)}
                style={{ cursor: this.props.onBarClick ? 'pointer' : 'default' }}/>
        );
      });
      return <g>{bars}</g>;
    },
  
    render () {
      if (!this.state.width || !this.state.height) {
        return <div/>;
      }
  
      const availableWidth = this.state.width - this.props.padding[1] - this.props.padding[3];
      const availableHeight = this.state.height - this.props.padding[0] - this.props.padding[2];
  
      const innerPadding = (availableWidth - this.props.barsWidth * this.props.data.length) /
          (this.props.data.length - 1);
      const relativeInnerPadding = innerPadding / (innerPadding + this.props.barsWidth);
  
      const maxY = d3.max(this.props.data, d => d.y);
      const xScale = d3.scale.ordinal()
          .domain(this.props.data.map(d => d.x))
          .rangeBands([0, availableWidth], relativeInnerPadding, 0);
      const yScale = d3.scale.linear()
          .domain([0, maxY])
          .range([availableHeight, 0]);
  
      return (
          <svg className="bar-chart" width={this.state.width} height={this.state.height}>
            <g transform={`translate(${this.props.padding[3]}, ${this.props.padding[0]})`}>
              {this.renderXTicks(xScale, yScale)}
              {this.renderXValues(xScale, yScale)}
              {this.renderBars(xScale, yScale)}
            </g>
          </svg>
      );
    }
  });
  