From 22696a0fc69934f054fe6f6f46e289eb90b0e97c Mon Sep 17 00:00:00 2001
From: Alejandro Gallardo Escobar <alejandro.gallardo@artica.es>
Date: Tue, 4 Sep 2018 17:23:42 +0200
Subject: [PATCH] Added new modes to calculate the status of the linked visual
 maps

---
 pandora_console/extras/mr/20.sql              |  11 +
 .../visual_console_builder.editor.js          | 109 ++++-
 .../ajax/visual_console_builder.ajax.php      |  68 ++-
 .../include/functions_visual_map.php          | 421 ++++++++++--------
 .../include/functions_visual_map_editor.php   |  73 ++-
 pandora_console/pandoradb.sql                 |   6 +
 6 files changed, 481 insertions(+), 207 deletions(-)
 create mode 100644 pandora_console/extras/mr/20.sql

diff --git a/pandora_console/extras/mr/20.sql b/pandora_console/extras/mr/20.sql
new file mode 100644
index 0000000000..b17abe229f
--- /dev/null
+++ b/pandora_console/extras/mr/20.sql
@@ -0,0 +1,11 @@
+START TRANSACTION;
+
+-- Changes for the 'service like status' feature (Carrefour)
+ALTER TABLE `tlayout_data` ADD COLUMN `linked_layout_status_type` ENUM ('default', 'weight', 'service') DEFAULT 'default';
+ALTER TABLE `tlayout_data` ADD COLUMN `linked_layout_status_as_service_warning` FLOAT(20, 3) NOT NULL default 0;
+ALTER TABLE `tlayout_data` ADD COLUMN `linked_layout_status_as_service_critical` FLOAT(20, 3) NOT NULL default 0;
+ALTER TABLE `tlayout_template_data` ADD COLUMN `linked_layout_status_type` ENUM ('default', 'weight', 'service') DEFAULT 'default';
+ALTER TABLE `tlayout_template_data` ADD COLUMN `linked_layout_status_as_service_warning` FLOAT(20, 3) NOT NULL default 0;
+ALTER TABLE `tlayout_template_data` ADD COLUMN `linked_layout_status_as_service_critical` FLOAT(20, 3) NOT NULL default 0;
+
+COMMIT;
\ No newline at end of file
diff --git a/pandora_console/godmode/reporting/visual_console_builder.editor.js b/pandora_console/godmode/reporting/visual_console_builder.editor.js
index eb0e9b19b1..9137957de5 100755
--- a/pandora_console/godmode/reporting/visual_console_builder.editor.js
+++ b/pandora_console/godmode/reporting/visual_console_builder.editor.js
@@ -829,8 +829,11 @@ function readFields() {
 	values['bars_graph_type'] = $("select[name=bars_graph_type]").val();
 	values['parent'] = $("select[name=parent]").val();
 	values['map_linked'] = $("select[name=map_linked]").val();
+	values['linked_map_status_calculation_type'] = $("select[name=linked_map_status_calculation_type]").val();
+	values['map_linked_weight'] = $("input[name=map_linked_weight]").val();
+	values['linked_map_status_service_critical'] = $("input[name=linked_map_status_service_critical]").val();
+	values['linked_map_status_service_warning'] = $("input[name=linked_map_status_service_warning]").val();
 	values['element_group'] = $("select[name=element_group]").val();
-	values['map_linked_weight'] = $("select[name=map_linked_weight]").val();
 	values['width_percentile'] = $("input[name=width_percentile]").val();
 	values['bars_graph_height'] = $("input[name=bars_graph_height]").val();
 	values['max_percentile'] = parseInt($("input[name=max_percentile]").val());
@@ -1537,10 +1540,16 @@ function loadFieldsFromDB(item) {
 					$("input[name=height]").val(val);
 				if (key == 'parent_item')
 					$("select[name=parent]").val(val);
+				if (key == 'linked_layout_status_type')
+					$("select[name=linked_map_status_calculation_type]").val(val).change();
 				if (key == 'id_layout_linked')
-					$("select[name=map_linked]").val(val);
+					$("select[name=map_linked]").val(val).change();
 				if (key == 'id_layout_linked_weight')
-					$("select[name=map_linked_weight]").val(val);
+					$("input[name=map_linked_weight]").val(val);
+				if (key == 'linked_layout_status_as_service_critical')
+					$("input[name=linked_map_status_service_critical]").val(val);
+				if (key == 'linked_layout_status_as_service_warning')
+					$("input[name=linked_map_status_service_warning]").val(val);
 				if (key == 'element_group')
 					$("select[name=element_group]").val(val);
 				if (key == 'width_percentile')
@@ -1838,14 +1847,16 @@ function hiddenFields(item) {
 	$("#parent_row." + item).css('display', '');
 
 	$("#map_linked_row").css('display', 'none');
+	$("#linked_map_status_calculation_row").css('display', 'none');
+	$("#map_linked_weight").css('display', 'none');
+	$("#linked_map_status_service_critical_row").css('display', 'none');
+	$("#linked_map_status_service_warning_row").css('display', 'none');
+
 	$("#map_linked_row." + item).css('display', '');
 
 	$("#element_group_row").css('display', 'none');
 	$("#element_group_row." + item).css('display', '');
 
-	$("#map_linked_weight").css('display', 'none');
-	$("#map_linked_weight." + item).css('display', '');
-
 	$("#module_graph_size_row").css('display', 'none');
 	$("#module_graph_size_row." + item).css('display', '');
 
@@ -1925,9 +1936,12 @@ function cleanFields(item) {
 	$("input[name=width]").val(0);
 	$("input[name=height]").val(0);
 	$("select[name=parent]").val('');
-	$("select[name=map_linked]").val('');
+	$("select[name=linked_map_status_calculation_type]").val('default').change();
+	$("select[name=map_linked]").val('').change();
+	$("input[name=map_linked_weight]").val('');
+	$("input[name=linked_map_status_service_critical]").val('');
+	$("input[name=linked_map_status_service_warning]").val('');
 	$("select[name=element_group]").val('');
-	$("select[name=map_linked_weight]").val('');
 	$("input[name=width_module_graph]").val(300);
 	$("input[name=height_module_graph]").val(180);
 	$("input[name='width_box']").val(300);
@@ -5141,4 +5155,81 @@ function multiDragMouse(eventDrag){
 			}
 		});
 	});
-}
\ No newline at end of file
+}
+
+function linkedMapStatusCalculationTypeChanged ($linkedMapStatusCalcRow, value) {
+	if ($linkedMapStatusCalcRow.length === 0 || !validRowOnSelectedItem($linkedMapStatusCalcRow)) return;
+
+	switch (value) {
+		case "weight":
+			// Show weight input
+			$linkedMapStatusCalcRow
+				.siblings("#map_linked_weight")
+					.show()
+				.siblings("#linked_map_status_service_critical_row")
+					.hide()
+				.siblings("#linked_map_status_service_warning_row")
+					.hide();
+			break;
+		case "service":
+			// Show critical and warning values
+			$linkedMapStatusCalcRow
+				.siblings("#map_linked_weight")
+					.hide()
+				.siblings("#linked_map_status_service_critical_row")
+					.show()
+				.siblings("#linked_map_status_service_warning_row")
+					.show();
+			break;
+		default:
+			// Hide inputs
+			$linkedMapStatusCalcRow
+				.siblings("#map_linked_weight")
+					.hide()
+				.siblings("#linked_map_status_service_critical_row")
+					.hide()
+				.siblings("#linked_map_status_service_warning_row")
+					.hide();
+			break;
+	}
+}
+
+function linkedMapChanged ($linkedMapRow, value) {
+	if ($linkedMapRow.length === 0 || !validRowOnSelectedItem($linkedMapRow)) return;
+
+	if (value === 0) {
+		$linkedMapRow
+			.siblings("#linked_map_status_calculation_row")
+				.hide()
+			.siblings("#map_linked_weight")
+				.hide()
+			.siblings("#linked_map_status_service_critical_row")
+				.hide()
+			.siblings("#linked_map_status_service_warning_row")
+				.hide();
+	} else {
+		var $linkedMapStatusCalcRow = $linkedMapRow.siblings("#linked_map_status_calculation_row");
+
+		if (!validRowOnSelectedItem($linkedMapStatusCalcRow)) return;
+
+		var calcType = $linkedMapStatusCalcRow.find("select").val();
+		$linkedMapStatusCalcRow.show();
+		linkedMapStatusCalculationTypeChanged($linkedMapStatusCalcRow, calcType);
+	}
+}
+
+function onLinkedMapChange (event) {
+	var $linkedMapRow = $(event.target).parent().parent();
+	var value = Number.parseInt(event.target.value);
+	linkedMapChanged($linkedMapRow, value);
+}
+
+function onLinkedMapStatusCalculationTypeChange (event) {
+	var $linkedMapStatusCalcRow = $(event.target).parent().parent();
+	var value = event.target.value || "default";
+	linkedMapStatusCalculationTypeChanged($linkedMapStatusCalcRow, value);
+}
+
+function validRowOnSelectedItem ($element) {
+	return $element.hasClass(selectedItem);
+}
diff --git a/pandora_console/include/ajax/visual_console_builder.ajax.php b/pandora_console/include/ajax/visual_console_builder.ajax.php
index fab370763d..d529721b93 100755
--- a/pandora_console/include/ajax/visual_console_builder.ajax.php
+++ b/pandora_console/include/ajax/visual_console_builder.ajax.php
@@ -100,7 +100,21 @@ $width = get_parameter('width', null);
 $height = get_parameter('height', null);
 $parent = get_parameter('parent', null);
 $map_linked = get_parameter('map_linked', null);
+$linked_map_status_calculation_type = get_parameter('linked_map_status_calculation_type', 'default');
+
 $map_linked_weight = get_parameter('map_linked_weight', null);
+if ($map_linked_weight !== null) {
+	$map_linked_weight = (int) $map_linked_weight;
+}
+$linked_map_status_service_critical = get_parameter('linked_map_status_service_critical', null);
+if ($linked_map_status_service_critical !== null) {
+	$linked_map_status_service_critical = (float) $linked_map_status_service_critical;
+}
+$linked_map_status_service_warning = get_parameter('linked_map_status_service_warning', null);
+if ($linked_map_status_service_warning !== null) {
+	$linked_map_status_service_warning = (float) $linked_map_status_service_warning;
+}
+
 $element_group = get_parameter('element_group', null);
 $width_percentile = get_parameter('width_percentile', 0);
 $bars_graph_height = get_parameter('bars_graph_height', null);
@@ -408,7 +422,7 @@ switch ($action) {
 		
 		// Linked to other layout ?? - Only if not module defined
 		if ($layoutData['id_layout_linked'] != 0) {
-			$status = visual_map_get_layout_status ($layoutData['id_layout_linked'], $layoutData['id_layout_linked_weight']);
+			$status = visual_map_get_layout_status($layoutData['id_layout_linked'], $layoutData);
 		
 		// Single object
 		}
@@ -619,12 +633,27 @@ switch ($action) {
 				if ($map_linked !== null) {
 					$values['id_layout_linked'] = $map_linked;
 				}
-				if ($element_group !== null) {
-					$values['element_group'] = $element_group;
+				if ($linked_map_status_calculation_type !== null) {
+					$values['linked_layout_status_type'] = $linked_map_status_calculation_type;
 				}
 				if ($map_linked_weight !== null) {
+					if ($map_linked_weight > 100) $map_linked_weight = 100;
+					if ($map_linked_weight < 0) $map_linked_weight = 0;
 					$values['id_layout_linked_weight'] = $map_linked_weight;
 				}
+				if ($linked_map_status_service_critical !== null) {
+					if ($linked_map_status_service_critical > 100) $linked_map_status_service_critical = 100;
+					if ($linked_map_status_service_critical < 0) $linked_map_status_service_critical = 0;
+					$values['linked_layout_status_as_service_critical'] = $linked_map_status_service_critical;
+				}
+				if ($linked_map_status_service_warning !== null) {
+					if ($linked_map_status_service_warning > 100) $linked_map_status_service_warning = 100;
+					if ($linked_map_status_service_warning < 0) $linked_map_status_service_warning = 0;
+					$values['linked_layout_status_as_service_warning'] = $linked_map_status_service_warning;
+				}
+				if ($element_group !== null) {
+					$values['element_group'] = $element_group;
+				}
 				switch ($type) {
 					// -- line_item ------------------------------------
 					case 'handler_start':
@@ -944,6 +973,16 @@ switch ($action) {
 				if ($elementFields['id_metaconsole'] != 0) {
 					metaconsole_restore_db();
 				}
+
+				if (isset($elementFields["id_layout_linked_weight"])) {
+					$elementFields["id_layout_linked_weight"] = (int) $elementFields["id_layout_linked_weight"];
+				}
+				if (isset($elementFields["linked_layout_status_as_service_critical"])) {
+					$elementFields["linked_layout_status_as_service_critical"] = (float) $elementFields["linked_layout_status_as_service_critical"];
+				}
+				if (isset($elementFields["linked_layout_status_as_service_warning"])) {
+					$elementFields["linked_layout_status_as_service_warning"] = (float) $elementFields["linked_layout_status_as_service_warning"];
+				}
 				
 				switch ($type) {
 					case 'auto_sla_graph':
@@ -1096,8 +1135,27 @@ switch ($action) {
 		}
 		$values['id_agente_modulo'] = $id_module;
 		$values['id_layout_linked'] = $map_linked;
+		$values['linked_layout_status_type'] = $linked_map_status_calculation_type;
+
+		if ($map_linked_weight !== null) {
+			if ($map_linked_weight > 100) $map_linked_weight = 100;
+			if ($map_linked_weight < 0) $map_linked_weight = 0;
+			$values['id_layout_linked_weight'] = $map_linked_weight;
+		}
+
+		if ($linked_map_status_service_critical !== null) {
+			if ($linked_map_status_service_critical > 100) $linked_map_status_service_critical = 100;
+			if ($linked_map_status_service_critical < 0) $linked_map_status_service_critical = 0;
+			$values['linked_layout_status_as_service_critical'] = $linked_map_status_service_critical;
+		}
+
+		if ($linked_map_status_service_warning !== null) {
+			if ($linked_map_status_service_warning > 100) $linked_map_status_service_warning = 100;
+			if ($linked_map_status_service_warning < 0) $linked_map_status_service_warning = 0;
+			$values['linked_layout_status_as_service_warning'] = $linked_map_status_service_warning;
+		}
+
 		$values['element_group'] = $element_group;
-		$values['id_layout_linked_weight'] = $map_linked_weight;
 		$values['parent_item'] = $parent;
 		$values['enable_link'] = $enable_link;
 		$values['show_on_top'] = $show_on_top;
@@ -1361,7 +1419,7 @@ if ($get_element_status) {
 		array('id' => $id_element));
 	
 	$res = visual_map_get_status_element($layoutData);
-	
+	html_debug($res, true);
 	echo $res;
 	
 	return;
diff --git a/pandora_console/include/functions_visual_map.php b/pandora_console/include/functions_visual_map.php
index 701a6a1694..42a4eac3fc 100755
--- a/pandora_console/include/functions_visual_map.php
+++ b/pandora_console/include/functions_visual_map.php
@@ -32,6 +32,7 @@ require_once ($config['homedir'].'/include/functions_modules.php');
 require_once ($config['homedir'].'/include/functions_users.php');
 require_once ($config['homedir'].'/include/functions.php');
 require_once ($config['homedir'].'/include/graphs/functions_d3.php');
+enterprise_include_once('include/functions_visual_map.php');
 
 function visual_map_print_item_toolbox($idDiv, $text, $float) {
 	if ($float == 'left') {
@@ -3143,7 +3144,7 @@ function visual_map_get_status_element($layoutData) {
 		else {
 			$calculate_weight = false;
 		}
-		$status = visual_map_get_layout_status ($layoutData['id_layout_linked'], 0, 0, $calculate_weight);
+		$status = visual_map_get_layout_status($layoutData['id_layout_linked'], $layoutData);
 
 		if ($layoutData['id_layout_linked_weight'] > 0) {
 			$elements_to_compare = db_get_all_rows_sql("SELECT id, element_group FROM tlayout_data WHERE type = 0 AND id_layout = " . $layoutData['id_layout_linked']);
@@ -3164,8 +3165,8 @@ function visual_map_get_status_element($layoutData) {
 			else {
 				$status = VISUAL_MAP_STATUS_NORMAL;
 				if (count($elements_to_compare) == 0) {
-       		$status = VISUAL_MAP_STATUS_UNKNOWN;
-        }
+					$status = VISUAL_MAP_STATUS_UNKNOWN;
+				}
 			}
 		}
 	}
@@ -3656,6 +3657,45 @@ function visual_map_get_user_layouts ($id_user = 0, $only_names = false, $filter
 	return $retval;
 }
 
+function visual_map_translate_agent_status ($agent_status) {
+	switch ($agent_status) {
+		case AGENT_STATUS_NORMAL:
+		default:
+			return VISUAL_MAP_STATUS_NORMAL;
+		case AGENT_STATUS_CRITICAL:
+			return VISUAL_MAP_STATUS_CRITICAL_BAD;
+		case AGENT_STATUS_WARNING:
+			return VISUAL_MAP_STATUS_WARNING;
+		case AGENT_STATUS_NOT_INIT:
+		case AGENT_STATUS_UNKNOWN:
+		case -1:
+			return VISUAL_MAP_STATUS_UNKNOWN;
+		case AGENT_STATUS_ALERT_FIRED:
+			return VISUAL_MAP_STATUS_CRITICAL_ALERT;
+	}
+}
+
+function visual_map_translate_module_status ($module_status) {
+	switch ($agent_status) {
+		case AGENT_MODULE_STATUS_NORMAL:
+		case AGENT_MODULE_STATUS_NORMAL_ALERT:
+		default:
+			return VISUAL_MAP_STATUS_NORMAL;
+		case AGENT_MODULE_STATUS_CRITICAL_BAD:
+			return VISUAL_MAP_STATUS_CRITICAL_BAD;
+		case AGENT_MODULE_STATUS_WARNING:
+			return VISUAL_MAP_STATUS_WARNING;
+		case AGENT_MODULE_STATUS_UNKNOWN:
+		case AGENT_MODULE_STATUS_NOT_INIT:
+		case AGENT_MODULE_STATUS_NO_DATA:
+		case -1:
+			return VISUAL_MAP_STATUS_UNKNOWN;
+		case AGENT_MODULE_STATUS_CRITICAL_ALERT:
+			return VISUAL_MAP_STATUS_CRITICAL_ALERT;
+		case AGENT_MODULE_STATUS_WARNING_ALERT:
+			return VISUAL_MAP_STATUS_WARNING_ALERT;
+	}
+}
 
 /** 
  * Get the status of a layout.
@@ -3665,205 +3705,232 @@ function visual_map_get_user_layouts ($id_user = 0, $only_names = false, $filter
  * are OK. If any of them is down, then result is down (0)
  * 
  * @param int Id of the layout
+ * @param array Information about the status calculation of the item
  * @param int Depth (for recursion control)
  * 
  * @return bool The status of the given layout. True if it's OK, false if not.
  */
-function visual_map_get_layout_status ($id_layout = 0, $depth = 0, $elements_in_critical = 0, $calculate_weight = false) {
+function visual_map_get_layout_status ($layout_id, $status_data = array(), $depth = 0) {
 	global $config;
 
-	$temp_status = VISUAL_MAP_STATUS_NORMAL;
-	$temp_total = VISUAL_MAP_STATUS_NORMAL;
-	$depth++; // For recursion depth checking
+	// TODO: Implement this limit into the setup
+	if ($depth > 10) return VISUAL_MAP_STATUS_UNKNOWN;
 	
-	// TODO: Implement this limit as a configurable item in setup
-	if ($depth > 10) {
-		return VISUAL_MAP_STATUS_UNKNOWN; // No status data if we need to exit by a excesive recursion
-	}
+	$layout_items = db_get_all_rows_filter("tlayout_data", array("id_layout" => $layout_id));
+	if ($layout_items === false) return VISUAL_MAP_STATUS_UNKNOWN;
 	
-	$id_layout = (int) $id_layout;
-	
-	$result = db_get_all_rows_filter ('tlayout_data',
-		array ('id_layout' => $id_layout),
-		array (
-			'id_agente_modulo',
-			'id_group',
-			'parent_item',
-			'id_layout_linked',
-			'id_agent',
-			'type',
-			'id_layout_linked_weight',
-			'id',
-			'id_layout',
-			'element_group',
-			'id_metaconsole'));
-	if ($result === false)
-		return VISUAL_MAP_STATUS_NORMAL;
-		
-	$stcount = 0;
-	$stcount_u = 0;
-	foreach ($result as $data) {
-		if ($data['type'] == 0) {
-			$stcount++;
-			if ($data["id_layout_linked"] == 0 && $data["id_agente_modulo"] == 0 && $data["id_agent"] == 0) {
-				$stcount_u++;
-			}
+	// Check for valid items to retrieve the status for
+	$valid_layout_items = array();
+	foreach ($layout_items as $layout_item_data) {
+		if (
+			// Group items
+			(
+				$layout_item_data['type'] == GROUP_ITEM &&
+				!empty($layout_item_data["id_group"]) &&
+				// ACL check
+				check_acl($config["id_user"], $layout_item_data["id_group"], "VR") &&
+				check_acl($config["id_user"], $layout_item_data["element_group"], "VR")
+			) ||
+			// Rest of items
+			(
+				(
+					// At least one of this ids is required
+					!empty($layout_item_data["id_layout_linked"]) ||
+					!empty($layout_item_data["id_agente_modulo"]) ||
+					!empty($layout_item_data["id_agent"])
+				) && (
+					// Weight and service types for status calculation require STATIC_GRAPH items
+					(
+						$status_data["linked_layout_status_type"] !== "weight" &&
+						$status_data["linked_layout_status_type"] !== "service"
+					) || (
+						$layout_item_data['type'] == STATIC_GRAPH && (
+							$status_data["linked_layout_status_type"] === "weight" ||
+							$status_data["linked_layout_status_type"] === "service"
+						)
+					)
+				) &&
+				// ACL check
+				check_acl($config["id_user"], $layout_item_data["element_group"], "VR")
+			)
+		) {
+			$valid_layout_items[] = $layout_item_data;
 		}
 	}
-	if ($stcount == 0 || $stcount_u == $stcount) {
-		return VISUAL_MAP_STATUS_UNKNOWN;
+	
+	if (empty($valid_layout_items)) return VISUAL_MAP_STATUS_UNKNOWN;
+
+	// Sort by node id to reduce the number of connections
+	if (is_metaconsole()) {
+		sort_by_column($valid_layout_items, "id_metaconsole");
 	}
 
-	foreach ($result as $data) {
-		$layout_group = $data['element_group'];
-		if (!check_acl ($config['id_user'], $layout_group, "VR")) {
-			continue;
+	$num_elements_by_status = array();
+	$meta_connected_to = null;
+
+	foreach ($valid_layout_items as $layout_item_data) {
+		if (is_metaconsole()) {
+			if (empty($layout_item_data["id_metaconsole"]) && $meta_connected_to) {
+				metaconsole_restore_db(); // Restore db connection
+				$meta_connected_to = null;
+			}
+			else if (
+				!empty($layout_item_data["id_metaconsole"]) && (
+					empty($meta_connected_to) ||
+					$meta_connected_to != $layout_item_data["id_metaconsole"]
+				)
+			) {
+				if (!empty($meta_connected_to)) metaconsole_restore_db(); // Restore db connection
+				$connection = metaconsole_get_connection_by_id($layout_item_data["id_metaconsole"]);
+				if (metaconsole_load_external_db($connection) != NOERR) continue;
+				$meta_connected_to = $layout_item_data["id_metaconsole"];
+			}
 		}
-		
-		switch ($data['type']) {
-			case GROUP_ITEM:
-				if ($data["id_layout_linked"] == 0) {
-					$group_status = groups_get_status($data['id_group']);
-					switch ($group_status) {
-						case AGENT_STATUS_ALERT_FIRED:
-							$status = VISUAL_MAP_STATUS_CRITICAL_ALERT;
-							break;
-						case AGENT_STATUS_CRITICAL:
-							$status = VISUAL_MAP_STATUS_CRITICAL_BAD;
-							break;
-						case AGENT_STATUS_WARNING:
-							$status = VISUAL_MAP_STATUS_WARNING;
-							break;
-						case AGENT_STATUS_UNKNOWN:
-							$status = VISUAL_MAP_STATUS_UNKNOWN;
-							break;
-						case AGENT_STATUS_NORMAL:
-						default:
-							$status = VISUAL_MAP_STATUS_NORMAL;
-							break;
+
+		$status = VISUAL_MAP_STATUS_NORMAL;
+
+		$ent_element_status = enterprise_hook("enterprise_visual_map_get_status_element", array($layoutData));
+		if ($ent_element_status === ENTERPRISE_NOT_HOOK) {
+			$ent_element_status = false;
+		}
+
+		// Enterprise element
+		if ($ent_element_status !== false) {
+			$status = $ent_element_status;
+		}
+		// Linked layout
+		else if (!empty($layout_item_data["id_layout_linked"])) {
+			$status = visual_map_get_layout_status($layout_item_data["id_layout_linked"], $layout_item_data, $depth + 1);
+		}
+		// Other
+		else {
+			switch ($layout_item_data["type"]) {
+				case STATIC_GRAPH:
+				case PERCENTILE_BAR:
+				case PERCENTILE_BUBBLE:
+				case CIRCULAR_PROGRESS_BAR:
+				case CIRCULAR_INTERIOR_PROGRESS_BAR:
+					// Module
+					if (!empty($layout_item_data["id_agente_modulo"])) {
+						$module_status = modules_get_agentmodule_status($layout_item_data["id_agente_modulo"]);
+						$status = visual_map_translate_module_status($module_status);
 					}
-				}
-				else {
-					$status = visual_map_get_layout_status(
-						$data["id_layout_linked"], $depth);
-				}
-				break;
-			default:
-				if (($data["id_layout_linked"] == 0 &&
-					$data["id_agente_modulo"] == 0 &&
-					$data["id_agent"] == 0) ||
-					$data['type'] != 0){
-						continue;
-					}
-				
-				// Other Layout (Recursive!)
-				if (($data["id_layout_linked"] != 0) && ($data["id_agente_modulo"] == 0)) {
-					if ($data['id_layout_linked_weight'] > 0) {
-						$calculate_weight_c = true;
+					// Agent
+					else if (!empty($layout_item_data["id_agent"])) {
+						$agent_status = agents_get_status($layout_item_data["id_agent"], true);
+						$status = visual_map_translate_agent_status($agent_status);
 					}
+					// Unknown
 					else {
-						$calculate_weight_c = false;
+						$status = VISUAL_MAP_STATUS_UNKNOWN;
 					}
-					$status = visual_map_get_layout_status($data["id_layout_linked"], $depth, 0, $calculate_weight_c);
-
-					$elements_in_child = db_get_all_rows_sql("SELECT id, element_group FROM tlayout_data WHERE type = 0 AND id_layout = " . $data['id_layout_linked']);
-					$layout_group = $data['element_group'];
-					
-					$childs_group_acl = array();
-					foreach ($elements_in_child as $c) {
-						if (check_acl ($config['id_user'], $c['element_group'], "VR")) {
-							$childs_group_acl[] = $c['id'];
-						}
-					}
-					$elements_in_child = $childs_group_acl;
-					
-					if ($calculate_weight_c) {
-						$aux_weight = ($status['elements_in_critical'] / count($elements_in_child)) * 100;
-						
-						if ($aux_weight >= $data['id_layout_linked_weight']) {
-							$status = $status['temp_total'];
-						}
-						else {
-							$status = VISUAL_MAP_STATUS_NORMAL;
-							if (count($elements_in_child) == 0) {
-								$status = VISUAL_MAP_STATUS_UNKNOWN;
-							}
-						}
-					}
-				}
-				// Module
-				elseif ($data["id_agente_modulo"] != 0) {
-					//Metaconsole db connection
-					if ($data['id_metaconsole'] != 0) {
-						$connection = db_get_row_filter ('tmetaconsole_setup',
-							array('id' => $data['id_metaconsole']));
-						if (metaconsole_load_external_db($connection) != NOERR) {
-							continue;
-						}
-					}
-
-					$status = modules_get_agentmodule_status($data["id_agente_modulo"]);
-					if ($status == 4){
-						$status = 3;
-					}
-
-					//Restore db connection
-					if ($data['id_metaconsole'] != 0) {
-						metaconsole_restore_db();
-					}
-				}
-				// Agent
-				else {
-					//--------------------------------------------------
-					// ADDED NO CHECK ACL FOR AVOID CHECK TAGS THAT
-					// MAKE VERY SLOW THE VISUALMAPS WITH ACL TAGS
-					//--------------------------------------------------
-					//Metaconsole db connection
-					if ($data['id_metaconsole'] != 0) {
-						$connection = db_get_row_filter ('tmetaconsole_setup',
-							array('id' => $data['id_metaconsole']));
-						if (metaconsole_load_external_db($connection) != NOERR) {
-							continue;
-						}
-					}
-					$status = agents_get_status($data["id_agent"], true);
-
-					//Restore db connection
-					if ($data['id_metaconsole'] != 0) {
-						metaconsole_restore_db();
-					}
-				}
-				break;
-		}
-		
-		if ($calculate_weight) {
-			if ($status == VISUAL_MAP_STATUS_CRITICAL_BAD || $status == VISUAL_MAP_STATUS_WARNING) {
-				$elements_in_critical++;
+					break;
+				case GROUP_ITEM:
+					$group_status = groups_get_status($layout_item_data['id_group']);
+					$status = visual_map_translate_agent_status($group_status);
+					break;
+				default:
+					// If it's a graph, a progress bar or a data tag, ALWAYS report status OK
+					// (=0) to avoid confussions here.
+					$status = VISUAL_MAP_STATUS_NORMAL;
+					break;
 			}
 		}
+
+		// When the status calculation type is 'default', only one critical element is required to
+		// set the layout status as critical, so we can return the critical status right now.
+		if (
+			$status_data["linked_layout_status_type"] === "default" && (
+				$status == VISUAL_MAP_STATUS_CRITICAL_BAD ||
+				$status == VISUAL_MAP_STATUS_CRITICAL_ALERT
+			)
+		) {
+			if (is_metaconsole() && $meta_connected_to) {
+				metaconsole_restore_db(); // Restore db connection
+			}
+			return $status;
+		}
 		else {
-			if ($status == VISUAL_MAP_STATUS_CRITICAL_BAD) {
+			if (!isset($num_elements_by_status[$status])) $num_elements_by_status[$status] = 0;
+			$num_elements_by_status[$status]++;
+		}
+	}
+
+	if (is_metaconsole() && $meta_connected_to) {
+		metaconsole_restore_db(); // Restore db connection
+	}
+
+	// Status calculation
+	switch ($status_data["linked_layout_status_type"]) {
+		default:
+		case "default":
+			$num_items_critical_alert = $num_elements_by_status[VISUAL_MAP_STATUS_CRITICAL_ALERT];
+			$num_items_critical = $num_elements_by_status[VISUAL_MAP_STATUS_CRITICAL_BAD];
+			$num_items_warning = $num_elements_by_status[VISUAL_MAP_STATUS_WARNING];
+			$num_items_unknown = $num_elements_by_status[VISUAL_MAP_STATUS_UNKNOWN];
+			
+			if ($num_items_critical_alert > 0) {
+				return VISUAL_MAP_STATUS_CRITICAL_ALERT;
+			}
+			else if ($num_items_critical > 0) {
 				return VISUAL_MAP_STATUS_CRITICAL_BAD;
 			}
-		
-		}
-		if ($calculate_weight) {
-			if ($status == VISUAL_MAP_STATUS_CRITICAL_BAD) {
-				$temp_total = VISUAL_MAP_STATUS_CRITICAL_BAD;
+			else if ($num_items_warning > 0) {
+				return VISUAL_MAP_STATUS_WARNING;
 			}
-			else if ($status == VISUAL_MAP_STATUS_WARNING && $temp_total != VISUAL_MAP_STATUS_CRITICAL_BAD) {
-				$temp_total = VISUAL_MAP_STATUS_WARNING;
+			else if ($num_items_unknown > 0) {
+				return VISUAL_MAP_STATUS_UNKNOWN;
 			}
-		}
-		else if ($status > $temp_total) {
-			$temp_total = $status;
-		}
+			else {
+				return VISUAL_MAP_STATUS_NORMAL;
+			}
+			break;
+		case "weight":
+			$weight = $status_data["id_layout_linked_weight"];
+			$num_items = count($valid_layout_items);
+			$num_items_critical_alert = $num_elements_by_status[VISUAL_MAP_STATUS_CRITICAL_ALERT];
+			$num_items_critical = $num_elements_by_status[VISUAL_MAP_STATUS_CRITICAL_BAD];
+			$num_items_warning = $num_elements_by_status[VISUAL_MAP_STATUS_WARNING];
+			$num_items_unknown = $num_elements_by_status[VISUAL_MAP_STATUS_UNKNOWN];
+			
+			if (
+				$num_items_critical > 0 &&
+				((($num_items_critical_alert + $num_items_critical) * 100) / $num_items) >= $weight
+			) {
+				return $num_items_critical_alert > 0 ? VISUAL_MAP_STATUS_CRITICAL_ALERT : VISUAL_MAP_STATUS_CRITICAL_BAD;
+			}
+			else if (
+				$num_items_warning > 0 &&
+				(($num_items_warning * 100) / $num_items) >= $weight
+			) {
+				return VISUAL_MAP_STATUS_WARNING;
+			}
+			else if (
+				$num_items_unknown > 0 &&
+				(($num_items_unknown * 100) / $num_items) >= $weight
+			) {
+				return VISUAL_MAP_STATUS_UNKNOWN;
+			}
+			else {
+				return VISUAL_MAP_STATUS_NORMAL;
+			}
+			break;
+		case "service":
+			$num_items_critical = $num_elements_by_status[VISUAL_MAP_STATUS_CRITICAL_BAD]
+				+ $num_elements_by_status[VISUAL_MAP_STATUS_CRITICAL_ALERT];
+			$critical_percentage = ($num_items_critical * 100) / count($valid_layout_items);
+
+			if ($critical_percentage >= $status_data["linked_layout_status_as_service_critical"]) {
+				return VISUAL_MAP_STATUS_CRITICAL_BAD;
+			}
+			else if ($critical_percentage >= $status_data["linked_layout_status_as_service_warning"]) {
+				return VISUAL_MAP_STATUS_WARNING;
+			}
+			else {
+				return VISUAL_MAP_STATUS_NORMAL;
+			}
+			break;
 	}
-	if ($calculate_weight) {
-		return array('elements_in_critical' => $elements_in_critical, 'temp_total' => $temp_total);
-	}
-	
-	return $temp_total;
 }
 
 /**
diff --git a/pandora_console/include/functions_visual_map_editor.php b/pandora_console/include/functions_visual_map_editor.php
index 83c394ab44..5b8cc1c522 100755
--- a/pandora_console/include/functions_visual_map_editor.php
+++ b/pandora_console/include/functions_visual_map_editor.php
@@ -702,26 +702,64 @@ function visual_map_editor_print_item_palette($visualConsole_id, $background) {
 				'<td align="left">' . html_print_select_from_sql (
 				'SELECT id, name
 				FROM tlayout
-				WHERE id != ' . $visualConsole_id, 'map_linked', '', '', 'None', '0', true) .
+				WHERE id != ' . (int) $visualConsole_id, 'map_linked', 0, 'onLinkedMapChange(event)', __('None'), 0, true) .
 				'</td>';
 
+			$status_type_select_items = array(
+				"weight" => __("By status weight"),
+				"service" => __("By critical elements")
+			);
+			$form_items_advance['linked_map_status_calculation_row'] = array();
+			$form_items_advance['linked_map_status_calculation_row']['items'] = array('static_graph');
+			$form_items_advance['linked_map_status_calculation_row']['html'] = '<td align="left">'.
+				__('Type of the status calculation of the linked map') . '</td>'
+				. '<td align="left">'
+				. html_print_select(
+					$status_type_select_items, 
+					'linked_map_status_calculation_type',
+					'default',
+					'onLinkedMapStatusCalculationTypeChange(event)',
+					__('By default'),
+					'default',
+					true,
+					false,
+					false
+				)
+				. '</td>';
+
 			$form_items_advance['map_linked_weight'] = array();
 			$form_items_advance['map_linked_weight']['items'] = array('static_graph');
-			$form_items_advance['map_linked_weight']['html'] = '<td align="left">'.
-				__('Map linked weight') . '</td>' .
-				'<td align="left">' . html_print_select(array('10' => '10%',
-															'20' => '20%',
-															'30' => '30%',
-															'40' => '40%',
-															'50' => '50%',
-															'60' => '60%',
-															'70' => '70%',
-															'80' => '80%',
-															'90' => '90%',
-															'100' => '100%'), 
-				'map_linked_weight', '', '', __('By default'), 0, true) . 
-				ui_print_help_icon ("linked_map_weight", true) .
-				'</td>';
+			$form_items_advance['map_linked_weight']['html'] = '<td align="left">'
+				. __('Map linked weight') . '</td>'
+				. '<td align="left">'
+				. html_print_input_text(
+					'map_linked_weight', 80, '', 3, 3, true, false, false, "", "type_number percentage"
+				)
+				. '<span>%</span>'
+				. ui_print_help_icon("linked_map_weight", true)
+				. '</td>';
+
+			$form_items_advance['linked_map_status_service_critical_row'] = array();
+			$form_items_advance['linked_map_status_service_critical_row']['items'] = array('static_graph');
+			$form_items_advance['linked_map_status_service_critical_row']['html'] = '<td align="left">'
+				. __('Critical weight') . '</td>'
+				. '<td align="left">'
+				. html_print_input_text(
+					'linked_map_status_service_critical', 80, '', 3, 3, true, false, false, "", "type_number percentage"
+				)
+				. '<span>%</span>'
+				. '</td>';
+			
+			$form_items_advance['linked_map_status_service_warning_row'] = array();
+			$form_items_advance['linked_map_status_service_warning_row']['items'] = array('static_graph');
+			$form_items_advance['linked_map_status_service_warning_row']['html'] = '<td align="left">'
+				. __('Warning weight') . '</td>'
+				. '<td align="left">'
+				. html_print_input_text(
+					'linked_map_status_service_warning', 50, '', 3, 3, true, false, false, "", "type_number percentage"
+				)
+				. '<span>%</span>'
+				. '</td>';
 
 			$form_items_advance['line_case']['items'] = array('line_item');
 			$form_items_advance['line_case']['html'] = '
@@ -788,6 +826,9 @@ function visual_map_editor_print_item_palette($visualConsole_id, $background) {
 	?>
 	<script type="text/javascript">
 		$(document).ready (function () {
+			$("input.type_number[type=text]").prop("type", "number");
+			$("input.percentage").prop("max", 100).prop("min", 0);
+
 			$(".border_color").attachColorPicker();
 			$(".fill_color").attachColorPicker();
 			$(".line_color").attachColorPicker();
diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql
index 1940c2cc45..ef0d656735 100644
--- a/pandora_console/pandoradb.sql
+++ b/pandora_console/pandoradb.sql
@@ -1377,7 +1377,10 @@ CREATE TABLE IF NOT EXISTS `tlayout_data` (
 	`border_color` varchar(200) DEFAULT "",
 	`fill_color` varchar(200) DEFAULT "",
 	`show_statistics` tinyint(2) NOT NULL default '0',
+	`linked_layout_status_type` ENUM ('default', 'weight', 'service') DEFAULT 'default',
 	`id_layout_linked_weight` int(10) NOT NULL default '0',
+	`linked_layout_status_as_service_warning` FLOAT(20, 3) NOT NULL default 0,
+	`linked_layout_status_as_service_critical` FLOAT(20, 3) NOT NULL default 0,
 	`element_group` int(10) NOT NULL default '0',
 	`show_on_top` tinyint(1) NOT NULL default '0',
 	`clock_animation` varchar(60) NOT NULL default "analogic_1",
@@ -3308,7 +3311,10 @@ CREATE TABLE IF NOT EXISTS `tlayout_template_data` (
 	`border_color` varchar(200) DEFAULT "",
 	`fill_color` varchar(200) DEFAULT "",
 	`show_statistics` tinyint(2) NOT NULL default '0',
+	`linked_layout_status_type` ENUM ('default', 'weight', 'service') DEFAULT 'default',
 	`id_layout_linked_weight` int(10) NOT NULL default '0',
+	`linked_layout_status_as_service_warning` FLOAT(20, 3) NOT NULL default 0,
+	`linked_layout_status_as_service_critical` FLOAT(20, 3) NOT NULL default 0,
 	`element_group` int(10) NOT NULL default '0',
 	`show_on_top` tinyint(1) NOT NULL default '0',
 	`clock_animation` varchar(60) NOT NULL default "analogic_1",