text: import Graphics from '../Graphics'
  import AxesUtils from './AxesUtils'
  
  /**
   * ApexCharts XAxis Class for drawing X-Axis.
   *
   * @module XAxis
   **/
  
  export default class XAxis {
    constructor(ctx) {
      this.ctx = ctx
      this.w = ctx.w
  
      const w = this.w
      this.axesUtils = new AxesUtils(ctx)
  
      this.xaxisLabels = w.globals.labels.slice()
      if (w.globals.timescaleLabels.length > 0 && !w.globals.isBarHorizontal) {
        //  timeline labels are there and chart is not rangeabr timeline
        this.xaxisLabels = w.globals.timescaleLabels.slice()
      }
  
      if (w.config.xaxis.overwriteCategories) {
        this.xaxisLabels = w.config.xaxis.overwriteCategories
      }
      this.drawnLabels = []
      this.drawnLabelsRects = []
  
      if (w.config.xaxis.position === 'top') {
        this.offY = 0
      } else {
        this.offY = w.globals.gridHeight + 1
      }
      this.offY = this.offY + w.config.xaxis.axisBorder.offsetY
      this.isCategoryBarHorizontal =
        w.config.chart.type === 'bar' && w.config.plotOptions.bar.horizontal
  
      this.xaxisFontSize = w.config.xaxis.labels.style.fontSize
      this.xaxisFontFamily = w.config.xaxis.labels.style.fontFamily
      this.xaxisForeColors = w.config.xaxis.labels.style.colors
      this.xaxisBorderWidth = w.config.xaxis.axisBorder.width
      if (this.isCategoryBarHorizontal) {
        this.xaxisBorderWidth = w.config.yaxis[0].axisBorder.width.toString()
      }
  
      if (this.xaxisBorderWidth.indexOf('%') > -1) {
        this.xaxisBorderWidth =
          (w.globals.gridWidth * parseInt(this.xaxisBorderWidth, 10)) / 100
      } else {
        this.xaxisBorderWidth = parseInt(this.xaxisBorderWidth, 10)
      }
      this.xaxisBorderHeight = w.config.xaxis.axisBorder.height
  
      // For bars, we will only consider single y xais,
      // as we are not providing multiple yaxis for bar charts
      this.yaxis = w.config.yaxis[0]
    }
  
    drawXaxis() {
      let w = this.w
      let graphics = new Graphics(this.ctx)
  
      let elXaxis = graphics.group({
        class: 'apexcharts-xaxis',
        transform: `translate(${w.config.xaxis.offsetX}, ${w.config.xaxis.offsetY})`
      })
  
      let elXaxisTexts = graphics.group({
        class: 'apexcharts-xaxis-texts-g',
        transform: `translate(${w.globals.translateXAxisX}, ${w.globals.translateXAxisY})`
      })
  
      elXaxis.add(elXaxisTexts)
  
      let labels = []
  
      for (let i = 0; i < this.xaxisLabels.length; i++) {
        labels.push(this.xaxisLabels[i])
      }
  
      this.drawXAxisLabelAndGroup(
        true,
        graphics,
        elXaxisTexts,
        labels,
        w.globals.isXNumeric,
        (i, colWidth) => colWidth
      )
  
      if (w.globals.hasGroups) {
        let labelsGroup = w.globals.groups
  
        labels = []
        for (let i = 0; i < labelsGroup.length; i++) {
          labels.push(labelsGroup[i].title)
        }
  
        let overwriteStyles = {}
        if (w.config.xaxis.group.style) {
          overwriteStyles.xaxisFontSize = w.config.xaxis.group.style.fontSize
          overwriteStyles.xaxisFontFamily = w.config.xaxis.group.style.fontFamily
          overwriteStyles.xaxisForeColors = w.config.xaxis.group.style.colors
          overwriteStyles.fontWeight = w.config.xaxis.group.style.fontWeight
          overwriteStyles.cssClass = w.config.xaxis.group.style.cssClass
        }
  
        this.drawXAxisLabelAndGroup(
          false,
          graphics,
          elXaxisTexts,
          labels,
          false,
          (i, colWidth) => labelsGroup[i].cols * colWidth,
          overwriteStyles
        )
      }
  
      if (w.config.xaxis.title.text !== undefined) {
        let elXaxisTitle = graphics.group({
          class: 'apexcharts-xaxis-title'
        })
  
        let elXAxisTitleText = graphics.drawText({
          x: w.globals.gridWidth / 2 + w.config.xaxis.title.offsetX,
          y:
            this.offY +
            parseFloat(this.xaxisFontSize) +
            w.globals.xAxisLabelsHeight +
            w.config.xaxis.title.offsetY,
          text: w.config.xaxis.title.text,
          textAnchor: 'middle',
          fontSize: w.config.xaxis.title.style.fontSize,
          fontFamily: w.config.xaxis.title.style.fontFamily,
          fontWeight: w.config.xaxis.title.style.fontWeight,
          foreColor: w.config.xaxis.title.style.color,
          cssClass:
            'apexcharts-xaxis-title-text ' + w.config.xaxis.title.style.cssClass
        })
  
        elXaxisTitle.add(elXAxisTitleText)
  
        elXaxis.add(elXaxisTitle)
      }
  
      if (w.config.xaxis.axisBorder.show) {
        const offX = w.globals.barPadForNumericAxis
        let elHorzLine = graphics.drawLine(
          w.globals.padHorizontal + w.config.xaxis.axisBorder.offsetX - offX,
          this.offY,
          this.xaxisBorderWidth + offX,
          this.offY,
          w.config.xaxis.axisBorder.color,
          0,
          this.xaxisBorderHeight
        )
  
        elXaxis.add(elHorzLine)
      }
  
      return elXaxis
    }
  
    drawXAxisLabelAndGroup(
      isLeafGroup,
      graphics,
      elXaxisTexts,
      labels,
      isXNumeric,
      colWidthCb,
      overwriteStyles = {}
    ) {
      let drawnLabels = []
      let drawnLabelsRects = []
      let w = this.w
  
      const xaxisFontSize = overwriteStyles.xaxisFontSize || this.xaxisFontSize
      const xaxisFontFamily =
        overwriteStyles.xaxisFontFamily || this.xaxisFontFamily
      const xaxisForeColors =
        overwriteStyles.xaxisForeColors || this.xaxisForeColors
      const fontWeight =
        overwriteStyles.fontWeight || w.config.xaxis.labels.style.fontWeight
      const cssClass =
        overwriteStyles.cssClass || w.config.xaxis.labels.style.cssClass
  
      let colWidth
  
      // initial x Position (keep adding column width in the loop)
      let xPos = w.globals.padHorizontal
  
      let labelsLen = labels.length
      let datapoints = w.globals.dataPoints
  
      if (isXNumeric) {
        let len = datapoints > 1 ? datapoints - 1 : datapoints
        colWidth = w.globals.gridWidth / len
        xPos = xPos + colWidthCb(0, colWidth) / 2 + w.config.xaxis.labels.offsetX
      } else {
        colWidth = w.globals.gridWidth / datapoints
        xPos = xPos + colWidthCb(0, colWidth) + w.config.xaxis.labels.offsetX
      }
  
      for (let i = 0; i <= labelsLen - 1; i++) {
        let x = xPos - colWidthCb(i, colWidth) / 2 + w.config.xaxis.labels.offsetX
  
        if (
          i === 0 &&
          labelsLen === 1 &&
          colWidth / 2 === xPos &&
          datapoints === 1
        ) {
          // single datapoint
          x = w.globals.gridWidth / 2
        }
        let label = this.axesUtils.getLabel(
          labels,
          [],
          x,
          i,
          drawnLabels,
          xaxisFontSize,
          isLeafGroup
        )
  
        let offsetYCorrection = 28
        if (w.globals.rotateXLabels && isLeafGroup) {
          offsetYCorrection = 22
        }
  
        if (!isLeafGroup) {
          offsetYCorrection =
            offsetYCorrection +
            parseFloat(xaxisFontSize) +
            (w.globals.xAxisLabelsHeight - w.globals.xAxisGroupLabelsHeight) +
            (w.globals.rotateXLabels ? 10 : 0)
        }
  
        const isCategoryTickAmounts =
          typeof w.config.xaxis.tickAmount !== 'undefined' &&
          w.config.xaxis.tickAmount !== 'dataPoints' &&
          w.config.xaxis.type !== 'datetime'
  
        if (isCategoryTickAmounts) {
          label = this.axesUtils.checkLabelBasedOnTickamount(i, label, labelsLen)
        } else {
          label = this.axesUtils.checkForOverflowingLabels(
            i,
            label,
            labelsLen,
            drawnLabels,
            drawnLabelsRects
          )
        }
  
        const getCatForeColor = () => {
          return isLeafGroup && w.config.xaxis.convertedCatToNumeric
            ? xaxisForeColors[w.globals.minX + i - 1]
            : xaxisForeColors[i]
        }
  
        if (isLeafGroup && label.text) {
          w.globals.xaxisLabelsCount++
        }
  
        if (w.config.xaxis.labels.show) {
          let elText = graphics.drawText({
            x: label.x,
            y:
              this.offY +
              w.config.xaxis.labels.offsetY +
              offsetYCorrection -
              (w.config.xaxis.position === 'top'
                ? w.globals.xAxisHeight + w.config.xaxis.axisTicks.height - 2
                : 0),
            text: label.text,
            textAnchor: 'middle',
            fontWeight: label.isBold ? 600 : fontWeight,
            fontSize: xaxisFontSize,
            fontFamily: xaxisFontFamily,
            foreColor: Array.isArray(xaxisForeColors)
              ? getCatForeColor()
              : xaxisForeColors,
            isPlainText: false,
            cssClass:
              (isLeafGroup
                ? 'apexcharts-xaxis-label '
                : 'apexcharts-xaxis-group-label ') + cssClass
          })
          elXaxisTexts.add(elText)
  
          if (isLeafGroup) {
            let elTooltipTitle = document.createElementNS(
              w.globals.SVGNS,
              'title'
            )
            elTooltipTitle.textContent = Array.isArray(label.text)
              ? label.text.join(' ')
              : label.text
            elText.node.appendChild(elTooltipTitle)
            if (label.text !== '') {
              drawnLabels.push(label.text)
              drawnLabelsRects.push(label)
            }
          }
        }
        if (i < labelsLen - 1) {
          xPos = xPos + colWidthCb(i + 1, colWidth)
        }
      }
    }
  
    // this actually becomes the vertical axis (for bar charts)
    drawXaxisInversed(realIndex) {
      let w = this.w
      let graphics = new Graphics(this.ctx)
  
      let translateYAxisX = w.config.yaxis[0].opposite
        ? w.globals.translateYAxisX[realIndex]
        : 0
  
      let elYaxis = graphics.group({
        class: 'apexcharts-yaxis apexcharts-xaxis-inversed',
        rel: realIndex
      })
  
      let elYaxisTexts = graphics.group({
        class: 'apexcharts-yaxis-texts-g apexcharts-xaxis-inversed-texts-g',
        transform: 'translate(' + translateYAxisX + ', 0)'
      })
  
      elYaxis.add(elYaxisTexts)
  
      let colHeight
  
      // initial x Position (keep adding column width in the loop)
      let yPos
      let labels = []
  
      if (w.config.yaxis[realIndex].show) {
        for (let i = 0; i < this.xaxisLabels.length; i++) {
          labels.push(this.xaxisLabels[i])
        }
      }
  
      colHeight = w.globals.gridHeight / labels.length
      yPos = -(colHeight / 2.2)
  
      let lbFormatter = w.globals.yLabelFormatters[0]
  
      const ylabels = w.config.yaxis[0].labels
  
      if (ylabels.show) {
        for (let i = 0; i <= labels.length - 1; i++) {
          let label = typeof labels[i] === 'undefined' ? '' : labels[i]
  
          label = lbFormatter(label, {
            seriesIndex: realIndex,
            dataPointIndex: i,
            w
          })
  
          const yColors = this.axesUtils.getYAxisForeColor(
            ylabels.style.colors,
            realIndex
          )
          const getForeColor = () => {
            return Array.isArray(yColors) ? yColors[i] : yColors
          }
  
          let multiY = 0
          if (Array.isArray(label)) {
            multiY = (label.length / 2) * parseInt(ylabels.style.fontSize, 10)
          }
          let elLabel = graphics.drawText({
            x: ylabels.offsetX - 15,
            y: yPos + colHeight + ylabels.offsetY - multiY,
            text: label,
            textAnchor: this.yaxis.opposite ? 'start' : 'end',
            foreColor: getForeColor(),
            fontSize: ylabels.style.fontSize,
            fontFamily: ylabels.style.fontFamily,
            fontWeight: ylabels.style.fontWeight,
            isPlainText: false,
            cssClass: 'apexcharts-yaxis-label ' + ylabels.style.cssClass
          })
  
          elYaxisTexts.add(elLabel)
  
          let elTooltipTitle = document.createElementNS(w.globals.SVGNS, 'title')
          elTooltipTitle.textContent = Array.isArray(label)
            ? label.join(' ')
            : label
          elLabel.node.appendChild(elTooltipTitle)
  
          if (w.config.yaxis[realIndex].labels.rotate !== 0) {
            let labelRotatingCenter = graphics.rotateAroundCenter(elLabel.node)
            elLabel.node.setAttribute(
              'transform',
              `rotate(${w.config.yaxis[realIndex].labels.rotate} 0 ${labelRotatingCenter.y})`
            )
          }
          yPos = yPos + colHeight
        }
      }
  
      if (w.config.yaxis[0].title.text !== undefined) {
        let elXaxisTitle = graphics.group({
          class: 'apexcharts-yaxis-title apexcharts-xaxis-title-inversed',
          transform: 'translate(' + translateYAxisX + ', 0)'
        })
  
        let elXAxisTitleText = graphics.drawText({
          x: 0,
          y: w.globals.gridHeight / 2,
          text: w.config.yaxis[0].title.text,
          textAnchor: 'middle',
          foreColor: w.config.yaxis[0].title.style.color,
          fontSize: w.config.yaxis[0].title.style.fontSize,
          fontWeight: w.config.yaxis[0].title.style.fontWeight,
          fontFamily: w.config.yaxis[0].title.style.fontFamily,
          cssClass:
            'apexcharts-yaxis-title-text ' +
            w.config.yaxis[0].title.style.cssClass
        })
  
        elXaxisTitle.add(elXAxisTitleText)
  
        elYaxis.add(elXaxisTitle)
      }
  
      let offX = 0
      if (this.isCategoryBarHorizontal && w.config.yaxis[0].opposite) {
        offX = w.globals.gridWidth
      }
      const axisBorder = w.config.xaxis.axisBorder
      if (axisBorder.show) {
        let elVerticalLine = graphics.drawLine(
          w.globals.padHorizontal + axisBorder.offsetX + offX,
          1 + axisBorder.offsetY,
          w.globals.padHorizontal + axisBorder.offsetX + offX,
          w.globals.gridHeight + axisBorder.offsetY,
          axisBorder.color,
          0
        )
  
        elYaxis.add(elVerticalLine)
      }
  
      if (w.config.yaxis[0].axisTicks.show) {
        this.axesUtils.drawYAxisTicks(
          offX,
          labels.length,
          w.config.yaxis[0].axisBorder,
          w.config.yaxis[0].axisTicks,
          0,
          colHeight,
          elYaxis
        )
      }
  
      return elYaxis
    }
  
    drawXaxisTicks(x1, y2, appendToElement) {
      let w = this.w
      let x2 = x1
  
      if (x1 < 0 || x1 - 2 > w.globals.gridWidth) return
  
      let y1 = this.offY + w.config.xaxis.axisTicks.offsetY
      y2 = y2 + y1 + w.config.xaxis.axisTicks.height
      if (w.config.xaxis.position === 'top') {
        y2 = y1 - w.config.xaxis.axisTicks.height
      }
  
      if (w.config.xaxis.axisTicks.show) {
        let graphics = new Graphics(this.ctx)
  
        let line = graphics.drawLine(
          x1 + w.config.xaxis.axisTicks.offsetX,
          y1 + w.config.xaxis.offsetY,
          x2 + w.config.xaxis.axisTicks.offsetX,
          y2 + w.config.xaxis.offsetY,
          w.config.xaxis.axisTicks.color
        )
  
        // we are not returning anything, but appending directly to the element passed in param
        appendToElement.add(line)
        line.node.classList.add('apexcharts-xaxis-tick')
      }
    }
  
    getXAxisTicksPositions() {
      const w = this.w
      let xAxisTicksPositions = []
  
      const xCount = this.xaxisLabels.length
      let x1 = w.globals.padHorizontal
  
      if (w.globals.timescaleLabels.length > 0) {
        for (let i = 0; i < xCount; i++) {
          x1 = this.xaxisLabels[i].position
          xAxisTicksPositions.push(x1)
        }
      } else {
        let xCountForCategoryCharts = xCount
        for (let i = 0; i < xCountForCategoryCharts; i++) {
          let x1Count = xCountForCategoryCharts
          if (w.globals.isXNumeric && w.config.chart.type !== 'bar') {
            x1Count -= 1
          }
          x1 = x1 + w.globals.gridWidth / x1Count
          xAxisTicksPositions.push(x1)
        }
      }
  
      return xAxisTicksPositions
    }
  
    // to rotate x-axis labels or to put ... for longer text in xaxis
    xAxisLabelCorrections() {
      let w = this.w
  
      let graphics = new Graphics(this.ctx)
  
      let xAxis = w.globals.dom.baseEl.querySelector('.apexcharts-xaxis-texts-g')
  
      let xAxisTexts = w.globals.dom.baseEl.querySelectorAll(
        '.apexcharts-xaxis-texts-g text:not(.apexcharts-xaxis-group-label)'
      )
      let yAxisTextsInversed = w.globals.dom.baseEl.querySelectorAll(
        '.apexcharts-yaxis-inversed text'
      )
      let xAxisTextsInversed = w.globals.dom.baseEl.querySelectorAll(
        '.apexcharts-xaxis-inversed-texts-g text tspan'
      )
  
      if (w.globals.rotateXLabels || w.config.xaxis.labels.rotateAlways) {
        for (let xat = 0; xat < xAxisTexts.length; xat++) {
          let textRotatingCenter = graphics.rotateAroundCenter(xAxisTexts[xat])
          textRotatingCenter.y = textRotatingCenter.y - 1 // + tickWidth/4;
          textRotatingCenter.x = textRotatingCenter.x + 1
  
          xAxisTexts[xat].setAttribute(
            'transform',
            `rotate(${w.config.xaxis.labels.rotate} ${textRotatingCenter.x} ${textRotatingCenter.y})`
          )
  
          xAxisTexts[xat].setAttribute('text-anchor', `end`)
  
          let offsetHeight = 10
  
          xAxis.setAttribute('transform', `translate(0, ${-offsetHeight})`)
  
          let tSpan = xAxisTexts[xat].childNodes
  
          if (w.config.xaxis.labels.trim) {
            Array.prototype.forEach.call(tSpan, (ts) => {
              graphics.placeTextWithEllipsis(
                ts,
                ts.textContent,
                w.globals.xAxisLabelsHeight -
                  (w.config.legend.position === 'bottom' ? 20 : 10)
              )
            })
          }
        }
      } else {
        let width = w.globals.gridWidth / (w.globals.labels.length + 1)
  
        for (let xat = 0; xat < xAxisTexts.length; xat++) {
          let tSpan = xAxisTexts[xat].childNodes
  
          if (w.config.xaxis.labels.trim && w.config.xaxis.type !== 'datetime') {
            Array.prototype.forEach.call(tSpan, (ts) => {
              graphics.placeTextWithEllipsis(ts, ts.textContent, width)
            })
          }
        }
      }
  
      if (yAxisTextsInversed.length > 0) {
        // truncate rotated y axis in bar chart (x axis)
        let firstLabelPosX = yAxisTextsInversed[
          yAxisTextsInversed.length - 1
        ].getBBox()
        let lastLabelPosX = yAxisTextsInversed[0].getBBox()
  
        if (firstLabelPosX.x < -20) {
          yAxisTextsInversed[
            yAxisTextsInversed.length - 1
          ].parentNode.removeChild(
            yAxisTextsInversed[yAxisTextsInversed.length - 1]
          )
        }
  
        if (
          lastLabelPosX.x + lastLabelPosX.width > w.globals.gridWidth &&
          !w.globals.isBarHorizontal
        ) {
          yAxisTextsInversed[0].parentNode.removeChild(yAxisTextsInversed[0])
        }
  
        // truncate rotated x axis in bar chart (y axis)
        for (let xat = 0; xat < xAxisTextsInversed.length; xat++) {
          graphics.placeTextWithEllipsis(
            xAxisTextsInversed[xat],
            xAxisTextsInversed[xat].textContent,
            w.config.yaxis[0].labels.maxWidth -
              parseFloat(w.config.yaxis[0].title.style.fontSize) * 2 -
              20
          )
        }
      }
    }
  
    // renderXAxisBands() {
    //   let w = this.w;
  
    //   let plotBand = document.createElementNS(w.globals.SVGNS, 'rect')
    //   w.globals.dom.elGraphical.add(plotBand)
    // }
  }
  