describe('c3 chart tooltip', function() {
  'use strict'

  var chart
  var tooltipConfiguration = {}
  var dataOrder = 'desc'
  var dataGroups

  var args = function() {
    return {
      data: {
        columns: [
          ['data1', 30, 200, 100, 400, 150, 250], // 1130
          ['data2', 50, 20, 10, 40, 15, 25], // 160
          ['data3', 150, 120, 110, 140, 115, 125] // 760
        ],
        order: dataOrder,
        groups: dataGroups
      },
      tooltip: tooltipConfiguration
    }
  }

  beforeEach(function(done) {
    chart = window.initChart(chart, args(), done)
    dataOrder = 'desc'
    dataGroups = undefined
  })

  describe('tooltip position', function() {
    beforeAll(function() {
      tooltipConfiguration = {}
    })

    describe('without left margin', function() {
      it('should show tooltip on proper position', function() {
        var eventRect = d3.select('.c3-event-rect').node(),
          x = chart.internal.x(1),
          y = chart.internal.y(200)
        window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

        var tooltipContainer = d3.select('.c3-tooltip-container'),
          top = Math.floor(+tooltipContainer.style('top').replace(/px/, '')),
          left = Math.floor(+tooltipContainer.style('left').replace(/px/, ''))
        expect(top).toBeGreaterThan(0)
        expect(left).toBeGreaterThan(0)
      })
    })

    describe('with left margin', function() {
      beforeAll(function() {
        d3.select('#chart').style('margin-left', '300px')
      })

      it('should show tooltip on proper position', function() {
        var eventRect = d3.select('.c3-event-rect').node(),
          x = chart.internal.x(1) + 300, // add margin-left
          y = chart.internal.y(200)
        window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

        var tooltipContainer = d3.select('.c3-tooltip-container'),
          top = Math.floor(+tooltipContainer.style('top').replace(/px/, '')),
          left = Math.floor(+tooltipContainer.style('left').replace(/px/, ''))
        expect(top).toBeGreaterThan(0)
        expect(left).toBeGreaterThan(0)
      })

      afterAll(function() {
        d3.select('#chart').style('margin-left', null)
      })
    })
  })

  describe('tooltip positionFunction', function() {
    var topExpected = 37,
      leftExpected = 79

    beforeAll(function() {
      tooltipConfiguration = {
        position: function(data, width, height, element) {
          expect(data.length).toBe(args().data.columns.length)
          expect(data[0]).toEqual(
            jasmine.objectContaining({
              index: 2,
              value: 100,
              id: 'data1'
            })
          )
          expect(width).toBeGreaterThan(0)
          expect(height).toBeGreaterThan(0)
          expect(element).toBe(d3.select('.c3-event-rect').node())
          return { top: topExpected, left: leftExpected }
        }
      }
    })

    it('should be set to the coordinate where the function returned', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(100)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var tooltipContainer = d3.select('.c3-tooltip-container'),
        top = Math.floor(+tooltipContainer.style('top').replace(/px/, '')),
        left = Math.floor(+tooltipContainer.style('left').replace(/px/, ''))
      expect(top).toBeGreaterThan(0)
      expect(left).toBeGreaterThan(0)
    })
  })

  describe('tooltip getTooltipContent', function() {
    beforeAll(function() {
      tooltipConfiguration = {
        data_order: 'desc'
      }
    })

    it('should sort values desc', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(100)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data3')
      expect(classes[2]).toBe('c3-tooltip-name--data1')
      expect(classes[3]).toBe('c3-tooltip-name--data2')
    })
  })

  describe('tooltip with data_order as desc with grouped data', function() {
    beforeAll(function() {
      dataOrder = 'desc'
      dataGroups = [['data1', 'data2', 'data3']]
    })

    it('should display each data in descending order', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(220)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data1') // 1130
      expect(classes[2]).toBe('c3-tooltip-name--data3') // 760
      expect(classes[3]).toBe('c3-tooltip-name--data2') // 160
    })
  })

  describe('tooltip with data_order as asc with grouped data', function() {
    beforeAll(function() {
      dataOrder = 'asc'
      dataGroups = [['data1', 'data2', 'data3']]
    })

    it('should display each data in ascending order', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(220)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data2') // 160
      expect(classes[2]).toBe('c3-tooltip-name--data3') // 760
      expect(classes[3]).toBe('c3-tooltip-name--data1') // 1130
    })
  })

  describe('tooltip with data_order as NULL with grouped data', function() {
    beforeAll(function() {
      dataOrder = null
      dataGroups = [['data1', 'data2', 'data3']]
    })

    it('should display each data in given order', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(220)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data1')
      expect(classes[2]).toBe('c3-tooltip-name--data2')
      expect(classes[3]).toBe('c3-tooltip-name--data3')
    })
  })

  describe('tooltip with data_order as Function with grouped data', function() {
    beforeAll(function() {
      var order = ['data2', 'data1', 'data3']
      dataOrder = function(data1, data2) {
        return order.indexOf(data1.id) - order.indexOf(data2.id)
      }
      dataGroups = [['data1', 'data2', 'data3']]
    })

    it('should display each data in order given by function', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(220)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data2')
      expect(classes[2]).toBe('c3-tooltip-name--data1')
      expect(classes[3]).toBe('c3-tooltip-name--data3')
    })
  })

  describe('tooltip with data_order as Array with grouped data', function() {
    beforeAll(function() {
      dataOrder = ['data2', 'data1', 'data3']
      dataGroups = [['data1', 'data2', 'data3']]
    })

    it('should display each data in order given by array', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(220)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data2')
      expect(classes[2]).toBe('c3-tooltip-name--data1')
      expect(classes[3]).toBe('c3-tooltip-name--data3')
    })
  })

  describe('tooltip with data_order as desc with un-grouped data', function() {
    beforeAll(function() {
      dataOrder = 'desc'
    })

    it('should display each tooltip value descending order', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(100)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data3') // 110
      expect(classes[2]).toBe('c3-tooltip-name--data1') // 100
      expect(classes[3]).toBe('c3-tooltip-name--data2') // 10
    })
  })

  describe('tooltip with data_order as asc with un-grouped data', function() {
    beforeAll(function() {
      dataOrder = 'asc'
    })

    it('should display each tooltip value in ascending order', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(100)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data2') // 10
      expect(classes[2]).toBe('c3-tooltip-name--data1') // 100
      expect(classes[3]).toBe('c3-tooltip-name--data3') // 110
    })
  })

  describe('tooltip with data_order as NULL with un-grouped data', function() {
    beforeAll(function() {
      dataOrder = null
    })

    it('should display each tooltip value in given data order', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(100)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data1')
      expect(classes[2]).toBe('c3-tooltip-name--data2')
      expect(classes[3]).toBe('c3-tooltip-name--data3')
    })
  })

  describe('tooltip with data_order as Function with un-grouped data', function() {
    beforeAll(function() {
      var order = ['data2', 'data1', 'data3']
      dataOrder = function(data1, data2) {
        return order.indexOf(data1.id) - order.indexOf(data2.id)
      }
    })

    it('should display each tooltip value in data order given by function', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(100)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data2')
      expect(classes[2]).toBe('c3-tooltip-name--data1')
      expect(classes[3]).toBe('c3-tooltip-name--data3')
    })
  })

  describe('tooltip with data_order as Array with un-grouped data', function() {
    beforeAll(function() {
      dataOrder = ['data2', 'data1', 'data3']
    })

    it('should display each tooltip value in data order given by array', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(100)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data2')
      expect(classes[2]).toBe('c3-tooltip-name--data1')
      expect(classes[3]).toBe('c3-tooltip-name--data3')
    })
  })

  describe('tooltip with tooltip_order as desc', function() {
    beforeAll(function() {
      tooltipConfiguration = {
        order: 'desc'
      }

      // this should be ignored
      dataOrder = 'asc'
      dataGroups = [['data1', 'data2', 'data3']]
    })

    it('should display each tooltip value descending order', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(100)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data3') // 110
      expect(classes[2]).toBe('c3-tooltip-name--data1') // 100
      expect(classes[3]).toBe('c3-tooltip-name--data2') // 10
    })
  })

  describe('tooltip with tooltip_order as asc', function() {
    beforeAll(function() {
      tooltipConfiguration = {
        order: 'asc'
      }

      // this should be ignored
      dataOrder = 'desc'
      dataGroups = [['data1', 'data2', 'data3']]
    })

    it('should display each tooltip value in ascending order', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(220)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data2') // 10
      expect(classes[2]).toBe('c3-tooltip-name--data1') // 100
      expect(classes[3]).toBe('c3-tooltip-name--data3') // 110
    })
  })

  describe('tooltip with tooltip_order as NULL', function() {
    beforeAll(function() {
      tooltipConfiguration = {
        order: null
      }
    })

    it('should display each tooltip value in given order', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(100)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data1')
      expect(classes[2]).toBe('c3-tooltip-name--data2')
      expect(classes[3]).toBe('c3-tooltip-name--data3')
    })
  })

  describe('tooltip with tooltip_order as Function', function() {
    beforeAll(function() {
      var order = ['data2', 'data1', 'data3']
      tooltipConfiguration = {
        order: function(data1, data2) {
          return order.indexOf(data1.id) - order.indexOf(data2.id)
        }
      }
    })

    it('should display each tooltip value in data order given by function', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(100)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data2')
      expect(classes[2]).toBe('c3-tooltip-name--data1')
      expect(classes[3]).toBe('c3-tooltip-name--data3')
    })
  })

  describe('tooltip with tooltip_order as Array', function() {
    beforeAll(function() {
      tooltipConfiguration = {
        order: ['data2', 'data1', 'data3']
      }
    })

    it('should display each tooltip value in data order given by array', function() {
      var eventRect = d3.select('.c3-event-rect').node(),
        x = chart.internal.x(2),
        y = chart.internal.y(100)
      window.setMouseEvent(chart, 'mousemove', x, y, eventRect)

      var classes = d3
        .selectAll('.c3-tooltip tr')
        .nodes()
        .map(function(node) {
          return node.className
        })

      expect(classes[0]).toBe('') // header
      expect(classes[1]).toBe('c3-tooltip-name--data2')
      expect(classes[2]).toBe('c3-tooltip-name--data1')
      expect(classes[3]).toBe('c3-tooltip-name--data3')
    })
  })
})
