/**
 * Blocks fabric - main object for whole blocks manipulations
 */
function ptsBlockFabric() {
  this._blocks = [];
  this._isSorting = false;
  this._animationSpeed = g_ptsAnimationSpeed;
}
ptsBlockFabric.prototype.addFromHtml = function (blockData, jqueryHtml) {
  var block = this.add(blockData);
  block.setRaw(jqueryHtml);
};
ptsBlockFabric.prototype.add = function (blockData) {
  var blockData = jQuery.extend({}, blockData);
  if (!blockData.original_id) {
    blockData.original_id = blockData.id;
    blockData.id = 0;
  }
  var blockClass = window['ptsBlock_' + blockData.cat_code];
  if (blockClass) {
    var block = new blockClass(blockData);
    var blockIter = this._blocks.push(block);
    block.setIter(blockIter - 1);
    return block;
  } else {
    // console.log('Block Class For ' + blockData.cat_code + ' Not Found!!!');
  }
};
ptsBlockFabric.prototype.getByViewId = function (viewId) {
  if (this._blocks && this._blocks.length) {
    for (var i = 0; i < this._blocks.length; i++) {
      if (this._blocks[i].get('view_id') == viewId) {
        return this._blocks[i];
      }
    }
  }
  return false;
};
/**
 * Base block object - for extending
 * @param {object} blockData all block data from database (block database row)
 */
function ptsBlockBase(blockData) {
  this._data = blockData;
  this._$ = null;
  this._original$ = null;
  this._id = 0;
  this._iter = 0;
  this._elements = [];
  this._animationSpeed = 300;
  this._disableContentChange = false;
  //this._oneTimeElementsInited = false;
}
ptsBlockBase.prototype.get = function (key) {
  return this._data[key];
};
ptsBlockBase.prototype.getParam = function (key) {
  return this._data.params[key] ? this._data.params[key].val : false;
};
ptsBlockBase.prototype.setParam = function (key, value) {
  if (!this._data.params[key]) this._data.params[key] = {};
  this._data.params[key].val = value;
};
ptsBlockBase.prototype.getRaw = function () {
  return this._$;
};
/**
 * Alias for getRaw method
 */
ptsBlockBase.prototype.$ = function () {
  return this.getRaw();
};
ptsBlockBase.prototype.setRaw = function (jqueryHtml) {
  this._$ = jqueryHtml;
  this._resetElements();
  this._initHtml();
  if (this.getParam('font_family')) {
    this._setFont(this.getParam('font_family'));
  }
};
ptsBlockBase.prototype._initElements = function () {
  this._initElementsForArea(this._$);
};
ptsBlockBase.prototype._initElementsForArea = function (area) {
  var block = this
    , addedElements = [];
  var initElement = function (htmlEl) {
    var elementCode = jQuery(htmlEl).data('el')
      , elementClass = window['ptsElement_' + elementCode];
    if (elementClass) {
      var newElement = new elementClass(jQuery(htmlEl), block);
      newElement._setCode(elementCode);
      var newIterNum = block._elements.push(newElement);
      addedElements.push(newElement);
      newElement.setIterNum(newIterNum - 1);	// newIterNum == new length of _elements array, iterator number for element - is new length - 1
    } else {
      // if (g_ptsEdit)
        // console.log('Undefined Element [' + elementCode + '] !!!');
    }
  };
  jQuery(area).find('.ptsEl').each(function () {
    initElement(this);
  });
  if (jQuery(area).hasClass('ptsEl')) {
    initElement(area);
  }
  this._afterInitElements();
  return addedElements;
};
ptsBlockBase.prototype._afterInitElements = function () {
};
ptsBlockBase.prototype._resetElements = function () {
  this._clearElements();
  this._initElements();
};
ptsBlockBase.prototype._clearElements = function () {
  if (this._elements && this._elements.length) {
    for (var i = 0; i < this._elements.length; i++) {
      this._elements[i].destroy();
    }
    this._elements = [];
  }
};
ptsBlockBase.prototype.getElements = function () {
  return this._elements;
};
ptsBlockBase.prototype._initHtml = function () {

};
/**
 * ID number in list of canvas elements
 * @param {numeric} iter Iterator - number in all blocks array - for this element
 */
ptsBlockBase.prototype.setIter = function (iter) {
  this._iter = iter;
};
ptsBlockBase.prototype.showLoader = function (txt) {
  var loaderHtml = jQuery('#ptsBlockLoader');
  txt = txt ? txt : loaderHtml.data('base-txt');
  loaderHtml.find('.ptsBlockLoaderTxt').html(txt);
  loaderHtml.css({
    'height': this._$.height()
    , 'top': this._$.offset().top
  }).addClass('active');
};
ptsBlockBase.prototype.hideLoader = function () {
  var loaderHtml = jQuery('#ptsBlockLoader');
  loaderHtml.removeClass('active');
};
ptsBlockBase.prototype._setFont = function (fontFamily) {
  var $fontLink = this._getFontLink();
  // If this is not standard font - it should be Google font, so - load it from Google Fonts server here

  if (toeInArrayPts(fontFamily, ptsBuildConst.standardFonts) === false) {
    $fontLink.attr({
      'href': 'https://fonts.googleapis.com/css?family=' + encodeURIComponent(fontFamily)
      //,	'data-font-family': fontFamily
    });
  }
  this._$.css({
    'font-family': fontFamily
  });
  this.setParam('font_family', fontFamily);
};
ptsBlockBase.prototype._getFontLink = function () {
  var $link = this._$.find('link.ptsFont');
  if (!$link.length) {
    $link = jQuery('<link class="ptsFont" rel="stylesheet" type="text/css"/>').appendTo(this._$);
  }
  return $link;
};
ptsBlockBase.prototype.getElementByIterNum = function (iterNum) {
  return this._elements[iterNum];
};
ptsBlockBase.prototype.removeElementByIterNum = function (iterNum) {
  this._elements.splice(iterNum, 1);
  if (this._elements && this._elements.length) {
    for (var i = 0; i < this._elements.length; i++) {
      this._elements[i].setIterNum(i);
    }
  }
};
// ptsBlockBase.prototype.destroyElementByIterNum = function(iterNum, clb) {
// 	this.getElementByIterNum( iterNum ).destroy( clb );	// It will call removeElementByIterNum() inside element destroy method
// };
ptsBlockBase.prototype.destroyElementByIterNum = function (iterNum, clb) {
  var element = this.getElementByIterNum(iterNum);
  if (element) {
    element.destroy(clb);  // Pass the callback to destroy
  } else if (clb && typeof (clb) === 'function') {
    clb();  // If no element, still call callback
  }
};
/**
 * Price table block base class
 */
function ptsBlock_price_table(blockData) {
  this._increaseHoverFontPerc = 20;	// Increase font on hover effect, %
  this._$lastHoveredCol = null;
  this._refreshColsBinded = false;
  this._onloadHandle = false;
  this._isAlreadyShowed = false;
  this._isResponsiveDescInit = false;
  ptsBlock_price_table.superclass.constructor.apply(this, arguments);
}
extendPts(ptsBlock_price_table, ptsBlockBase);
ptsBlock_price_table.prototype._getColsContainer = function () {
  return this._$.find('.ptsColsWrapper:first');
};
ptsBlock_price_table.prototype._getCols = function (includeDescCol) {
  return this._getColsContainer().find('.ptsCol' + (includeDescCol ? '' : ':not(.ptsTableDescCol)'));
};
ptsBlock_price_table.prototype._initTooltipsForCells = function () {
  if (this.getParam('disable_custom_tooltip_style') != '1') {
    var $tooltipstedCells = this._$.find('.ptsCell[title], .ptsColFooter[title], .ptsColHeader[title], .ptsColDesc[title]');
    if ($tooltipstedCells && $tooltipstedCells.length) {
      // TODO: Move this to Options and make this part more flexible
      var tooltipsterSettings = {
        contentAsHTML: true
        , interactive: true
        , speed: 250
        , delay: 0
        , animation: 'swing'
        , maxWidth: 450
        , position: 'top'
      };
      $tooltipstedCells.tooltipster(tooltipsterSettings);

      $tooltipstedCells.each(function () {
        var el = jQuery(this);
        el.attr('data-title', el.attr('title')).removeAttr('title');
      });
    }
  }
};
ptsBlock_price_table.prototype._afterInitElements = function () {
  ptsBlock_price_table.superclass._afterInitElements.apply(this, arguments);
  if (parseInt(this.getParam('enb_hover_animation')) == 1) {
    this._initHoverEffect();
  }
  if (this.getParam('table_align'))
    this._$.addClass('ptsTableAlign_' + this.getParam('table_align'));
  if (this.getParam('text_align'))
    this._$.addClass('ptsAlign_' + this.getParam('text_align'));
  if (this.getParam('ajax'))
    this._$.addClass('ptsAjax_' + this.getParam('ajax'));
  if (!this._disableContentChange) {
    this._refreshCellsHeight();
  }
  if (!this._refreshColsBinded) {
    this._$.bind('ptsBlockContentChanged', jQuery.proxy(function () {
      this._refreshCellsHeight();
    }, this));
    this._refreshColsBinded = true;
  }
  if (!_ptsIsEditMode()) { // Not for edit mode unfortunatelly ....
    this._initTooltipsForCells();
    /*var $tooltipstedCells = this._$.find('.ptsCell[title], .ptsColFooter[title], .ptsColHeader[title], .ptsColDesc[title]');

    if(this.getParam('disable_custom_tooltip_style') != '1') {
      if($tooltipstedCells && $tooltipstedCells.length) {
        // TODO: Move this to Options and make this part more flexible
        var tooltipsterSettings = {
          contentAsHTML: true
          ,	interactive: true
          ,	speed: 250
          ,	delay: 0
          ,	animation: 'swing'
          ,	maxWidth: 450
          ,	position: 'top'
        };
        $tooltipstedCells.tooltipster( tooltipsterSettings );
      }
    }*/
    var self = this
      , PTS_VISIBLE_SET_HEIGHT_KEY = 'PTS-VISIBLE-SET-HEIGHT-KEY';

    this._fixResponsive();

    jQuery(window).resize(function () {
      if (!self._$.is(':visible')) {
        self._$.data(PTS_VISIBLE_SET_HEIGHT_KEY, false);
      } else {
        self._fixResponsive();
        self._refreshCellsHeight();
      }
    });
    jQuery('.ptsTableFrontedShell .ptsPreDisplayStyle').remove();
    jQuery('.ptsBlock').css({
      'opacity': '1'
      , 'visibility': 'visible'
    });
    jQuery(window).on('toggleChangeCellHeight', function () {
      self._refreshCellsHeight();
    });
    jQuery(function () {
      var isEnableLazyLoad = function () {
        return self._$.find('img[data-lazy-src]:not(.lazyloaded)').length > 0;
      }, checkedLazyLoadLib = false;

      if (isEnableLazyLoad()) {
        checkedLazyLoadLib = true;
      }

      var observer = new MutationObserver(function (mutationsList) {
        for (var mutation of mutationsList) {
          if (mutation.type === 'childList') {
            jQuery(mutation.addedNodes).each(function () {
              if (this.nodeType === 1 && this.nodeName === 'IMG' && self._$ && self._$.get(0) && jQuery.contains(self._$.get(0), this)) {
                if (checkedLazyLoadLib) {
                  var isLoadedImages = true;

                  self._$.find('img[data-lazy-src]').each(function () {
                    var $this = jQuery(this);

                    if (!$this.hasClass('lazyloaded') && !$this.hasClass('lazyload')) {
                      isLoadedImages = false;
                    }
                  });

                  if (isLoadedImages) {
                    checkedLazyLoadLib = false;

                    self._$.find('img[data-lazy-src]').on('load', function () {
                      self._fixResponsive();
                      self._refreshCellsHeight();
                    });
                  }
                }
              }
            });
          }
        }

        if (self._isAlreadyShowed || !self._$) return;

        if (self._$.visible()) {
          self._isAlreadyShowed = true;
          self._fixResponsive();
          self._refreshCellsHeight();
        }
      });

      observer.observe(document.body, {
        childList: true,
        subtree: true
      });

      self.setCalcWidth();
    });
  } else {
    this.columnChidrensWidthCalc();
  }

  var self = this;

  if (!this._onloadHandle) {
    this._onloadHandle = true;
    jQuery(window).on("load", function () {
      self._refreshCellsHeight();
    });
  }
};
ptsBlock_price_table.prototype._initHoverEffect = function () {
  // if(_ptsIsEditMode()) {
  // 	this.setParam('enb_hover_animation', 1);
  // 	return;
  // }

  if (parseInt(this.getParam('enb_hover_animation')) == 1) {
    var $cols = this._getCols()
      , self = this;
    $cols.mouseenter((e) => {
      self._increaseHoverFont(jQuery(e.currentTarget));
    })
      .mouseleave((e) => {
        self._backHoverFont(jQuery(e.currentTarget));
      })
      .mouseover((e) => {
        self._increaseHoverFont(jQuery(e.currentTarget));
      })
      .mouseout((e) => {
        self._backHoverFont(jQuery(e.currentTarget));
      });
  }

};
ptsBlock_price_table.prototype._increaseHoverFont = function ($col) {
  var self = this;
  if (_ptsIsEditMode()) return;	// Not for edit mode unfortunatelly ....
  var $descCell = $col.find('.ptsColDesc');
  $col.height($col.height()); // Reset height on frontend.tables.js (listeners: window resize)
  $descCell.find('span').each(function () {
    var newFontSize = jQuery(this).data('new-font-size');
    if (!newFontSize) {
      var prevFontSize = jQuery(this).css('font-size')
        , fontUnits = prevFontSize.replace(/\d+/, '')
        , fontSize = parseInt(str_replace(prevFontSize, fontUnits, ''));
      if (fontSize && fontUnits) {
        newFontSize = Math.ceil(fontSize + (self._increaseHoverFontPerc * fontSize / 100));
        jQuery(this)
          .data('prev-font-size', prevFontSize)
          .data('font-units', fontUnits)
          .data('new-font-size', newFontSize);
      }
    }
    if (newFontSize) {
      jQuery(this).css('font-size', newFontSize + jQuery(this).data('font-units'));
    }
  });

  if (this.getParam('is_horisontal_row_type') != '1') {

    if (!$descCell.attr('data-prev-height')) {
      var descHeight = $descCell.outerHeight();
      $descCell.attr('data-prev-height', descHeight);
    } else {
      descHeight = $descCell.attr('data-prev-height');
    }
    $descCell.css({
      'min-height': descHeight
      , 'height': 'auto'
    });
  }

  $col.addClass('hover');
  if (_ptsIsEditMode()) {
    setTimeout(function () {
      var colElement = self.getElementByIterNum($col.data('iter-num'));
      if (colElement) {
        colElement.repositeMenu();
      }
    }, g_ptsHoverAnim);	// 300 - standard animation speed
  }
};
ptsBlock_price_table.prototype._backHoverFont = function ($col) {
  if (_ptsIsEditMode()) return;	// Not for edit mode unfortunatelly ....
  $col.removeClass('hover');
  var $descCell = $col.find('.ptsColDesc');
  $descCell.find('span').each(function () {
    var prevFontSize = jQuery(this).data('prev-font-size');
    if (prevFontSize) {
      jQuery(this).css('font-size', prevFontSize);
    }
  });
  setTimeout(function () {
    $descCell.outerHeight($descCell.data('prev-height'));
  }, 300);	// time is set in css styles, but it always is something around 300ms
};
ptsBlock_price_table.prototype._disableHoverEffect = function ($cols) {
  if (_ptsIsEditMode()) return;	// Not for edit mode unfortunatelly ....
  $cols = $cols ? $cols : this._getCols();
  //$cols.unbind('hover.animation');
};
ptsBlock_price_table.prototype.getColSelectors = function () {
  return {
    header: { sel: '.ptsColHeader' }
    , desc: { sel: '.ptsColDesc' }
    , rows: { sel: '.ptsRows' }
    , cells: { sel: '.ptsCell' }
    , footer: { sel: '.ptsColFooter' }
  };
};
ptsBlock_price_table.prototype.getMaxColsSizes = function (widthDesc) {
  var $cols = this._getCols(widthDesc)
    , sizes = this.getColSelectors();

  $cols.each(function () {
    //fix effects from bug with large min-height in frontend #266
    jQuery(this).css({ 'min-height': 'auto' });
    for (var key in sizes) {
      if (key == 'rows') continue;
      var $entity = jQuery(this).find(sizes[key].sel);
      if ($entity && $entity.length) {
        if (key == 'cells') {
          if (!sizes[key].height)
            sizes[key].height = [];
          var cellNum = 0;
          $entity.each(function () {
            var prevHeight = jQuery(this).outerHeight();

            jQuery(this).css('height', 'auto');
            var height = jQuery(this).outerHeight();

            if (!sizes[key].height[cellNum] || sizes[key].height[cellNum] < height) {
              sizes[key].height[cellNum] = height;
            }
            //jQuery(this).outerHeight( prevHeight );
            cellNum++;
          });
        } else {
          var prevHeight = $entity.outerHeight();

          $entity.css('height', 'auto');
          var height = $entity.outerHeight();

          if (!sizes[key].height || sizes[key].height < height) {
            sizes[key].height = height;
          }
          $entity.outerHeight(prevHeight);
        }
      }
    }
  });
  return sizes;
};
ptsBlock_price_table.prototype.getColumnWithInfo = function (strWidthAttr) {
  var trimAttr = strWidthAttr.trim();
  var number = trimAttr.match('\\d+');
  var isPerc = trimAttr.match('%');
  var isPx = trimAttr.match('\\d+');
  if (number === null || (isPerc === null && isPx === null)) {
    return null;
  }
  return new Object({
    'num': (number.length && number.length > 0 && !isNaN(parseInt(number[0]))) ? parseInt(number[0]) : null,
    'isPerc': isPerc === null ? false : true
  });
};
ptsBlock_price_table.prototype.setColsWidth = function (width, perc) {
  var thatObj = this;
  if (thatObj.getParam('is_horisontal_row_type') != '1') {
    if (this.getParam('dsbl_responsive') === '1') {
      var tableWidth = this._$.width(),
        fixedValueTableWidth = this._$.width(),
        $cols = this._getCols(true),
        notSettedColumnWidthArr = new Array();
      $cols.each(function () {
        var col1 = jQuery(this);
        if (col1.length > 0 && col1[0].style && col1[0].style.width) {
          var colWidthObj = thatObj.getColumnWithInfo(col1[0].style.width);
          if (colWidthObj && 'num' in colWidthObj && 'isPerc' in colWidthObj) {
            var calcColWidth = 0;
            if (colWidthObj.isPerc) {
              calcColWidth = fixedValueTableWidth * colWidthObj.num / 100;
            } else {
              calcColWidth = colWidthObj.num;
            }
            var colPdL = parseFloat(col1.css('padding-left')),
              colPdR = parseFloat(col1.css('padding-right')),
              colMgL = parseFloat(col1.css('margin-left')),
              colMgR = parseFloat(col1.css('margin-right')),
              colSumMarginPadding = 0;
            if (!isNaN(colPdL)) {
              colSumMarginPadding += colPdL;
            }
            if (!isNaN(colPdR)) {
              colSumMarginPadding += colPdR;
            }
            if (!isNaN(colMgL)) {
              colSumMarginPadding += colMgL;
            }
            if (!isNaN(colMgR)) {
              colSumMarginPadding += colMgR;
            }
            tableWidth -= calcColWidth;
            calcColWidth = Math.floor(calcColWidth - colSumMarginPadding);
            if (calcColWidth < 0) {
              calcColWidth = 0;
            }
            col1.width(calcColWidth);
          } else {
            notSettedColumnWidthArr[notSettedColumnWidthArr.length] = col1;
          }
        } else {
          notSettedColumnWidthArr[notSettedColumnWidthArr.length] = col1;
        }
      });
      if (tableWidth > 0 && notSettedColumnWidthArr.length > 0) {
        var calcWidthForNsCol = Math.round(tableWidth / notSettedColumnWidthArr.length);
        for (var oneNsColumn in notSettedColumnWidthArr) {
          // set width for Other columns
          notSettedColumnWidthArr[oneNsColumn].width(calcWidthForNsCol);
        }
      }
    } else {
      width = parseFloat(width);
      if (width) {
        if (!perc) {
          this.setParam('col_width', width);
        }
        var $cols = this._getCols(true);
        if (perc) {
          width += '%';
        } else {
          width += 'px';
        }
        $cols.css({
          'width': width
        });
      }
    }
  } else {
    this.columnChidrensWidthCalc();
  }
};
ptsBlock_price_table.prototype.columnChidrensWidthCalc = function () {
  if (this.getParam('is_horisontal_row_type') != '1') {
    return;
  }
  // only for HORIZONTAL ROW
  var $cols = this._getCols(true);
  $cols.each(function (ind, oneCol) {
    var currColumn = jQuery(oneCol)
      , emptyChilds = currColumn.find('.ptsTableElementContent').children(':not(:has(">div")):not(".ptsColBadge")')
      , level1Childs = currColumn.find('.ptsTableElementContent').children(':has(">div"):not(".ptsColBadge")')
      , level1ChildRows = currColumn.find('.ptsTableElementContent').children('.ptsRows')
      , level2ChildRows = level1ChildRows.children()
      , allChildCount = level1Childs.length
      , level2ChildCount = 1;

    if (level1ChildRows.length > 0 && level2ChildRows.length > 0) {
      allChildCount += level2ChildRows.length - 1;
      level2ChildCount = level2ChildRows.length;
    }
    //
    emptyChilds.css({
      'width': "0%",
      'margin': '0',
      'padding': '0',
    });
    var oneChildWidth = Math.floor(95 / allChildCount);

    level1Childs.css('width', oneChildWidth + '%');
    var widthInPixel = level1Childs.css('width');
    level1ChildRows.css('width', (level2ChildCount * oneChildWidth + 2) + '%');
    level2ChildRows.css('width', widthInPixel);
  });
}
ptsBlock_price_table.prototype.checkColWidthPerc = function () {
  if (this.getParam('calc_width') === 'table') {
    this.setColWidthPerc();
  }
};
ptsBlock_price_table.prototype.setColWidthPerc = function () {
  var $cols = this._getCols(parseInt(this.getParam('enb_desc_col')));
  this.setColsWidth(100 / $cols.length, true);
};
ptsBlock_price_table.prototype.setTableWidth = function (width, measure) {
  if (width && parseInt(width)) {
    width = parseInt(width);
    this.setParam('table_width', width);
  } else {
    width = this.getParam('table_width');
  }
  if (measure) {
    this.setParam('table_width_measure', measure);
  } else {
    measure = this.getParam('table_width_measure');
  }
  this._$.width(width + measure);

};
ptsBlock_price_table.prototype.setTableVertPadding = function (padding, measure) {
  if (padding && parseInt(padding)) {
    padding = parseInt(padding);
    this.setParam('vert_padding', padding);
  } else {
    padding = this.getParam('vert_padding');
  }
  if (measure) {
    this.setParam('vert_padding_measure', measure);
  } else {
    measure = this.getParam('vert_padding_measure');
  }
  this._$.find('.ptsCol').css('paddingBottom', padding + 'px');
};
ptsBlock_price_table.prototype.setCalcWidth = function (type) {
  if (type) {
    this.setParam('calc_width', type);
  } else {
    type = this.getParam('calc_width');
  }
  switch (type) {
    case 'table':
      this.setTableWidth();
      this.setColWidthPerc();
      break;
    case 'col':
      var enb_desc_col = this.getParam('enb_desc_col') != 0 ? true : false;
      this._$.width(this._getCols(enb_desc_col).length * this.getParam('col_width'));
      this.setColsWidth(this.getParam('col_width'));
      break;
  }
};
ptsBlock_price_table.prototype._fixResponsive = function () {
  if (this.getParam('is_horisontal_row_type') == '1') {
    var $parent = this._$.parents('.ptsTableFrontedShell:first').parent()
      , parentWidth = $parent.width();

    if (jQuery(window).width() < 600) {
      $parent.addClass('ptsResponcive');
    } else {
      $parent.removeClass('ptsResponcive');
    }
    return;
  }
  var $parent = this._$.parents('.ptsTableFrontedShell:first').parent()
    , parentWidth = $parent.width()
    , widthMeasure = this.getParam('table_width_measure')
    , calcWidth = this.getParam('calc_width')
    , includeDesc = parseInt(this.getParam('enb_desc_col'))
    , $cols = this._getCols(includeDesc)
    , actualTblWidth = this._$.width()
    , criticalColWidth = isNaN(parseInt(this.getParam('resp_min_col_width'))) ? 150 : parseInt(this.getParam('resp_min_col_width'))
    , dsblResponsive = parseInt(this.getParam('dsbl_responsive'));
  this._$.removeClass('ptsBlockMobile');
  switch (calcWidth) {
    case 'table':
      switch (widthMeasure) {
        case '%':
          var self = this
            , removeOtherDescCol = function () {
              if (!dsblResponsive
                && !_ptsIsEditMode()
                && self._$.find('.ptsTableDescCol').length > 1
                && includeDesc
              ) {
                var $descCols = self._$.find('.ptsTableDescCol')
                  , firstCol = false;

                $descCols.each(function () {
                  var $this = jQuery(this);
                  if (!firstCol) {
                    firstCol = true;
                    return;
                  }
                  $this.remove();
                });
              }
            };

          //removeOtherDescCol();

          $cols = this._getCols(includeDesc);
          // There can be several desc cols - exclude those invalid numbers
          var descColNum = $cols.filter('.ptsTableDescCol').length;

          var colsNum = $cols.length - (descColNum > 1 ? descColNum - 1 : 0)
            , currWidth = actualTblWidth / colsNum;

          if (currWidth <= criticalColWidth && !dsblResponsive) {
            $cols.css('width', '100%');

            if (!_ptsIsEditMode() && includeDesc) {
              var $descColumn = this._$.find('.ptsTableDescCol').first()
                , $columns = this._$.find('.ptsCol:not(.ptsTableDescCol)')
                , firstCol = false;
              removeOtherDescCol();

              var i = 0;
              $columns.each(function () {
                var $this = jQuery(this);

                if (!firstCol) {
                  firstCol = true;
                  return;
                }

                i++;
                var $descClone = $descColumn.clone();
                $descClone.find('.tooltipstered[data-title]').removeClass('tooltipstered').each(function () {
                  var el = jQuery(this);
                  el.attr('title', el.attr('data-title')).removeAttr('data-title');
                });
                $descClone.insertBefore($this);

              });
              this._initTooltipsForCells();

              this._isResponsiveDescInit = true;
              this._$.find('.ptsCol').css('width', '50%');
            }

            this._$.addClass('ptsBlockMobile');
            this.setParam('went_to_responsive', 1);
          } else {
            removeOtherDescCol();
            if (this.getParam('went_to_responsive')) {
              this.setColWidthPerc();
              this.setParam('went_to_responsive', 0);
            }
          }
          break;
        case 'px':
          if (actualTblWidth > parentWidth) {
            this.setParam('went_to_responsive', this.getParam('table_width'));
            this.setTableWidth(100, '%');	// make it 100% in this case
            this._fixResponsive();	// Repeat - to check case '%':
          } else if (this.getParam('went_to_responsive')) {
            this.setTableWidth(this.getParam('went_to_responsive'), 'px');	// Back to px width
            this.setParam('went_to_responsive', 0);
          }
          break;
      }
      break;
    case 'col':
      var colsNum = $cols.length
        , currWidth = parseFloat(this.getParam('col_width'));
      if (currWidth * colsNum >= parentWidth) {
        this.setParam('went_to_responsive', currWidth);
        this.setParam('table_width', 100);	// Set table width to 100%
        this.setParam('table_width_measure', '%');
        this.setCalcWidth('table');
        this._fixResponsive();	// Repeat - to check case '%':
      } else if (this.getParam('went_to_responsive')) {
        this.setCalcWidth('col');
        this.setParam('col_width', this.getParam('went_to_responsive'));	// Back to px width
        this.setParam('went_to_responsive', 0);
      }
      break;
  }
};
ptsBlock_price_table.prototype._refreshCellsHeight = function () {
  // Really important  - keep all this functionality as light as possible, as it can slow down whole builder work
  var $cols = this._getCols(true)
    , self = this
    , sizes = this.getMaxColsSizes(true);

  $cols.each(function () {
    for (var key in sizes) {

      var $entity = jQuery(this).find(sizes[key].sel);
      if (self.getParam('is_horisontal_row_type') == '1') {
        $entity.css({ 'height': 'auto' });
      } else {
        if (key == 'rows') {
          $entity.css({ 'height': 'auto' });
          continue;
        }
        if ($entity && $entity.length) {
          if (key == 'cells') {
            var cellNum = 0;
            $entity.each(function () {
              jQuery(this).css('height', sizes[key].height[cellNum]);
              cellNum++;
            });
          } else {
            $entity.outerHeight(sizes[key].height);

            if ($entity.outerHeight() != sizes[key].height) {
              $entity.css('height', sizes[key].height);
            }
          }
        }
      }
    }
  });
};


// ELEMENTS BASE JS

function ptsElementBase(jqueryHtml, block) {
  this._iterNum = 0;
  this._id = 'el_' + mtRand(1, 999999);
  this._animationSpeed = g_ptsAnimationSpeed;
  this._$ = jqueryHtml;
  this._block = block;
  if (typeof (this._menuOriginalId) === 'undefined') {
    this._menuOriginalId = '';
  }
  this._innerImgsCount = 0;
  this._innerImgsLoaded = 0;
  //this._$menu = null;
  this._menu = null;
  this._menuClbs = {};
  if (typeof (this._menuClass) === 'undefined') {
    this._menuClass = 'ptsElementMenu';
  }
  this._menuOnBottom = false;
  this._code = 'base';

  this._initedComplete = false;
  this._editArea = null;
  if (typeof (this._isMovable) === 'undefined') {
    this._isMovable = false;
  }
  this._moveHandler = null;
  this._sortInProgress = false;
  if (typeof (this._showMenuEvent) === 'undefined') {
    this._showMenuEvent = 'click';
  }
  if (typeof (this._changeable) === 'undefined') {
    this._changeable = false;
  }
  if (g_ptsEdit) {
    this._init();
    this._initMenuClbs();
    this._initMenu();

    var images = this._$.find('img');
    if (images && (this._innerImgsCount = images.length)) {
      this._innerImgsLoaded = 0;
      var self = this;
      images.load(function () {
        self._innerImgsLoaded++;
        if (self._$.find('img').length == self._innerImgsLoaded) {
          self._afterFullContentLoad();
        }
      });
    }
  }
  this._onlyFirstHtmlInit();
  this._initedComplete = true;
}
ptsElementBase.prototype.getId = function () {
  return this._id;
};
ptsElementBase.prototype.getBlock = function () {
  return this._block;
};
ptsElementBase.prototype._onlyFirstHtmlInit = function () {
  if (this._$ && !this._$.data('first-inited')) {
    this._$.data('first-inited', 1);
    return true;
  }
  return false;
};
ptsElementBase.prototype.setIterNum = function (num) {
  this._iterNum = num;
  this._$.data('iter-num', num);
};
ptsElementBase.prototype.getIterNum = function () {
  return this._iterNum;
};
ptsElementBase.prototype.$ = function () {
  return this._$;
};
ptsElementBase.prototype.getCode = function () {
  return this._code;
};
ptsElementBase.prototype._setCode = function (code) {
  this._code = code;
};
ptsElementBase.prototype._init = function () {
  this._beforeInit();
};
ptsElementBase.prototype._beforeInit = function () {

};
ptsElementBase.prototype.destroy = function () {

};
ptsElementBase.prototype.get = function (opt) {
  return jQuery('<div/>').html(this._$.attr('data-' + opt)).text();	// not .data() - as it should be saved even after page reload, .data() will not create element attribute
};
ptsElementBase.prototype.set = function (opt, val) {
  this._$.attr('data-' + opt, jQuery('<div/>').text(val).html());	// not .data() - as it should be saved even after page reload, .data() will not create element attribute
};
ptsElementBase.prototype._getEditArea = function () {
  if (!this._editArea || this._$.attr('data-reset') == '1') {
    this._editArea = this._$.children('.ptsElArea');
    if (!this._editArea.length) {
      this._editArea = this._$.find('.ptsInputShell');
      this._$.removeAttr('data-reset');
    }
  }
  return this._editArea;
};
ptsElementBase.prototype._getOverlay = function () {
  return this._$.find('.ptsElOverlay');
};
/**
 * Standart button item
 */
function ptsElement_btn(jqueryHtml, block) {
  if (typeof (this._menuOriginalId) === 'undefined') {
    this._menuOriginalId = 'ptsElMenuBtnExl';
  }
  this._menuClass = 'ptsElementMenu_btn';
  this._haveAdditionBgEl = null;
  this._changeable = true;
  this.includePostLinks = true;
  ptsElement_btn.superclass.constructor.apply(this, arguments);
}
extendPts(ptsElement_btn, ptsElementBase);
ptsElement_btn.prototype._onlyFirstHtmlInit = function () {
  if (ptsElement_btn.superclass._onlyFirstHtmlInit.apply(this, arguments)) {
    if (this.get('customhover-clb')) {
      var clbName = this.get('customhover-clb');
      if (typeof (this[clbName]) === 'function') {
        var self = this;
        this._getEditArea().hover(function () {
          self[clbName](true, this);
        }, function () {
          self[clbName](false, this);
        });
      }
    }
  }
};
ptsElement_btn.prototype._hoverChangeFontColor = function (hover, element) {
  if (hover) {
    jQuery(element)
      .data('original-color', this._getEditArea().css('color'))
      .css('color', jQuery(element).parents('.ptsEl:first').attr('data-bgcolor'));	// Ugly, but only one way to get this value in dynamic way for now
  } else {
    jQuery(element)
      .css('color', jQuery(element).data('original-color'));
  }
};
ptsElement_btn.prototype._hoverChangeBgColor = function (hover, element) {
  var parentElement = jQuery(element).parents('.ptsEl:first');	// Actual element html
  if (hover) {
    parentElement
      .data('original-color', parentElement.css('background-color'))
      .css('background-color', parentElement.attr('data-bgcolor'));	// Ugly, but only one way to get this value in dynamic way for now
  } else {
    parentElement
      .css('background-color', parentElement.data('original-color'));
  }
};
ptsElement_btn.prototype._hoverBorderColor = function (hover, element) {
  //var parentElement = jQuery(element).parents('.ptsEl:first');	// Actual element html
  if (hover) {
    jQuery(element)
      .data('original-color', jQuery(element).css('border-color'))
      .css('border-color', jQuery(element).parents('.ptsEl:first').attr('data-bgcolor'));	// Ugly, but only one way to get this value in dynamic way for now
  } else {
    jQuery(element)
      .css('border-color', jQuery(element).data('original-color'));
  }
};
/**
 * Table column element
 */
function ptsElement_table_col(jqueryHtml, block) {
  if (typeof (this._menuOriginalId) === 'undefined') {
    this._menuOriginalId = 'ptsElMenuTableColExl';
  }
  if (typeof (this._menuClass) === 'undefined') {
    this._menuClass = 'ptsElementMenu_table_col';
  }
  if (typeof (this._isMovable) === 'undefined') {
    this._isMovable = true;
  }
  this._showMenuEvent = 'click';
  this._colNum = 0;
  ptsElement_table_col.superclass.constructor.apply(this, arguments);
  /*if(parseInt(this.get('enb-schedule'))) {
    console.log(this.getIterNum());
  }*/
}
extendPts(ptsElement_table_col, ptsElementBase);
ptsElement_table_col.prototype.setIterNum = function () {
  ptsElement_table_col.superclass.setIterNum.apply(this, arguments);
  if (!g_ptsEdit && typeof (ptsScheduleCheck) !== 'undefined') {
    ptsScheduleCheck(this);
  }
};
/**
 * Table description column element
 */
function ptsElement_table_col_desc(jqueryHtml, block) {
  this._isMovable = false;
  ptsElement_table_col_desc.superclass.constructor.apply(this, arguments);
  //this.refreshHeight();
  //var self = this;
  /*this.getBlock().$().bind('ptsBlockContentChanged', function(){
    self.refreshHeight();
  });*/
}
extendPts(ptsElement_table_col_desc, ptsElement_table_col);
/*ptsElement_table_col_desc.prototype.refreshHeight = function() {
  var sizes = this.getBlock().getMaxColsSizes();
  for(var key in sizes) {
    var $entity = this._$.find(sizes[ key ].sel);
    if($entity && $entity.length) {
      if(key == 'cells' &&  sizes[ key ].height) {
        var cellNum = 0;
        $entity.each(function(){
          if(typeof(sizes[ key ].height[ cellNum ]) !== 'undefined') {
            jQuery(this).css('height', sizes[ key ].height[ cellNum ]);
          }
          cellNum++;
        });
      } else {
        $entity.css('height', sizes[ key ].height);
      }
    }
  }
};*/

/**
 * Text element
 */
function ptsElement_table_cell_txt(jqueryHtml, block) {
  if (block.getParam('responsive_text')) {
    jqueryHtml.find('span, p').responsiveText({ minFontSize: 14 });
  }
  this.includePostLinks = true;
  ptsElement_table_cell_txt.superclass.constructor.apply(this, arguments);
}
extendPts(ptsElement_table_cell_txt, ptsElementBase);


// RESPONSIVE TEXT

(function ($) {

  $.fn.responsiveText = function (options) {

    // Setup options
    var settings = $.extend({
      'minFontSize': Number.NEGATIVE_INFINITY,
      'maxFontSize': Number.POSITIVE_INFINITY
    }, options);

    return this.each(function () {

      // Store the object
      var $this = $(this),
        text = $this.get(0);

      if (!text) return;

      $this.data('original-font-size', parseFloat(
        window.getComputedStyle(text).fontSize
      ), 10);

      // Resizer() resizes items based on the object width divided by the compressor * 10
      var resizer = function () {
        var ratio = null,
          originalWidth = window.screen.availWidth,
          currentWidth = window.innerWidth,
          size = $this.data('original-font-size');

        if (originalWidth == currentWidth || !size) return;

        if (currentWidth != originalWidth)
          ratio = originalWidth / currentWidth;

        if (currentWidth > originalWidth)
          size *= ratio;
        else
          size /= ratio;

        size = Math.max(
          Math.min(
            size,
            settings.maxFontSize
          ),
          settings.minFontSize
        );

        $this.css('font-size', size + 'px');
      };

      resizer();

      // Call on resize. Opera debounces their resize by default.
      $(window).on('resize.responsiveText orientationchange.responsiveText', resizer);

    });

  };

})(jQuery);
// TABLES BASE
var g_ptsEdit = false
  , g_ptsBlockFabric = null
  , g_ptsHoverAnim = 300	// Table hover animation lenght, ms - hardcoded for now
  , g_ptsHoverMargin = 20;	// Table hover margin displace, px - hardcoded for now

//array with unique_id template that without enabled options header row
//overlap toggle elements
var g_ptsUniqueIdArray = ['wnOq3v2K', 'sa0DHT4h', 'B1gpCofW', 'ptmJ4YnA', 'r0OL4vCy'];

jQuery(document).ready(function () {
  _ptsInitFabric();
  if (typeof (ptsTables) !== 'undefined' && ptsTables && ptsTables.length) {
    for (var i = 0; i < ptsTables.length; i++) {
      g_ptsBlockFabric.addFromHtml(ptsTables[i], jQuery('#' + ptsTables[i].view_id));

      jQuery('body').trigger('set_default_position');
      //for fix horizontal element size bugs frontend.pro.tables.js
      if (ptsTables[i].unique_id === "7m6k5X0i") {
        jQuery('#' + ptsTables[i].view_id).attr('data-unique_id', ptsTables[i].unique_id);
      }

      // fix overlap toggle elements
      if (g_ptsUniqueIdArray.indexOf(ptsTables[i].unique_id) != -1) {
        jQuery('#' + ptsTables[i].view_id).attr('data-unique_id', ptsTables[i].unique_id);
        //if undefined that means options is enabled by default.

        var enableHeader = '1';
        if (typeof ptsTables[i].params.enb_head_row !== 'undefined') {
          enableHeader = typeof (ptsTables[i].params.enb_head_row.val) !== "undefined" ? '0' : '1';
        }
        jQuery(document.body).trigger("overlay_toggle", [ptsTables[i].unique_id, enableHeader]);
      }
      //jQuery(".ptsTableFrontedShell .tooltipstered").removeAttr("title");
    }
    jQuery(window).bind('load', function () {
      if (typeof (g_ptsAllowAddUndo) !== 'undefined') {
        setTimeout(function () {
          g_ptsAllowAddUndo = true;
          _ptsAddUndoBuffer();
        }, 200);
      }
    });
  }
});
jQuery(window).on("load", function () {
  setTimeout(function () { jQuery('body').trigger('resize'); }, 500);
});
//in case images are loading dynamically
jQuery('.ptsEl.ptsCol[data-el="table_col"] img').on('load', function () {
  jQuery('body').trigger('resize');
});
function _ptsInitFabric() {
  g_ptsBlockFabric = new ptsBlockFabric();
}
function ptsGetFabric() {
  return g_ptsBlockFabric;
}
function _ptsIsEditMode() {
  return (typeof (g_ptsEditMode) !== 'undefined' && g_ptsEditMode);
}
//TABLES BASE END
//MODAL
(function ($) {
  'use strict';

  $.fn.sModal = function (options) {
    var self = this,
      settings = $.extend({
        width: 640,
        height: 480,
        buttons: [],
      }, options),
      $modalOverlay,
      $modalContainer,
      $closeModalButton,
      $modalContent,
      $modalButtons,
      modalOverlayStyle = {
        position: 'fixed',
        top: 0,
        left: 0,
        background: 'rgba(0,0,0,.75)',
        width: '100%',
        height: '100%',
        'z-index': '100000',
        display: 'none',
        'overflow-y': 'auto',
      },
      modalContainerStyle = {
        width: settings.width,
        position: 'absolute',
        top: '50%',
        left: '50%',
        'max-width': 'calc(100% - 1.5em)',
        'margin-right': '-50%',
        'margin-bottom': '20px',
        transform: 'translate(-50%, -50%)',
        background: '#fff',
        padding: '1em',
      },
      modalContentStyle = {
        height: 'calc(100% - 3.6em)',
        'overflow-y': 'auto',
        'overflow-x': 'hidden',
        padding: '1em',
      },
      closeButtonStyle = {
        position: 'absolute',
        right: '10px',
        top: '10px',
        'font-size': '35px',
        color: '#fff',
        cursor: 'pointer',
      },
      modalButtonsStyle = {
        position: 'relative',
        width: '100%',
        'text-align': 'right',
        'margin-top': '1em',
      };


    function closeModal() {
      self.trigger('close.before');
      if (jQuery('.sModal:visible').length < 2) {
        jQuery('body').css('overflow', 'auto');
      }
      $modalOverlay.fadeOut();
      self.trigger('close.after');
    }

    function openModal() {
      jQuery('body').css('overflow', 'hidden');
      $modalOverlay.show(0, function () {
        resizeModal();
        $modalOverlay.hide().fadeIn();
      });

      if (parseInt(jQuery('.sc-modal-container').css('top')) > jQuery(window).height()) {
        var offset = jQuery(window).height() / 2 + 40;
        jQuery('.sc-modal-container').css('top', offset);
      }

    }

    function resizeModal() {
      var offset = '50%';
      if ($modalContainer.height() > jQuery(window).height()) {
        offset = $modalContainer.height() / 2 + 40;
      }
      $modalContainer.css('top', offset);
    }

    function createInstance($modalTemplate) {

      $modalOverlay = jQuery('<div class="sc-modal-overlay" tabindex="0">').css(modalOverlayStyle);

      $modalContainer = jQuery('<div class="sc-modal-container">').css(modalContainerStyle);

      $closeModalButton = jQuery('<div class="sc-modal-close-button">&times;</div>').css(closeButtonStyle);
      $closeModalButton.appendTo($modalOverlay);

      $modalContent = jQuery('<div class="sc-modal-content">').css(modalContentStyle);
      $modalContent.appendTo($modalContainer);

      $modalTemplate.appendTo($modalContent).show();

      $modalContainer.appendTo($modalOverlay);

      $modalOverlay.appendTo('body');
      $modalOverlay.add($closeModalButton).on('click', function (event) {
        if (jQuery(this).is(jQuery(event.target))) {
          closeModal();
        }
      });

      jQuery(document).on('keyup', function (event) {
        if (event.which == 27 && $modalOverlay.is(':visible')) {
          closeModal();
        }
      });

      var resizeTimer;

      jQuery(window).on('resize', function (event) {
        clearTimeout(resizeTimer);
        resizeTimer = setTimeout(function () {
          resizeModal();
        }, 250);
      });

      if (settings.buttons.length > 0) {
        $modalButtons = jQuery('<div class="sc-modal-action-buttons">').css(modalButtonsStyle);

        for (var i = 0; i < settings.buttons.length; i++) {
          jQuery('<button>').attr('class', settings.buttons[i].class || null)
            .html(settings.buttons[i].content || null)
            .on('click', $.proxy(settings.buttons[i].event, $modalTemplate))
            .appendTo($modalButtons);
        }

        self.$buttons = $modalButtons;

        $modalButtons.appendTo($modalContainer);
      }

    }

    createInstance(this);

    $.extend(this, {
      open: function () {
        this.trigger('open.before');
        openModal();
        this.trigger('open.after');
        return this;
      },
      close: function () {
        this.trigger('close.before');
        closeModal();
        this.trigger('close.after');
        return this;
      }
    });

    return this;
  };

})(jQuery);
//MODAL