<?php

/**
 * Render block
 */
class Flo_Flex_Builder_Render_Block {
  protected $attributes = null;
  protected $elements = [];
  protected $mobile_elements = [];
  protected $z_index_maps = [];
  protected $maps = [];
  protected $groups_sizes = [];
  protected $global_options = [];
  protected $block_id = null;
  protected $is_gutenberg = null;
  public $b = "flex-block";
  public $block_source = null;
  public $colors = [];
  public $block = null;
  public $groupsSizes = [];

  // For YOAST or other server-calls, force serverside rendering for desktop
  // elements. Ignore mobile elements
  // When rendering elements, only_desktop is populated, and forced to be printed server-side
  public $force_render = false;


  public function __construct($attributes, $force_server_render = false) {

    $this->parse_attributes($attributes);
    // $this->block_id = mt_rand(1, 999999);
    $this->force_render = $force_server_render;

    if (!$this->block) return false;

    $data = $this->block;
    if (isset($data['elements'])) $this->elements = $data['elements'];
    if (isset($data['mobile_elements'])) $this->mobile_elements = $force_server_render ? [] : $data['mobile_elements'];
    if (isset($data['groupsSizes'])) $this->groupsSizes = $data['groupsSizes'];
    if (isset($data['maps'])) $this->maps = $data['maps'];
    if (isset($data['zIndexMaps'])) $this->zIndexMaps = $data['zIndexMaps'];
  }

  public function parse_attributes($attributes) {

    $this->block_id = mt_rand(1, 999);
    $this->attributes = $attributes;
    $this->block_source = false;

    // Gutenberg scenario
    if (is_array($attributes) && isset($attributes['data'])) {
      $this->block_source = 'gut';

      // Flex theme with ACF scenario
    } else if ($attributes && sizeof($attributes)) {
      $this->block_source = 'acf_theme';

      // Old flothemes.com scenario
    } else {
      if (!function_exists('get_sub_field')) return false;
      $this->block_source = 'flothemes_site';
    }

    //PROPS
    $builder_obj = $this->get_primary_prop("flo_flex_builder_obj");
    if (!$builder_obj) return false;

    $this->set_main_object($builder_obj);
    $this->set_colors();
  }

  /**
   * Get data according to source
   */
  function get_primary_prop($option_name, $default = null, $data_type = null) {
    $gutenberg_mapping = [
      'flex__hide-mobile' => 'hideOnMobile',
      'flex__hide-desktop' => 'hideOnDesktop',
      'flo_flex_builder_obj' => 'data',
      'flex__block-custom-class' => 'className'
    ];

    if ($this->block_source === 'gut' && isset($gutenberg_mapping[$option_name])) $option_name = $gutenberg_mapping[$option_name];

    if ($this->block_source === 'flothemes_site') {
      $found = get_sub_field($option_name);
    } else {
      $found = flo_data($this->attributes, $option_name, $default);
    }

    if (!is_null($data_type)) {
      switch ($data_type) {
        case 'bool':
          $found = boolval($found);
          break;
        case 'integer':
          $found = (int)$found;
          break;
        default:
          break;
      }
    }

    return $found;
  }

  function set_colors() {
    $colors = null;
    $data = $this->block;
    if (
      isset($data["globalOptions"]["themeColors"]) &&
      sizeof($data["globalOptions"]["themeColors"])
    ) {
      $colors = $data["globalOptions"]["themeColors"];
    } else {
      $stylekitData = Flex_Builder_Data::getFlexStylekitStyles(get_the_ID());

      if ($stylekitData) {
        $colors = $stylekitData['colors']['values'];
      }
    }

    $this->colors = $colors;
  }

  function set_main_object($builder_obj) {
    $this->block = is_array($builder_obj) ? $builder_obj : json_decode($builder_obj, true);
    $this->block_id = $this->get_prop(['blockID'], rand());
  }

  public function get_prop($arr, $default) {
    return get_deep_value($this->block, $arr, $default);
  }

  public function get_attribute($arr, $default) {
    return get_deep_value($this->attributes, $arr, $default);
  }

  public function get_custom_classes() {
    return $this->get_primary_prop("flex__block-custom-class", '');
  }

  /**
   * Get HTML classes string for the block
   */
  function get_classes() {

    $custom_block_class = $this->get_custom_classes();
    $desktopFullscreenClass = $this->get_prop(['globalOptions', 'globalBlockHeightIsFullscreen'], false) ? $this->b . '--desktop-fullscreen' : '';
    $mobileFullscreenClass = $this->get_prop(['globalOptions', 'globalMobileBlockHeightIsFullscreen'], false) ? $this->b . '--mobile-fullscreen' : '';
    $isPopupClass = $this->get_attribute(['isPopup'], false) ? $this->b . '--is-popup' : '';
    $useAsStickyClass = $this->get_attribute(['useAsSticky'], false) ? $this->b . '--use-as-sticky' : '';

    $classes = remove_new_lines('
      alignfull
      ' . $this->b . '
      ' . $this->b . '--' . $this->block_id . '
      ' . $custom_block_class . '
      ' . $desktopFullscreenClass . '
      ' . $mobileFullscreenClass . '
      ' . $isPopupClass . '
      ' . $useAsStickyClass . '
    ');

    return $classes;
  }

  /**
   * @return array
   */
  function get_block_styles() {

    $hide_on_desktop = $this->get_primary_prop("flex__hide-desktop", false, 'bool');
    $hide_on_mobile = $this->get_primary_prop("flex__hide-mobile", false, 'bool');

    $decoded_data = $this->block;

    $desktop_font_size = $this->get_prop(['globalOptions', 'htmlFontSize'], 1.25);
    $desktopFontSizePx = $desktop_font_size * (1280 / 100);
    $mobile_font_size = $desktopFontSizePx / (375 / 100);

    // We need these in any of the element PHP to calculate sizes for srcsets
    global $flex_desktop_font_size;
    global $flex_mobile_font_size;
    $flex_desktop_font_size = (float) $desktop_font_size;
    $flex_mobile_font_size = (float) $mobile_font_size;

    // Mobile height & patch
    $wasChangedAfterUpdate = isset($decoded_data['globalOptions']['heightFixFlag']) && isset($decoded_data['globalOptions']['heightFixFlag']) === true;
    if ($wasChangedAfterUpdate || defined('FLEX_MOBILE_HEIGHT_FLAG')) {
      $mob_height_em = str_replace('rem', 'em', $this->get_prop(['globalOptions', 'globalMobileBlockHeightRem'], 100));
    } else {
      $mob_height_em = $this->get_prop(['globalOptions', 'globalMobileBlockHeight'], 10) / $desktopFontSizePx . "em";
    }

    // Desktop height
    if (isset($decoded_data['globalOptions']['globalBlockHeightRem']) && strlen($decoded_data['globalOptions']['globalBlockHeightRem'])) {
      $blockHeightVal = str_replace('rem', 'em', $decoded_data['globalOptions']['globalBlockHeightRem']);
    } else {
      $blockHeightVal = '46.875em';
    }

    // Colors
    $globalBlockBgColor = $this->get_prop(['globalOptions', 'globalBlockBgColor'], '');
    $desktopBg = parseColor($globalBlockBgColor, $this->colors);

    $globalMobileBlockBgColor = $this->get_prop(['globalOptions', 'globalMobileBlockBgColor'], $globalBlockBgColor);
    $mobBg = parseColor($globalMobileBlockBgColor, $this->colors);

    // Margins
    $margins = $this->get_primary_prop("flex_margins");

    $topMargin = FLEX_GUTENBERG ? $this->get_attribute(['topMargin'], 0) : get_deep_value($margins, ['flex_top_margin_desktop'], 0);
    $bottomMargin = FLEX_GUTENBERG ? $this->get_attribute(['bottomMargin'], 0) : get_deep_value($margins, ['flex_bottom_margin_desktop'], 0);

    $topMarginMob = FLEX_GUTENBERG ? $this->get_attribute(['mobileTopMargin'], 0) : get_deep_value($margins, ['flex_top_margin_mobile'], 0);
    $bottomMarginMob = FLEX_GUTENBERG ? $this->get_attribute(['mobileBottomMargin'], 0) : get_deep_value($margins, ['flex_bottom_margin_mobile'], 0);

    $desktop_styles = remove_new_lines("
      --html-font-size: " . $desktop_font_size . "vw;
      --height:" . $blockHeightVal . ";
      --bg-color: " . getStyleKitColor($desktopBg) . ";
      --margin-top: " . flex_em_calc($topMargin, $desktop_font_size, "desktop") . "em;
      --margin-bottom: " . flex_em_calc($bottomMargin, $desktop_font_size, "desktop") . "em;
    ");
    if ($hide_on_desktop) $desktop_styles .= 'display: none;';

    $mobile_styles = remove_new_lines("
      --html-font-size: " . $mobile_font_size . "vw;
      --height: " . $mob_height_em . ";
      --bg-color: " . getStyleKitColor($mobBg) . ";
      --margin-top: " . flex_em_calc($topMarginMob, $mobile_font_size, "mobile") . "em;
      --margin-bottom: " . flex_em_calc($bottomMarginMob, $mobile_font_size, "mobile") . "em;
    ");
    if ($hide_on_mobile) $mobile_styles .= 'display: none;';

    return ['desktop' => $desktop_styles, 'mobile' => $mobile_styles];
  }

  public function render() {

    if (is_admin() && !$this->force_render) return '';

    if (!sizeof($this->elements) && !sizeof($this->mobile_elements) && !$this->force_render) return '';

    $elements_obj = $this->render_elements();

    $should_hide_on_desktop = $elements_obj['statistics']['desktop_elements'] === 0;
    $should_hide_on_mobile = $elements_obj['statistics']['mobile_elements'] === 0;

    $block_html_id = 'flex-' . $this->block_id;
    if (FLEX_GUTENBERG) {
      $block_html_id = $this->get_attribute(['blockAnchor'], $block_html_id);
    } else {
      $block_html_id = $this->get_primary_prop("flex__block-custom-id", $block_html_id);
    }

    $isPopup = $this->get_attribute(['isPopup'], false);
    $popupSettingsDataAttribute = '';
    if ($isPopup) {
      $popupSettings = $this->get_prop(['globalOptions', 'popupSettings'], false) ? $this->get_prop(['globalOptions', 'popupSettings'], false) : null;
      if ($popupSettings) {
        $popupSettingsDataAttribute = 'data-popup-settings="' . htmlspecialchars(json_encode($popupSettings)) . '"';
      }
    }

    return '
    <div
      class="' . $this->get_classes() . '"
      data-block-id="' . $this->block_id . '"' . ' ' . '
      id="' . strtolower($block_html_id) . '"
      ' . $popupSettingsDataAttribute . '
    >
    ' . $this->render_style_tag($should_hide_on_desktop, $should_hide_on_mobile) . '
    <div class="' . $this->b . '__main-container server-rendered">' .
      $elements_obj['markup'] .
      $this->render_groups() .
      '</div></div>';
  }

  /**
   * Render block style tab
   * TODO: add this to the header
   */
  public function render_style_tag($hide_desktop = false, $hide_mobile = false) {
    $styles = $this->get_block_styles();
    if ( $this->get_custom_classes() && $this->get_custom_classes() !== '' ) {
      $custom_classes = '.' . implode('.', explode(' ', $this->get_custom_classes()));
    } else {
      $custom_classes = '';
    }
    $selector = '.' . $this->b . '--' . $this->block_id . '' . $custom_classes;
    return remove_new_lines('
    <style>
        @media only screen and (min-width: 768px) {
          ' . $selector . ' {
            ' . ($hide_desktop ? 'display: none;' : $styles['desktop']) . '
          }
        }
        @media only screen and (max-width: 767px) {
          ' . $selector . ' {
            ' . ($hide_mobile ? 'display: none;' : $styles['mobile']) . '
          }
        }
    </style>
    ');
  }

  public function render_elements() {
    $elements = new Flo_Flex_Builder_Render_Element([
      'block' => $this->block,
      'block_id' => $this->block_id,
      'attributes' => $this->attributes,
      'maps' => $this->maps,
      'colors' => $this->colors,
      'elements' => $this->elements,
      'mobile_elements' => $this->mobile_elements,
      'b' => $this->b,
      'force_render' => $this->force_render
    ]);
    return $elements->render_elements();
  }

  public function render_groups() {
    // When is forced server-rendering, ignore groups.
    if ($this->force_render) return '';

    $groups = new Flo_Flex_Builder_Render_Groups([
      'block' => $this->block,
      'block_id' => $this->block_id,
      'maps' => $this->maps,
      'groupsSizes' => $this->groupsSizes,
      'elements' => $this->elements,
      'mobile_elements' => $this->mobile_elements,
      'b' => $this->b,
      'force_render' => $this->force_render
    ]);
    return $groups->render();
  }
}
