text: import Graphics from './Graphics'
  import Utils from '../utils/Utils'
  
  /**
   * ApexCharts Fill Class for setting fill options of the paths.
   *
   * @module Fill
   **/
  
  class Fill {
    constructor(ctx) {
      this.ctx = ctx
      this.w = ctx.w
  
      this.opts = null
      this.seriesIndex = 0
    }
  
    clippedImgArea(params) {
      let w = this.w
      let cnf = w.config
  
      let svgW = parseInt(w.globals.gridWidth, 10)
      let svgH = parseInt(w.globals.gridHeight, 10)
  
      let size = svgW > svgH ? svgW : svgH
  
      let fillImg = params.image
  
      let imgWidth = 0
      let imgHeight = 0
      if (
        typeof params.width === 'undefined' &&
        typeof params.height === 'undefined'
      ) {
        if (
          cnf.fill.image.width !== undefined &&
          cnf.fill.image.height !== undefined
        ) {
          imgWidth = cnf.fill.image.width + 1
          imgHeight = cnf.fill.image.height
        } else {
          imgWidth = size + 1
          imgHeight = size
        }
      } else {
        imgWidth = params.width
        imgHeight = params.height
      }
  
      let elPattern = document.createElementNS(w.globals.SVGNS, 'pattern')
  
      Graphics.setAttrs(elPattern, {
        id: params.patternID,
        patternUnits: params.patternUnits
          ? params.patternUnits
          : 'userSpaceOnUse',
        width: imgWidth + 'px',
        height: imgHeight + 'px'
      })
  
      let elImage = document.createElementNS(w.globals.SVGNS, 'image')
      elPattern.appendChild(elImage)
  
      elImage.setAttributeNS(window.SVG.xlink, 'href', fillImg)
  
      Graphics.setAttrs(elImage, {
        x: 0,
        y: 0,
        preserveAspectRatio: 'none',
        width: imgWidth + 'px',
        height: imgHeight + 'px'
      })
  
      elImage.style.opacity = params.opacity
  
      w.globals.dom.elDefs.node.appendChild(elPattern)
    }
  
    getSeriesIndex(opts) {
      const w = this.w
  
      if (
        ((w.config.chart.type === 'bar' || w.config.chart.type === 'rangeBar') &&
          w.config.plotOptions.bar.distributed) ||
        w.config.chart.type === 'heatmap'
      ) {
        this.seriesIndex = opts.seriesNumber
      } else {
        this.seriesIndex = opts.seriesNumber % w.globals.series.length
      }
  
      return this.seriesIndex
    }
  
    fillPath(opts) {
      let w = this.w
      this.opts = opts
  
      let cnf = this.w.config
      let pathFill
  
      let patternFill, gradientFill
  
      this.seriesIndex = this.getSeriesIndex(opts)
  
      let fillColors = this.getFillColors()
      let fillColor = fillColors[this.seriesIndex]
  
      //override fillcolor if user inputted color with data
      if (w.globals.seriesColors[this.seriesIndex] !== undefined) {
        fillColor = w.globals.seriesColors[this.seriesIndex]
      }
  
      if (typeof fillColor === 'function') {
        fillColor = fillColor({
          seriesIndex: this.seriesIndex,
          dataPointIndex: opts.dataPointIndex,
          value: opts.value,
          w
        })
      }
      let fillType = this.getFillType(this.seriesIndex)
      let fillOpacity = Array.isArray(cnf.fill.opacity)
        ? cnf.fill.opacity[this.seriesIndex]
        : cnf.fill.opacity
  
      let defaultColor = fillColor
  
      if (opts.color) {
        fillColor = opts.color
      }
  
      if (fillColor.indexOf('rgb') === -1) {
        if (fillColor.length < 9) {
          // if the hex contains alpha and is of 9 digit, skip the opacity
          defaultColor = Utils.hexToRgba(fillColor, fillOpacity)
        }
      } else {
        if (fillColor.indexOf('rgba') > -1) {
          fillOpacity = Utils.getOpacityFromRGBA(fillColor)
        }
      }
      if (opts.opacity) fillOpacity = opts.opacity
  
      if (fillType === 'pattern') {
        patternFill = this.handlePatternFill(
          patternFill,
          fillColor,
          fillOpacity,
          defaultColor
        )
      }
  
      if (fillType === 'gradient') {
        gradientFill = this.handleGradientFill(
          fillColor,
          fillOpacity,
          this.seriesIndex
        )
      }
  
      if (fillType === 'image') {
        let imgSrc = cnf.fill.image.src
  
        let patternID = opts.patternID ? opts.patternID : ''
        this.clippedImgArea({
          opacity: fillOpacity,
          image: Array.isArray(imgSrc)
            ? opts.seriesNumber < imgSrc.length
              ? imgSrc[opts.seriesNumber]
              : imgSrc[0]
            : imgSrc,
          width: opts.width ? opts.width : undefined,
          height: opts.height ? opts.height : undefined,
          patternUnits: opts.patternUnits,
          patternID: `pattern${w.globals.cuid}${opts.seriesNumber +
            1}${patternID}`
        })
        pathFill = `url(#pattern${w.globals.cuid}${opts.seriesNumber +
          1}${patternID})`
      } else if (fillType === 'gradient') {
        pathFill = gradientFill
      } else if (fillType === 'pattern') {
        pathFill = patternFill
      } else {
        pathFill = defaultColor
      }
  
      // override pattern/gradient if opts.solid is true
      if (opts.solid) {
        pathFill = defaultColor
      }
  
      return pathFill
    }
  
    getFillType(seriesIndex) {
      const w = this.w
  
      if (Array.isArray(w.config.fill.type)) {
        return w.config.fill.type[seriesIndex]
      } else {
        return w.config.fill.type
      }
    }
  
    getFillColors() {
      const w = this.w
      const cnf = w.config
      const opts = this.opts
  
      let fillColors = []
  
      if (w.globals.comboCharts) {
        if (w.config.series[this.seriesIndex].type === 'line') {
          if (w.globals.stroke.colors instanceof Array) {
            fillColors = w.globals.stroke.colors
          } else {
            fillColors.push(w.globals.stroke.colors)
          }
        } else {
          if (w.globals.fill.colors instanceof Array) {
            fillColors = w.globals.fill.colors
          } else {
            fillColors.push(w.globals.fill.colors)
          }
        }
      } else {
        if (cnf.chart.type === 'line') {
          if (w.globals.stroke.colors instanceof Array) {
            fillColors = w.globals.stroke.colors
          } else {
            fillColors.push(w.globals.stroke.colors)
          }
        } else {
          if (w.globals.fill.colors instanceof Array) {
            fillColors = w.globals.fill.colors
          } else {
            fillColors.push(w.globals.fill.colors)
          }
        }
      }
  
      // colors passed in arguments
      if (typeof opts.fillColors !== 'undefined') {
        fillColors = []
        if (opts.fillColors instanceof Array) {
          fillColors = opts.fillColors.slice()
        } else {
          fillColors.push(opts.fillColors)
        }
      }
  
      return fillColors
    }
  
    handlePatternFill(patternFill, fillColor, fillOpacity, defaultColor) {
      const cnf = this.w.config
      const opts = this.opts
      let graphics = new Graphics(this.ctx)
  
      let patternStrokeWidth =
        cnf.fill.pattern.strokeWidth === undefined
          ? Array.isArray(cnf.stroke.width)
            ? cnf.stroke.width[this.seriesIndex]
            : cnf.stroke.width
          : Array.isArray(cnf.fill.pattern.strokeWidth)
          ? cnf.fill.pattern.strokeWidth[this.seriesIndex]
          : cnf.fill.pattern.strokeWidth
      let patternLineColor = fillColor
  
      if (cnf.fill.pattern.style instanceof Array) {
        if (typeof cnf.fill.pattern.style[opts.seriesNumber] !== 'undefined') {
          let pf = graphics.drawPattern(
            cnf.fill.pattern.style[opts.seriesNumber],
            cnf.fill.pattern.width,
            cnf.fill.pattern.height,
            patternLineColor,
            patternStrokeWidth,
            fillOpacity
          )
          patternFill = pf
        } else {
          patternFill = defaultColor
        }
      } else {
        patternFill = graphics.drawPattern(
          cnf.fill.pattern.style,
          cnf.fill.pattern.width,
          cnf.fill.pattern.height,
          patternLineColor,
          patternStrokeWidth,
          fillOpacity
        )
      }
      return patternFill
    }
  
    handleGradientFill(fillColor, fillOpacity, i) {
      const cnf = this.w.config
      const opts = this.opts
      let graphics = new Graphics(this.ctx)
      let utils = new Utils()
  
      let type = cnf.fill.gradient.type
      let gradientFrom = fillColor
      let gradientTo
      let opacityFrom =
        cnf.fill.gradient.opacityFrom === undefined
          ? fillOpacity
          : Array.isArray(cnf.fill.gradient.opacityFrom)
          ? cnf.fill.gradient.opacityFrom[i]
          : cnf.fill.gradient.opacityFrom
  
      if (gradientFrom.indexOf('rgba') > -1) {
        opacityFrom = Utils.getOpacityFromRGBA(gradientFrom)
      }
      let opacityTo =
        cnf.fill.gradient.opacityTo === undefined
          ? fillOpacity
          : Array.isArray(cnf.fill.gradient.opacityTo)
          ? cnf.fill.gradient.opacityTo[i]
          : cnf.fill.gradient.opacityTo
  
      if (
        cnf.fill.gradient.gradientToColors === undefined ||
        cnf.fill.gradient.gradientToColors.length === 0
      ) {
        if (cnf.fill.gradient.shade === 'dark') {
          gradientTo = utils.shadeColor(
            parseFloat(cnf.fill.gradient.shadeIntensity) * -1,
            fillColor.indexOf('rgb') > -1 ? Utils.rgb2hex(fillColor) : fillColor
          )
        } else {
          gradientTo = utils.shadeColor(
            parseFloat(cnf.fill.gradient.shadeIntensity),
            fillColor.indexOf('rgb') > -1 ? Utils.rgb2hex(fillColor) : fillColor
          )
        }
      } else {
        const gToColor = cnf.fill.gradient.gradientToColors[opts.seriesNumber]
        gradientTo = gToColor
        if (gToColor.indexOf('rgba') > -1) {
          opacityTo = Utils.getOpacityFromRGBA(gToColor)
        }
      }
  
      if (cnf.fill.gradient.inverseColors) {
        let t = gradientFrom
        gradientFrom = gradientTo
        gradientTo = t
      }
  
      if (gradientFrom.indexOf('rgb') > -1) {
        gradientFrom = Utils.rgb2hex(gradientFrom)
      }
      if (gradientTo.indexOf('rgb') > -1) {
        gradientTo = Utils.rgb2hex(gradientTo)
      }
  
      return graphics.drawGradient(
        type,
        gradientFrom,
        gradientTo,
        opacityFrom,
        opacityTo,
        opts.size,
        cnf.fill.gradient.stops,
        cnf.fill.gradient.colorStops,
        i
      )
    }
  }
  
  export default Fill
  