'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _warning = require('fbjs/lib/warning');

var _warning2 = _interopRequireDefault(_warning);

var _pdfRenderer = require('@textkit/pdf-renderer');

var _pdfRenderer2 = _interopRequireDefault(_pdfRenderer);

var _textLayout = require('@react-pdf/text-layout');

var _lodash = require('lodash.upperfirst');

var _lodash2 = _interopRequireDefault(_lodash);

var _emoji = require('../utils/emoji');

var _ignorableChars = require('../utils/ignorableChars');

var _font = require('../font');

var _font2 = _interopRequireDefault(_font);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

// Global layout engine
// It's created dynamically because it may accept a custom hyphenation callback
var LAYOUT_ENGINE = void 0;
var INFINITY = 99999;

// TODO: Import and pass Textkit as a whole
var PDFRenderer = (0, _pdfRenderer2.default)({ Rect: _textLayout.Rect });

var TextEngine = function () {
  function TextEngine(element) {
    _classCallCheck(this, TextEngine);

    this.element = element;
    this._container = null;
    this.start = 0;
    this.end = 0;
    this.computed = false;
    this.preprocessors = [_ignorableChars.ignoreChars, _emoji.embedEmojis];
  }

  _createClass(TextEngine, [{
    key: 'lineIndexAtHeight',
    value: function lineIndexAtHeight(height) {
      var counter = 0;
      for (var i = 0; i < this.lines.length; i++) {
        var line = this.lines[i];

        if (counter + line.height > height) {
          return i;
        }

        counter += line.height;
      }

      return this.lines.length;
    }
  }, {
    key: 'heightAtLineIndex',
    value: function heightAtLineIndex(index) {
      var counter = 0;

      for (var i = 0; i <= index; i++) {
        var line = this.lines[i];
        counter += line.height;
      }

      return counter;
    }
  }, {
    key: 'splice',
    value: function splice(height) {
      var result = this.clone();
      var index = this.lineIndexAtHeight(height);

      result.start = index;
      result.end = this.end;
      this.end = index;

      return result;
    }
  }, {
    key: 'clone',
    value: function clone() {
      var result = new TextEngine(this.element);
      result.computed = this.computed;
      result._container = this._container;
      return result;
    }
  }, {
    key: 'transformText',
    value: function transformText(text, transformation) {
      switch (transformation) {
        case 'uppercase':
          return text.toUpperCase();
        case 'lowercase':
          return text.toLowerCase();
        case 'capitalize':
          return (0, _lodash2.default)(text);
        default:
          return text;
      }
    }
  }, {
    key: 'layout',
    value: function layout(width, dirty) {
      if (this.computed) return;
      var path = new _textLayout.Path().rect(0, 0, width, INFINITY);
      var container = new _textLayout.Container(path);
      var string = _textLayout.AttributedString.fromFragments(this.attributedString).trim();

      // Do the actual text layout
      this.layoutEngine.layout(string, [container]);

      // Get the total amount of rendered lines
      var linesCount = container.blocks.reduce(function (acc, block) {
        return acc + block.lines.length;
      }, 0);

      this.computed = true;
      this._container = container;
      this.end = linesCount + 1;
    }
  }, {
    key: 'render',
    value: function render() {
      var margin = this.element.margin;
      var padding = this.element.padding;

      var _element$getAbsoluteL = this.element.getAbsoluteLayout(),
          top = _element$getAbsoluteL.top,
          left = _element$getAbsoluteL.left;

      // We translate lines based on Yoga container


      var initialX = this.lines[0] ? this.lines[0].rect.y : 0;

      this.lines.forEach(function (line) {
        line.rect.x += left + margin.left + padding.left;
        line.rect.y += top + margin.top + padding.top - initialX;
      });

      var renderer = new PDFRenderer(this.element.root, {
        outlineLines: false
      });
      renderer.render(this.container);
    }
  }, {
    key: 'container',
    get: function get() {
      var lines = this._container.blocks.reduce(function (acc, block) {
        return [].concat(_toConsumableArray(acc), _toConsumableArray(block.lines));
      }, []);

      return _extends({}, this._container, {
        blocks: [{ lines: lines.splice(this.start, this.end) }]
      });
    }
  }, {
    key: 'layoutEngine',
    get: function get() {
      if (!LAYOUT_ENGINE) {
        LAYOUT_ENGINE = new _textLayout.LayoutEngine({
          hyphenationCallback: _font2.default.getHyphenationCallback()
        });
      }

      return LAYOUT_ENGINE;
    }
  }, {
    key: 'lines',
    get: function get() {
      if (!this.container) {
        return [];
      }

      return this.container.blocks.reduce(function (acc, block) {
        return [].concat(_toConsumableArray(acc), _toConsumableArray(block.lines));
      }, []);
    }
  }, {
    key: 'height',
    get: function get() {
      if (!this._container) {
        return -1;
      }

      return this.lines.reduce(function (acc, line) {
        return acc + line.height;
      }, 0);
    }
  }, {
    key: 'width',
    get: function get() {
      if (!this._container) {
        return -1;
      }

      return Math.max.apply(Math, _toConsumableArray(this.lines.map(function (line) {
        return line.advanceWidth;
      })));
    }
  }, {
    key: 'attributedString',
    get: function get() {
      var _this = this;

      var fragments = [];

      var _element$getComputedS = this.element.getComputedStyles(),
          _element$getComputedS2 = _element$getComputedS.color,
          color = _element$getComputedS2 === undefined ? 'black' : _element$getComputedS2,
          _element$getComputedS3 = _element$getComputedS.fontFamily,
          fontFamily = _element$getComputedS3 === undefined ? 'Helvetica' : _element$getComputedS3,
          _element$getComputedS4 = _element$getComputedS.fontSize,
          fontSize = _element$getComputedS4 === undefined ? 18 : _element$getComputedS4,
          _element$getComputedS5 = _element$getComputedS.textAlign,
          textAlign = _element$getComputedS5 === undefined ? 'left' : _element$getComputedS5,
          position = _element$getComputedS.position,
          top = _element$getComputedS.top,
          bottom = _element$getComputedS.bottom,
          align = _element$getComputedS.align,
          lineHeight = _element$getComputedS.lineHeight,
          textDecoration = _element$getComputedS.textDecoration,
          textDecorationColor = _element$getComputedS.textDecorationColor,
          textDecorationStyle = _element$getComputedS.textDecorationStyle,
          textTransform = _element$getComputedS.textTransform;

      (0, _warning2.default)(!align, '"align" style prop will be deprecated on future versions. Please use "textAlign" instead in Text node');

      this.element.children.forEach(function (child) {
        if (typeof child === 'string') {
          var obj = _font2.default.getFont(fontFamily);
          var font = obj ? obj.data : fontFamily;
          var string = _this.transformText(child, textTransform);

          fragments.push({
            string: string,
            attributes: {
              font: font,
              color: color,
              fontSize: fontSize,
              align: textAlign,
              link: _this.element.src,
              underlineStyle: textDecorationStyle,
              underline: textDecoration === 'underline',
              underlineColor: textDecorationColor || color,
              lineHeight: lineHeight ? lineHeight * fontSize : null,
              yOffset: position === 'relative' ? -top || bottom || 0 : null
            }
          });
        } else {
          if (child.engine) {
            var _fragments;

            (_fragments = fragments).push.apply(_fragments, _toConsumableArray(child.engine.attributedString));
          }
        }
      });

      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = this.preprocessors[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var preprocessor = _step.value;

          fragments = preprocessor(fragments);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      return fragments;
    }
  }]);

  return TextEngine;
}();

exports.default = TextEngine;