text: const Util = require('../../util/common');
  const Shape = require('../shape');
  
  let textWidthCacheCounter = 0;
  let textWidthCache = {};
  const TEXT_CACHE_MAX = 5000;
  
  class Text extends Shape {
    _initProperties() {
      super._initProperties();
      this._attrs.canFill = true;
      this._attrs.canStroke = true;
      this._attrs.type = 'text';
    }
  
    getDefaultAttrs() {
      return {
        lineWidth: 0,
        lineCount: 1,
        fontSize: 12,
        fontFamily: 'sans-serif',
        fontStyle: 'normal',
        fontWeight: 'normal',
        fontVariant: 'normal',
        textAlign: 'start',
        textBaseline: 'bottom',
        lineHeight: null,
        textArr: null
      };
    }
  
    _getFontStyle() {
      const attrs = this._attrs.attrs;
      const { fontSize, fontFamily, fontWeight, fontStyle, fontVariant } = attrs;
      return `${fontStyle} ${fontVariant} ${fontWeight} ${fontSize}px ${fontFamily}`;
    }
  
    _afterAttrsSet() {
      const attrs = this._attrs.attrs;
      attrs.font = this._getFontStyle();
  
      if (attrs.text) {
        const text = attrs.text;
        let textArr;
        if (Util.isString(text) && (text.indexOf('\n') !== -1)) {
          textArr = text.split('\n');
          const lineCount = textArr.length;
          attrs.lineCount = lineCount;
          attrs.textArr = textArr;
        }
      }
      this.set('attrs', attrs);
    }
  
    _getTextHeight() {
      const attrs = this._attrs.attrs;
      if (attrs.height) {
        return attrs.height;
      }
      const lineCount = attrs.lineCount;
      const fontSize = attrs.fontSize * 1;
      if (lineCount > 1) {
        const spaceingY = this._getSpaceingY();
        return fontSize * lineCount + spaceingY * (lineCount - 1);
      }
      return fontSize;
    }
  
    _getSpaceingY() {
      const attrs = this._attrs.attrs;
      const lineHeight = attrs.lineHeight;
      const fontSize = attrs.fontSize * 1;
      return lineHeight ? (lineHeight - fontSize) : fontSize * 0.14;
    }
  
    drawInner(context) {
      const self = this;
      const attrs = self._attrs.attrs;
      const text = attrs.text;
      if (!text) {
        return;
      }
      const textArr = attrs.textArr;
      const fontSize = attrs.fontSize * 1;
      const spaceingY = self._getSpaceingY();
      let x = attrs.x;
      let y = attrs.y;
  
      if (attrs.rotate) { // 文本旋转
        context.translate(x, y);
        context.rotate(attrs.rotate);
        x = 0;
        y = 0;
      }
  
      const textBaseline = attrs.textBaseline;
      let height;
      if (textArr) {
        height = self._getTextHeight();
      }
      let subY;
  
      // context.beginPath();
      if (self.hasFill()) {
        const fillOpacity = attrs.fillOpacity;
        if (!Util.isNil(fillOpacity) && fillOpacity !== 1) {
          context.globalAlpha = fillOpacity;
        }
        if (textArr) {
          for (let i = 0, len = textArr.length; i < len; i++) {
            const subText = textArr[i];
            subY = y + i * (spaceingY + fontSize) - height + fontSize; // bottom;
            if (textBaseline === 'middle') {
              subY += height - fontSize - (height - fontSize) / 2;
            }
            if (textBaseline === 'top') {
              subY += height - fontSize;
            }
            context.fillText(subText, x, subY);
          }
        } else {
          context.fillText(text, x, y);
        }
      }
  
      if (self.hasStroke()) {
        if (textArr) {
          for (let i = 0, len = textArr.length; i < len; i++) {
            const subText = textArr[i];
            subY = y + i * (spaceingY + fontSize) - height + fontSize; // bottom;
            if (textBaseline === 'middle') {
              subY += height - fontSize - (height - fontSize) / 2;
            }
            if (textBaseline === 'top') {
              subY += height - fontSize;
            }
            context.strokeText(subText, x, subY);
          }
        } else {
          context.strokeText(text, x, y);
        }
      }
    }
  
    calculateBox() {
      const self = this;
      const attrs = self._attrs.attrs;
      const { x, y, textAlign, textBaseline } = attrs;
      const width = self._getTextWidth(); // attrs.width
      if (!width) {
        // 如果width不存在，四点共其实点
        return {
          minX: x,
          minY: y,
          maxX: x,
          maxY: y
        };
      }
      const height = self._getTextHeight(); // attrs.height
      const point = {
        x,
        y: y - height
      }; // default textAlign: start, textBaseline: bottom
  
      if (textAlign) {
        if (textAlign === 'end' || textAlign === 'right') {
          point.x -= width;
        } else if (textAlign === 'center') {
          point.x -= width / 2;
        }
      }
  
      if (textBaseline) {
        if (textBaseline === 'top') {
          point.y += height;
        } else if (textBaseline === 'middle') {
          point.y += height / 2;
        }
      }
  
      return {
        minX: point.x,
        minY: point.y,
        maxX: point.x + width,
        maxY: point.y + height
      };
    }
  
    _getTextWidth() {
      const attrs = this._attrs.attrs;
      if (attrs.width) {
        return attrs.width;
      }
      const text = attrs.text;
      const context = this.get('context');
  
      if (Util.isNil(text)) return undefined;
  
      const font = attrs.font;
      const textArr = attrs.textArr;
      const key = text + '' + font;
      if (textWidthCache[key]) {
        return textWidthCache[key];
      }
  
      let width = 0;
      if (textArr) {
        for (let i = 0, length = textArr.length; i < length; i++) {
          const subText = textArr[i];
          width = Math.max(width, Util.measureText(subText, font, context).width);
        }
      } else {
        width = Util.measureText(text, font, context).width;
      }
  
      if (textWidthCacheCounter > TEXT_CACHE_MAX) {
        textWidthCacheCounter = 0;
        textWidthCache = {};
      }
      textWidthCacheCounter++;
      textWidthCache[key] = width;
  
      return width;
    }
  }
  
  Shape.Text = Text;
  module.exports = Text;
  