<?php

require_once(__DIR__ . "/element-styles.php");
require_once(__DIR__ . "/render-element.php");
require_once(__DIR__ . "/render-from-map.php");
require_once(__DIR__ . "/minify-html.php");

// RENDER HELPER FUNCTIONS
if (!function_exists("renderElements")) {

	function sort_elements_by_position($elements_arr) {
		if (!is_array($elements_arr)) return array();
		$arr_sorted = array();
		foreach ($elements_arr as $el_key => $el_value) {
			$arr_sorted[$el_key] = $el_value['data']['posY'];
		}

		asort($arr_sorted);

		$sorted_elements = array();
		foreach ($arr_sorted as $el_key => $order) {
			$sorted_elements[$el_key] = $elements_arr[$el_key];
		}

		return $sorted_elements;
	}

	// used when no map is available (old plugin version, when groups were not available yet)
	function renderElements($data, $viewport = "desktop") {

		$flexMarkup = "";

		if (
			isset($data["maps"]) &&
			isset($data["maps"][$viewport]) &&
			isset($data["groupsSizes"]) &&
			isset($data["groupsSizes"][$viewport])
		) {
			$flexMarkup = flexRenderFromMap($data, $viewport);
		} else {
			// get flat map if available (for z-indexes)

			// REORDER ELEMENTS
			if ($data && !empty($data['elements']) && !get_deep_value($data, ["globalOptions", "htmlInLayerOrder"], false)) {
				$data['elements'] = sort_elements_by_position($data['elements']);
				$data['mobile_elements'] = sort_elements_by_position($data['mobile_elements']);
			}

			$flatMap = isset($data["zIndexMaps"]) ? $data["zIndexMaps"]["desktop"] : null;

			// get color names and send to renderer
			$colors = null;
			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'];
				}
			}

			// get elements obj
			if ($viewport === "desktop") {
				$elements = isset($data["elements"]) ? $data["elements"] : [];
			} else {
				$elements = isset($data["mobile_elements"]) ? $data["mobile_elements"] : [];
			}


			if (isset($elements) && sizeof($elements)) {
				foreach ($elements as $element) {
					$flexMarkup .= flexRenderEl($element, $data['blockID'], $flatMap, $colors, $viewport, null);
				}
			}
		}

		// return minify_html($flexMarkup);
		return $flexMarkup;
	}
}

/**
 * Returns a flat array with element IDs as they sit in map
 * @param array $children[]
 * @return array elementIDs
 */
// function get_element_ids_from_map_in_order($children) {
// 	$element_ids = [];

// 	foreach ($children as $child) {
// 		if ($child['type'] === 'gr') {
// 			$element_ids = array_merge($element_ids, get_element_ids_from_map_in_order($child['children']));
// 		} else {
// 			$element_ids[] = $child['id'];
// 		}
// 	}
// 	return $element_ids;
// };

if (!function_exists("renderHTMLElements")) {
	function renderHTMLElements($data) {
		$markup = '';
		$elements = array_keys(array_merge($data['elements'], $data['mobile_elements']));

		// get color names and send to renderer
		$colors = null;
		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'];
			}
		}

		$elements_props = array();
		foreach ($elements as $key) {
			$elements_props[$key] = isset($data['elements'][$key]) ? $data['elements'][$key] : $data['mobile_elements'][$key];
			$elements_props[$key]['top_position'] = floatval(get_deep_value($elements_props[$key], ['data', 'posY'], 1));
		}

		// Reordering by position of appearance. Desktop view priority. 
		// In case option is set, reorder by map
		if (get_deep_value($data, ["globalOptions", "htmlInLayerOrder"], false)) {
			$element_ids = 	get_element_ids_from_map_in_order($data['maps']['desktop']['children']);
			$element_ids_mobile = 	get_element_ids_from_map_in_order($data['maps']['mobile']['children']);
			foreach ($elements_props as $element) {
				$desktop_index = array_search($element['id'], $element_ids);
				$elements_props[$element['id']]['top_position'] = $desktop_index !== false ? $desktop_index : array_search($element['id'], $element_ids_mobile);
			}
		}
		usort($elements_props, 'flex_sort_by_position');

		foreach ($elements_props as $element) {
			$blockID = isset($data['blockID']) ? $data['blockID'] : uniqid('blockID--');
			$markup .= flexRenderHTMLEl($element, $blockID, $colors, $data);
		}

		return $markup;
	}
}

/**
 * Used for server-side group rendering
 */
function get_group_styling($data) {
	return remove_new_lines('
		top: ' . flexParseNr($data['min_y']) . 'em;
		left: ' . flexParseNr($data['min_x']) . 'em;
		width: ' . flexParseNr($data['w']) . 'em;
		height: ' . flexParseNr($data['h']) . 'em;
		z-index: -1;
	');
}

/**
 * Creates an array of groups maped to their ID, value is an array of group 
 * content IDs (element IDs or other group IDs, if nested)
 */
function walk_in_element_map($children, $group_id = null) {
	global $flex_groups_flat_map;
	global $flex_groups_props;

	if ($group_id && !isset($flex_groups_flat_map[$group_id])) $flex_groups_flat_map[$group_id] = [];
	foreach ($children as $child) {
		if ($group_id) $flex_groups_flat_map[$group_id][] = $child['id'];
		if ($child['type'] === 'gr') {
			walk_in_element_map($child['children'], $child['id']);
			$flex_groups_props[$child['id']] = array_merge($child, ['children' => false]);
		}
	}
}

/**
 * delete this if we remain with one-level groups
 */
function flexRenderGroups($data, $children, $device, $group_sizes) {
	$childrenMarkup = "";

	foreach ($children as $node) {
		if ($node["type"] === "gr") {

			$gr_id = $node['id'];
			global $flex_groups_flat_map;
			global $flex_groups_props;

			$childrenMarkup .= '
			<div class="flex-group flex-group--' . $gr_id . ' server-rendered" 
					data-device="' . $device . '" 
					data-groups_and_elements="' . implode(",", $flex_groups_flat_map[$gr_id]) . '"
					data-all_elements="' . get_elements_from_group($flex_groups_flat_map[$gr_id], $flex_groups_flat_map) . '"
					data-play-hover-animations="' . getGroupPropBool($flex_groups_props[$gr_id], "playHoverAnimations") . '"
					data-play-click-animations="' . getGroupPropBool($flex_groups_props[$gr_id], "playClickAnimations") . '"
					data-trigger-links="' . getGroupPropBool($flex_groups_props[$gr_id], "triggerLinks", "false") . '"
					data-clip-content="' . getGroupPropBool($flex_groups_props[$gr_id], "clipContent", "false") . '"

					style="' . get_group_styling($group_sizes[$gr_id]) . '">';

			$childrenMarkup = remove_new_lines($childrenMarkup);
			$childrenMarkup .= flexRenderGroups($data, $node["children"], $device, $group_sizes);
			$childrenMarkup .= "</div>";
		}
	}
	return $childrenMarkup;
}

/**
 * Nested groups
 */
function renderElGroups($data) {
	$markup = '';

	$group_sizes = $data['groupsSizes'];
	$map = $data['maps'];

	global $flex_groups_flat_map;
	global $flex_groups_props;
	$flex_groups_flat_map = [];
	$flex_groups_props = [];

	// Create list of groups and their children
	foreach ($map as $device => $groups) {
		walk_in_element_map($groups['children']);
	}

	$markup = flexRenderGroups($data, $map['desktop']['children'], 'desktop', $group_sizes['desktop']);

	return $markup;
}


/**
 * FALLBACK with one level for groups
 */
if (!function_exists("renderElGroups")) {
	function renderElGroups($data) {
		$markup = '';

		$group_sizes = $data['groupsSizes'];
		$map = $data['maps'];

		global $flex_groups_flat_map;
		global $flex_groups_props;
		$flex_groups_flat_map = [];
		$flex_groups_props = [];

		// Create list of groups and their children
		foreach ($map as $device => $groups) {
			walk_in_element_map($groups['children']);
		}

		foreach ($group_sizes as $device => $groups) {
			foreach ($groups as $gr_id => $gr) {
				$markup .= '
					<div class="flex-group flex-group--' . $gr_id . ' server-rendered" 
					    data-device="' . $device . '" 
							data-groups_and_elements="' . implode(",", $flex_groups_flat_map[$gr_id]) . '"
							data-all_elements="' . get_elements_from_group($flex_groups_flat_map[$gr_id], $flex_groups_flat_map) . '"
							data-play-hover-animations="' . getGroupPropBool($flex_groups_props[$gr_id], "playHoverAnimations") . '"
							data-play-click-animations="' . getGroupPropBool($flex_groups_props[$gr_id], "playClickAnimations") . '"
							data-trigger-links="' . getGroupPropBool($flex_groups_props[$gr_id], "triggerLinks", "false") . '"
							data-clip-content="' . getGroupPropBool($flex_groups_props[$gr_id], "clipContent", "false") . '"
							style="' . get_group_styling($gr) . '">
					</div>';
			}
		}
		$flex_groups_flat_map = [];

		return $markup;
	}
}

/**
 * Returns all elements from a specific group. Also nested elements
 */
function get_elements_from_group($children, $all_groups) {
	$groups_and_els = '';

	foreach ($children as $child) {
		if (strpos($child, 'gr') !== false) {
			$groups_and_els .= get_elements_from_group($all_groups[$child], $all_groups);
		} else {
			$groups_and_els .= ' ' . $child;
		}
	}
	return $groups_and_els;
}
