'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 _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();

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 _yogaLayout = require('yoga-layout');

var _yogaLayout2 = _interopRequireDefault(_yogaLayout);

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

var _lodash2 = _interopRequireDefault(_lodash);

var _lodash3 = require('lodash.isfunction');

var _lodash4 = _interopRequireDefault(_lodash3);

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

var _lodash6 = _interopRequireDefault(_lodash5);

var _Node2 = require('./Node');

var _Node3 = _interopRequireDefault(_Node2);

var _lodash7 = require('lodash.pick');

var _lodash8 = _interopRequireDefault(_lodash7);

var _lodash9 = require('lodash.merge');

var _lodash10 = _interopRequireDefault(_lodash9);

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

var _warning2 = _interopRequireDefault(_warning);

var _stylesheet = require('../stylesheet');

var _stylesheet2 = _interopRequireDefault(_stylesheet);

var _debug = require('../mixins/debug');

var _debug2 = _interopRequireDefault(_debug);

var _borders = require('../mixins/borders');

var _borders2 = _interopRequireDefault(_borders);

var _styles = require('../utils/styles');

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

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

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

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var PERCENT = /^(\d+)?%$/g;

var Base = function (_Node) {
  _inherits(Base, _Node);

  function Base(root, props) {
    _classCallCheck(this, Base);

    var _this = _possibleConstructorReturn(this, (Base.__proto__ || Object.getPrototypeOf(Base)).call(this));

    _this.root = root;
    _this.parent = null;
    _this.children = [];

    _this.props = (0, _lodash10.default)({}, _this.constructor.defaultProps, Base.defaultProps, props);

    (0, _warning2.default)(!_this.props.styles, '"styles" prop passed instead of "style" prop');

    _this.layout = _yogaLayout2.default.Node.createDefault();
    _this.canBeSplitted = false;
    return _this;
  }

  _createClass(Base, [{
    key: 'appendChild',
    value: function appendChild(child) {
      if (child) {
        child.parent = this;
        this.children.push(child);
        this.layout.insertChild(child.layout, this.layout.getChildCount());
      }
    }
  }, {
    key: 'removeChild',
    value: function removeChild(child) {
      var index = this.children.indexOf(child);

      if (index !== -1) {
        child.parent = null;
        this.children.splice(index, 1);
        this.layout.removeChild(child.layout);
      }
    }
  }, {
    key: 'moveTo',
    value: function moveTo(parent) {
      this.reset();
      this.parent.removeChild(this);
      parent.appendChild(this);
    }
  }, {
    key: 'applyProps',
    value: function applyProps() {
      var _this2 = this;

      var _page = this.page,
          size = _page.size,
          orientation = _page.orientation;


      this.style = this.style || _stylesheet2.default.resolve(this.props.style, {
        width: size[0],
        height: size[1],
        orientation: orientation
      });

      (0, _lodash2.default)(this.style).map(function (_ref) {
        var _ref2 = _slicedToArray(_ref, 2),
            attribute = _ref2[0],
            value = _ref2[1];

        _this2.applyStyle(attribute, value);
      });

      this.children.forEach(function (child) {
        if (child.applyProps) {
          child.applyProps();
        }
      });
    }
  }, {
    key: 'setDimension',
    value: function setDimension(attr, value) {
      var fixedMethod = 'set' + (0, _lodash6.default)(attr);
      var percentMethod = fixedMethod + 'Percent';
      var isPercent = PERCENT.exec(value);

      if (isPercent) {
        this.layout[percentMethod](parseInt(isPercent[1], 10));
      } else {
        this.layout[fixedMethod](value);
      }
    }
  }, {
    key: 'setPosition',
    value: function setPosition(edge, value) {
      var isPercent = PERCENT.exec(value);

      if (isPercent) {
        this.layout.setPositionPercent(edge, parseInt(isPercent[1], 10));
      } else {
        this.layout.setPosition(edge, value);
      }
    }
  }, {
    key: 'applyStyle',
    value: function applyStyle(attribute, value) {
      var setter = 'set' + (0, _lodash6.default)(attribute);

      switch (attribute) {
        case 'marginTop':
          this.layout.setMargin(_yogaLayout2.default.EDGE_TOP, this.marginTop || value);
          break;
        case 'marginRight':
          this.layout.setMargin(_yogaLayout2.default.EDGE_RIGHT, this.marginRight || value);
          break;
        case 'marginBottom':
          this.layout.setMargin(_yogaLayout2.default.EDGE_BOTTOM, this.marginBottom || value);
          break;
        case 'marginLeft':
          this.layout.setMargin(_yogaLayout2.default.EDGE_LEFT, this.marginLeft || value);
          break;
        case 'paddingTop':
          this.layout.setPadding(_yogaLayout2.default.EDGE_TOP, this.paddingTop || value);
          break;
        case 'paddingRight':
          this.layout.setPadding(_yogaLayout2.default.EDGE_RIGHT, this.paddingRight || value);
          break;
        case 'paddingBottom':
          this.layout.setPadding(_yogaLayout2.default.EDGE_BOTTOM, this.paddingBottom || value);
          break;
        case 'paddingLeft':
          this.layout.setPadding(_yogaLayout2.default.EDGE_LEFT, this.paddingLeft || value);
          break;
        case 'borderTopWidth':
          this.layout.setBorder(_yogaLayout2.default.EDGE_TOP, value);
          break;
        case 'borderRightWidth':
          this.layout.setBorder(_yogaLayout2.default.EDGE_RIGHT, value);
          break;
        case 'borderBottomWidth':
          this.layout.setBorder(_yogaLayout2.default.EDGE_BOTTOM, value);
          break;
        case 'borderLeftWidth':
          this.layout.setBorder(_yogaLayout2.default.EDGE_LEFT, value);
          break;
        case 'position':
          this.layout.setPositionType(value === 'absolute' ? _yogaLayout2.default.POSITION_TYPE_ABSOLUTE : _yogaLayout2.default.POSITION_TYPE_RELATIVE);
          break;
        case 'top':
          this.setPosition(_yogaLayout2.default.EDGE_TOP, this.top || value);
          break;
        case 'right':
          this.setPosition(_yogaLayout2.default.EDGE_RIGHT, this.right || value);
          break;
        case 'bottom':
          this.setPosition(_yogaLayout2.default.EDGE_BOTTOM, this.bottom || value);
          break;
        case 'left':
          this.setPosition(_yogaLayout2.default.EDGE_LEFT, this.left || value);
          break;
        case 'width':
        case 'height':
          this.setDimension(attribute, this[attribute] - this.marginLeft - this.marginRight || value);
          break;
        case 'minHeight':
        case 'maxHeight':
        case 'minWidth':
        case 'maxWidth':
          this.setDimension(attribute, value);
          break;
        default:
          if ((0, _lodash4.default)(this.layout[setter])) {
            this.layout[setter](value);
          }
      }
    }
  }, {
    key: 'isAbsolute',
    value: function isAbsolute() {
      return this.props.style.position === 'absolute';
    }
  }, {
    key: 'isEmpty',
    value: function isEmpty() {
      return this.children.length === 0;
    }
  }, {
    key: 'recalculateLayout',
    value: function recalculateLayout() {
      this.children.forEach(function (child) {
        return child.recalculateLayout();
      });
    }
  }, {
    key: 'getAbsoluteLayout',
    value: function getAbsoluteLayout() {
      var parentMargin = this.parent.margin || { left: 0, top: 0 };
      var parentLayout = this.parent.getAbsoluteLayout ? this.parent.getAbsoluteLayout() : { left: 0, top: 0 };

      return {
        left: this.left + parentMargin.left + parentLayout.left,
        top: this.top + parentMargin.top + parentLayout.top,
        height: this.height,
        width: this.width
      };
    }
  }, {
    key: 'getWidth',
    value: function getWidth() {
      return this.layout.getComputedWidth() + this.layout.getComputedMargin(_yogaLayout2.default.EDGE_LEFT) + this.layout.getComputedMargin(_yogaLayout2.default.EDGE_RIGTH) - this.layout.getComputedPadding(_yogaLayout2.default.EDGE_LEFT) - this.layout.getComputedPadding(_yogaLayout2.default.EDGE_RIGTH);
    }
  }, {
    key: 'getHeight',
    value: function getHeight() {
      return this.layout.getComputedHeight() + this.layout.getComputedMargin(_yogaLayout2.default.EDGE_TOP) + this.layout.getComputedMargin(_yogaLayout2.default.EDGE_BOTTOM) - this.layout.getComputedPadding(_yogaLayout2.default.EDGE_TOP) - this.layout.getComputedPadding(_yogaLayout2.default.EDGE_BOTTOM);
    }
  }, {
    key: 'getComputedStyles',
    value: function getComputedStyles() {
      var element = this.parent;
      var inheritedStyles = {};

      while (element && element.parent) {
        inheritedStyles = _extends({}, element.parent.style, element.style, inheritedStyles);
        element = element.parent;
      }

      return _extends({}, (0, _lodash8.default)(inheritedStyles, _styles.inheritedProperties), this.style);
    }
  }, {
    key: 'drawBackgroundColor',
    value: function drawBackgroundColor() {
      var margin = this.margin;

      var _getAbsoluteLayout = this.getAbsoluteLayout(),
          left = _getAbsoluteLayout.left,
          top = _getAbsoluteLayout.top,
          width = _getAbsoluteLayout.width,
          height = _getAbsoluteLayout.height;

      var _getComputedStyles = this.getComputedStyles(),
          backgroundColor = _getComputedStyles.backgroundColor;

      if (backgroundColor) {
        this.root.fillColor(backgroundColor).rect(left + margin.left, top + margin.top, width - margin.left - margin.right, height - margin.top - margin.bottom).fill();
      }
    }
  }, {
    key: 'wrapHeight',
    value: function wrapHeight(height) {
      return Math.min(height, this.height);
    }
  }, {
    key: 'clone',
    value: function clone() {
      var clone = new this.constructor(this.root, this.props);

      clone.width = this.width;
      clone.style = this.style;
      clone.parent = this.parent;
      clone.height = this.height;
      clone.margin = this.margin;
      clone.padding = this.padding;

      return clone;
    }
  }, {
    key: 'renderChildren',
    value: function () {
      var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(page) {
        var absoluteChilds, nonAbsoluteChilds, i, _i;

        return regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                absoluteChilds = this.children.filter(function (child) {
                  return child.isAbsolute();
                });
                nonAbsoluteChilds = this.children.filter(function (child) {
                  return !child.isAbsolute();
                });
                i = 0;

              case 3:
                if (!(i < nonAbsoluteChilds.length)) {
                  _context.next = 9;
                  break;
                }

                _context.next = 6;
                return nonAbsoluteChilds[i].render(page);

              case 6:
                i++;
                _context.next = 3;
                break;

              case 9:
                _i = 0;

              case 10:
                if (!(_i < absoluteChilds.length)) {
                  _context.next = 16;
                  break;
                }

                _context.next = 13;
                return absoluteChilds[_i].render(page);

              case 13:
                _i++;
                _context.next = 10;
                break;

              case 16:
              case 'end':
                return _context.stop();
            }
          }
        }, _callee, this);
      }));

      function renderChildren(_x) {
        return _ref3.apply(this, arguments);
      }

      return renderChildren;
    }()
  }, {
    key: 'page',
    get: function get() {
      return this.parent.page;
    }
  }]);

  return Base;
}(_Node3.default);

Base.defaultProps = {
  style: {},
  minPresenceAhead: 0
};


Object.assign(Base.prototype, _debug2.default);
Object.assign(Base.prototype, _borders2.default);

exports.default = Base;