	private RoutingEntry getRoutingEntryHRG(AbstractRoutingGraph<HRMID, AbstractRoutingGraphLink> pHRG, HRMID pFrom, HRMID pTo, String pCause, LinkedList<LinkedList<AbstractRoutingGraphLink>> pRefDeletedLinks)
	{
		boolean DEBUG = HRMConfig.DebugOutput.GUI_SHOW_HRG_ROUTING;
		RoutingEntry tResult = null;
		LinkedList<AbstractRoutingGraphLink> tDeletedLinks = null;
		if(pRefDeletedLinks != null){
			tDeletedLinks = pRefDeletedLinks.getFirst();
		}
		if (DEBUG){
			Logging.log(this, "getRoutingEntryHRG() searches a route from " + pFrom + " to " + pTo);
		}
		synchronized (pHRG){
			if(pFrom.equals(pTo)){
				tResult = RoutingEntry.createLocalhostEntry(pFrom, pCause);
				tResult.extendCause(this + "::getRoutingEntry() with same source and destination address " + pFrom);
				return tResult;
			}
			if(pFrom.getHierarchyLevel() < pTo.getHierarchyLevel()){
				DEBUG = true;
				HRMID tAbstractSource = pFrom.getClusterAddress(pTo.getHierarchyLevel());
				if (DEBUG){
					Logging.log(this, "getRoutingEntryHRG() searches a more abstract route from a more abstract source " + tAbstractSource + "(" + pFrom + ") to destination " + pTo);
				}
				RoutingEntry tSecondRoutePart = getRoutingEntryHRG(pHRG, tAbstractSource, pTo, pCause, null);
				if (DEBUG){
					Logging.log(this, "          ..second route part: " + tSecondRoutePart);
				}
				if(tSecondRoutePart != null){
					HRMID tOutgressGatewayFromSourceCluster = tSecondRoutePart.getSource();
					RoutingEntry tIntraClusterRoutePart = getRoutingEntryHRG(pHRG, pFrom, tOutgressGatewayFromSourceCluster, pCause, null);
					if (DEBUG){
						Logging.log(this, "          ..first route part: " + tIntraClusterRoutePart);
					}
					if(tIntraClusterRoutePart != null){
						tResult = tIntraClusterRoutePart.clone();
						tResult.append(tSecondRoutePart, pCause);
						if (DEBUG){
							Logging.log(this, "          ..resulting route (" + pFrom + " ==> " + pTo + "): " + tResult);
						}
					}else{
						Logging.warn(this, "getRoutingEntryHRG() couldn't determine an HRG route from " + pFrom + " to " + tOutgressGatewayFromSourceCluster + " as first part for a route from " + pFrom + " to " + pTo);
					}
				}else{
					Logging.warn(this, "getRoutingEntryHRG() couldn't determine an HRG route from " + tAbstractSource + " to " + pTo + " as second part for a route from " + pFrom + " to " + pTo);
				}
				if(tResult != null){
					tResult.extendCause(this + "::getRoutingEntry()");
				}
				return tResult;
			}
			if(pFrom.getHierarchyLevel() > pTo.getHierarchyLevel()){
				HRMID tAbstractDestination = pTo.getClusterAddress(pFrom.getHierarchyLevel());
				if (DEBUG){
					Logging.log(this, "getRoutingEntryHRG() searches a more abstract route from " + pFrom + " to more abstract destination " + tAbstractDestination + "(" + pTo + ")");
				}
				RoutingEntry tFirstRoutePart = getRoutingEntryHRG(pHRG, pFrom, tAbstractDestination, pCause, null);
				if (DEBUG){
					Logging.log(this, "          ..first route part: " + tFirstRoutePart);
				}
				if(tFirstRoutePart != null){
					HRMID tIngressGatewayToDestinationCluster = tFirstRoutePart.getLastNextHop();
					RoutingEntry tIntraClusterRoutePart = getRoutingEntryHRG(pHRG, tIngressGatewayToDestinationCluster, pTo, pCause, null);
					if (DEBUG){
						Logging.log(this, "          ..second route part: " + tIntraClusterRoutePart);
					}
					if(tIntraClusterRoutePart != null){
						tResult = tFirstRoutePart.clone();
						tResult.append(tIntraClusterRoutePart, pCause);
						if (DEBUG){
							Logging.log(this, "          ..resulting route (" + pFrom + " ==> " + tAbstractDestination + "): " + tResult);
						}
					}else{
						Logging.warn(this, "getRoutingEntryHRG() couldn't determine an HRG route from " + tIngressGatewayToDestinationCluster + " to " + pTo + " as second part for a route from " + pFrom + " to " + pTo);
					}
				}else{
					Logging.warn(this, "getRoutingEntryHRG() couldn't determine an HRG route from " + pFrom + " to " + tAbstractDestination + " as first part for a route from " + pFrom + " to " + pTo);
				}
				if(tResult != null){
					tResult.extendCause(this + "::getRoutingEntry()");
				}
				return tResult;
			}
			int tStep = 0;
			List<AbstractRoutingGraphLink> tPath = getRouteHRG(pHRG, pFrom, pTo);
			AbstractRoutingGraphLink tFirstUsedInterClusterLink = null;
			if(tPath != null){
				boolean tRouteLeavesSuperiorCluster = false;
				HRMID tLastClusterGateway = null;
				HRMID tFirstForeignGateway = null;
				if(!tPath.isEmpty()){
					HRMID tFromToSuperiorCluster = pFrom.getForeignCluster(pTo).getSuperiorClusterAddress();
					if (DEBUG){
						Logging.log(this, "      ..found inter cluster path (" + pFrom + " to " + pTo + "): [superior cluster: " + tFromToSuperiorCluster + "]");
						int i = 0;
						for(AbstractRoutingGraphLink tLink : tPath){
							if (DEBUG){
								Logging.log(this, "        ..inter-cluster step[" + i + "]: " + tLink);
							}
							i++;
						}
					}
					for(AbstractRoutingGraphLink tInterClusterLink : tPath){
						RoutingEntry tInterClusterRoutingEntry = tInterClusterLink.getRoutingEntry();
						if(!tInterClusterRoutingEntry.getNextHop().isCluster(tFromToSuperiorCluster)){
							tRouteLeavesSuperiorCluster = true;
							Logging.warn(this, "         ..detected route beyond cluster borders of " + tFromToSuperiorCluster + " in entry: " + tInterClusterRoutingEntry);
						}
						if(tResult != null){
							if(tLastClusterGateway == null){
								throw new RuntimeException(this + "::getRoutingEntryHRG() should never reach this point");
							}
							HRMID tNextClusterGateway = tInterClusterRoutingEntry.getSource();
							if(!tLastClusterGateway.equals(tNextClusterGateway)){
								List<AbstractRoutingGraphLink> tIntraClusterPath = getRouteHRG(pHRG, tLastClusterGateway, tNextClusterGateway);
								if(tIntraClusterPath != null){
									if(!tIntraClusterPath.isEmpty()){
										RoutingEntry tLogicalIntraClusterRoutingEntry = null;
										AbstractRoutingGraphLink tIntraClusterLogLink = tIntraClusterPath.get(0);
										if(tIntraClusterPath.size() == 1){
											tLogicalIntraClusterRoutingEntry = (RoutingEntry) tIntraClusterLogLink.getRoute().getFirst();
										}else{
											tLogicalIntraClusterRoutingEntry = RoutingEntry.create(tIntraClusterPath);
											if(tLogicalIntraClusterRoutingEntry == null){
												if(pRefDeletedLinks == null){
													Logging.warn(this, "getRoutingEntryHRG() for " + pFrom + " found a complex intra-cluster path from " + tLastClusterGateway + " to " + tNextClusterGateway + " and wasn't able to derive an aggregated logical link from it..");
													Logging.warn(this, " 	..path: " + tIntraClusterPath);
													Logging.warn(this, "      ..from: " + tLastClusterGateway);
													Logging.warn(this, "      ..to: " + tNextClusterGateway);
													Logging.warn(this, "    ..for a routing from " + pFrom + " to " + pTo);
												}else{
												}
												tResult = null;
												break;
											}
										}
										if(tLogicalIntraClusterRoutingEntry != null){
											if (DEBUG){
												Logging.log(this, "        ..step [" + tStep + "] (intra-cluster): " + tLogicalIntraClusterRoutingEntry + " ## " + tIntraClusterPath);
											}
											tResult.append(tLogicalIntraClusterRoutingEntry, pCause + "append1_intra_cluster from " + tLastClusterGateway + " to " + tNextClusterGateway);
											tStep++;
											if(tFirstForeignGateway == null){
												if(tLogicalIntraClusterRoutingEntry.getHopCount() > 0){
													tFirstForeignGateway = tLogicalIntraClusterRoutingEntry.getNextHop();
												}
											}
										}
									}else{
										if(pRefDeletedLinks != null){
											if(!tLastClusterGateway.equals(tNextClusterGateway)){
												tResult = null;
												break;
											}else{
											}
										}else{
											Logging.warn(this, "getRoutingEntryHRG() found an empty intra-cluster path..");
											Logging.warn(this, "      ..from: " + tLastClusterGateway);
											Logging.warn(this, "      ..to: " + tNextClusterGateway);
											Logging.warn(this, "    ..for a routing from " + pFrom + " to " + pTo);
										}
									}
								}else{
									Logging.warn(this, "getRoutingEntryHRG() couldn't find a route from " + tLastClusterGateway + " to " + tNextClusterGateway + " for a routing from " + pFrom + " to " + pTo);
									tResult = null;
									break;
								}
							}else{
							}
							if (DEBUG){
								Logging.log(this, "        ..step [" + tStep + "] (cluster-2-cluster): " + tInterClusterRoutingEntry);
							}
							tResult.append(tInterClusterRoutingEntry, pCause + "append2_inter_cluster for a route from " + pFrom + " to " + pTo);
						}else{
							if (DEBUG){
								Logging.log(this, "        ..step [" + tStep + "] (cluster-2-cluster): " + tInterClusterRoutingEntry);
							}
							tInterClusterRoutingEntry.extendCause(pCause + "append3_start_inter_cluster for a route from " + pFrom + " to " + pTo);
							tResult = tInterClusterRoutingEntry;
						}
						tStep++;
						if(tFirstUsedInterClusterLink == null){
							tFirstUsedInterClusterLink = tInterClusterLink;
						}
						if(tFirstForeignGateway == null){
							if(tInterClusterRoutingEntry.getHopCount() > 0){
								tFirstForeignGateway = tInterClusterRoutingEntry.getNextHop();
							}
						}
						tLastClusterGateway = tInterClusterRoutingEntry.getNextHop();
					} 
				}else{
					if(pRefDeletedLinks == null){
					}else{
					}
				}
				if(tResult != null){
					tResult.setDest(pFrom.getForeignCluster(pTo) );
					tResult.setNextHopL2Address(null);
					if(tRouteLeavesSuperiorCluster){
						tResult.setRouteAcrossNetwork();
					}
					if(tFirstUsedInterClusterLink != null){
						if(tDeletedLinks != null){
							if (DEBUG){
								Logging.log(this, "  ..mark as deleted: " + tFirstUsedInterClusterLink);
							}
							tDeletedLinks.add(tFirstUsedInterClusterLink);
							pHRG.unlink(tFirstUsedInterClusterLink);
						}
					}
				}
			}else{
				if(!FOUND_GLOBAL_ERROR){
					Logging.warn(this, "getRoutingEntryHRG() couldn't determine an HRG based inter-cluster route from " + pFrom + " to " + pTo);
				}
			}
		}
		return tResult;
	}

	private RoutingEntry getRoutingEntryHRG(AbstractRoutingGraph<HRMID, AbstractRoutingGraphLink> pHRG, HRMID pFrom, HRMID pTo, String pCause, LinkedList<LinkedList<AbstractRoutingGraphLink>> pRefDeletedLinks)
	{
		boolean DEBUG = HRMConfig.DebugOutput.GUI_SHOW_HRG_ROUTING;
		RoutingEntry tResult = null;
		LinkedList<AbstractRoutingGraphLink> tDeletedLinks = null;
		if(pRefDeletedLinks != null){
			tDeletedLinks = pRefDeletedLinks.getFirst();
		}
		if (DEBUG){
			Logging.log(this, "getRoutingEntryHRG() searches a route from " + pFrom + " to " + pTo);
		}
		synchronized (pHRG){
			if(pFrom.equals(pTo)){
				tResult = RoutingEntry.createLocalhostEntry(pFrom, pCause);
				tResult.extendCause(this + "::getRoutingEntry() with same source and destination address " + pFrom);
				return tResult;
			}
			if(pFrom.getHierarchyLevel() < pTo.getHierarchyLevel()){
				DEBUG = true;
				HRMID tAbstractSource = pFrom.getClusterAddress(pTo.getHierarchyLevel());
				if (DEBUG){
					Logging.log(this, "getRoutingEntryHRG() searches a more abstract route from a more abstract source " + tAbstractSource + "(" + pFrom + ") to destination " + pTo);
				}
				RoutingEntry tSecondRoutePart = getRoutingEntryHRG(pHRG, tAbstractSource, pTo, pCause, null);
				if (DEBUG){
					Logging.log(this, "          ..second route part: " + tSecondRoutePart);
				}
				if(tSecondRoutePart != null){
					HRMID tOutgressGatewayFromSourceCluster = tSecondRoutePart.getSource();
					RoutingEntry tIntraClusterRoutePart = getRoutingEntryHRG(pHRG, pFrom, tOutgressGatewayFromSourceCluster, pCause, null);
					if (DEBUG){
						Logging.log(this, "          ..first route part: " + tIntraClusterRoutePart);
					}
					if(tIntraClusterRoutePart != null){
						tResult = tIntraClusterRoutePart.clone();
						tResult.append(tSecondRoutePart, pCause);
						if (DEBUG){
							Logging.log(this, "          ..resulting route (" + pFrom + " ==> " + pTo + "): " + tResult);
						}
					}else{
						Logging.warn(this, "getRoutingEntryHRG() couldn't determine an HRG route from " + pFrom + " to " + tOutgressGatewayFromSourceCluster + " as first part for a route from " + pFrom + " to " + pTo);
					}
				}else{
					Logging.warn(this, "getRoutingEntryHRG() couldn't determine an HRG route from " + tAbstractSource + " to " + pTo + " as second part for a route from " + pFrom + " to " + pTo);
				}
				if(tResult != null){
					tResult.extendCause(this + "::getRoutingEntry()");
				}
				return tResult;
			}
			if(pFrom.getHierarchyLevel() > pTo.getHierarchyLevel()){
				HRMID tAbstractDestination = pTo.getClusterAddress(pFrom.getHierarchyLevel());
				if (DEBUG){
					Logging.log(this, "getRoutingEntryHRG() searches a more abstract route from " + pFrom + " to more abstract destination " + tAbstractDestination + "(" + pTo + ")");
				}
				RoutingEntry tFirstRoutePart = getRoutingEntryHRG(pHRG, pFrom, tAbstractDestination, pCause, null);
				if (DEBUG){
					Logging.log(this, "          ..first route part: " + tFirstRoutePart);
				}
				if(tFirstRoutePart != null){
					HRMID tIngressGatewayToDestinationCluster = tFirstRoutePart.getLastNextHop();
					RoutingEntry tIntraClusterRoutePart = getRoutingEntryHRG(pHRG, tIngressGatewayToDestinationCluster, pTo, pCause, null);
					if (DEBUG){
						Logging.log(this, "          ..second route part: " + tIntraClusterRoutePart);
					}
					if(tIntraClusterRoutePart != null){
						tResult = tFirstRoutePart.clone();
						tResult.append(tIntraClusterRoutePart, pCause);
						if (DEBUG){
							Logging.log(this, "          ..resulting route (" + pFrom + " ==> " + tAbstractDestination + "): " + tResult);
						}
					}else{
						Logging.warn(this, "getRoutingEntryHRG() couldn't determine an HRG route from " + tIngressGatewayToDestinationCluster + " to " + pTo + " as second part for a route from " + pFrom + " to " + pTo);
					}
				}else{
					Logging.warn(this, "getRoutingEntryHRG() couldn't determine an HRG route from " + pFrom + " to " + tAbstractDestination + " as first part for a route from " + pFrom + " to " + pTo);
				}
				if(tResult != null){
					tResult.extendCause(this + "::getRoutingEntry()");
				}
				return tResult;
			}
			int tStep = 0;
			List<AbstractRoutingGraphLink> tPath = getRouteHRG(pHRG, pFrom, pTo);
			AbstractRoutingGraphLink tFirstUsedInterClusterLink = null;
			if(tPath != null){
				boolean tRouteLeavesSuperiorCluster = false;
				HRMID tLastClusterGateway = null;
				HRMID tFirstForeignGateway = null;
				if(!tPath.isEmpty()){
					HRMID tFromToSuperiorCluster = pFrom.getForeignCluster(pTo).getSuperiorClusterAddress();
					if (DEBUG){
						Logging.log(this, "      ..found inter cluster path (" + pFrom + " to " + pTo + "): [superior cluster: " + tFromToSuperiorCluster + "]");
						int i = 0;
						for(AbstractRoutingGraphLink tLink : tPath){
							if (DEBUG){
								Logging.log(this, "        ..inter-cluster step[" + i + "]: " + tLink);
							}
							i++;
						}
					}
					for(AbstractRoutingGraphLink tInterClusterLink : tPath){
						RoutingEntry tInterClusterRoutingEntry = tInterClusterLink.getRoutingEntry();
						if(!tInterClusterRoutingEntry.getNextHop().isCluster(tFromToSuperiorCluster)){
							tRouteLeavesSuperiorCluster = true;
						}
						if(tResult != null){
							if(tLastClusterGateway == null){
								throw new RuntimeException(this + "::getRoutingEntryHRG() should never reach this point");
							}
							HRMID tNextClusterGateway = tInterClusterRoutingEntry.getSource();
							if(!tLastClusterGateway.equals(tNextClusterGateway)){
								List<AbstractRoutingGraphLink> tIntraClusterPath = getRouteHRG(pHRG, tLastClusterGateway, tNextClusterGateway);
								if(tIntraClusterPath != null){
									if(!tIntraClusterPath.isEmpty()){
										RoutingEntry tLogicalIntraClusterRoutingEntry = null;
										AbstractRoutingGraphLink tIntraClusterLogLink = tIntraClusterPath.get(0);
										if(tIntraClusterPath.size() == 1){
											tLogicalIntraClusterRoutingEntry = (RoutingEntry) tIntraClusterLogLink.getRoute().getFirst();
										}else{
											tLogicalIntraClusterRoutingEntry = RoutingEntry.create(tIntraClusterPath);
											if(tLogicalIntraClusterRoutingEntry == null){
												if(pRefDeletedLinks == null){
													Logging.warn(this, "getRoutingEntryHRG() for " + pFrom + " found a complex intra-cluster path from " + tLastClusterGateway + " to " + tNextClusterGateway + " and wasn't able to derive an aggregated logical link from it..");
													Logging.warn(this, " 	..path: " + tIntraClusterPath);
													Logging.warn(this, "      ..from: " + tLastClusterGateway);
													Logging.warn(this, "      ..to: " + tNextClusterGateway);
													Logging.warn(this, "    ..for a routing from " + pFrom + " to " + pTo);
												}else{
												}
												tResult = null;
												break;
											}
										}
										if(tLogicalIntraClusterRoutingEntry != null){
											if (DEBUG){
												Logging.log(this, "        ..step [" + tStep + "] (intra-cluster): " + tLogicalIntraClusterRoutingEntry + " ## " + tIntraClusterPath);
											}
											tResult.append(tLogicalIntraClusterRoutingEntry, pCause + "append1_intra_cluster from " + tLastClusterGateway + " to " + tNextClusterGateway);
											tStep++;
											if(tFirstForeignGateway == null){
												if(tLogicalIntraClusterRoutingEntry.getHopCount() > 0){
													tFirstForeignGateway = tLogicalIntraClusterRoutingEntry.getNextHop();
												}
											}
										}
									}else{
										if(pRefDeletedLinks != null){
											if(!tLastClusterGateway.equals(tNextClusterGateway)){
												tResult = null;
												break;
											}else{
											}
										}else{
											Logging.warn(this, "getRoutingEntryHRG() found an empty intra-cluster path..");
											Logging.warn(this, "      ..from: " + tLastClusterGateway);
											Logging.warn(this, "      ..to: " + tNextClusterGateway);
											Logging.warn(this, "    ..for a routing from " + pFrom + " to " + pTo);
										}
									}
								}else{
									Logging.warn(this, "getRoutingEntryHRG() couldn't find a route from " + tLastClusterGateway + " to " + tNextClusterGateway + " for a routing from " + pFrom + " to " + pTo);
									tResult = null;
									break;
								}
							}else{
							}
							if (DEBUG){
								Logging.log(this, "        ..step [" + tStep + "] (cluster-2-cluster): " + tInterClusterRoutingEntry);
							}
							tResult.append(tInterClusterRoutingEntry, pCause + "append2_inter_cluster for a route from " + pFrom + " to " + pTo);
						}else{
							if (DEBUG){
								Logging.log(this, "        ..step [" + tStep + "] (cluster-2-cluster): " + tInterClusterRoutingEntry);
							}
							tInterClusterRoutingEntry.extendCause(pCause + "append3_start_inter_cluster for a route from " + pFrom + " to " + pTo);
							tResult = tInterClusterRoutingEntry;
						}
						tStep++;
						if(tFirstUsedInterClusterLink == null){
							tFirstUsedInterClusterLink = tInterClusterLink;
						}
						if(tFirstForeignGateway == null){
							if(tInterClusterRoutingEntry.getHopCount() > 0){
								tFirstForeignGateway = tInterClusterRoutingEntry.getNextHop();
							}
						}
						tLastClusterGateway = tInterClusterRoutingEntry.getNextHop();
					} 
				}else{
					if(pRefDeletedLinks == null){
					}else{
					}
				}
				if(tResult != null){
					tResult.setDest(pFrom.getForeignCluster(pTo) );
					tResult.setNextHopL2Address(null);
					if(tRouteLeavesSuperiorCluster){
						tResult.setRouteAcrossNetwork();
					}
					if(tFirstUsedInterClusterLink != null){
						if(tDeletedLinks != null){
							if (DEBUG){
								Logging.log(this, "  ..mark as deleted: " + tFirstUsedInterClusterLink);
							}
							tDeletedLinks.add(tFirstUsedInterClusterLink);
							pHRG.unlink(tFirstUsedInterClusterLink);
						}
					}
				}
			}else{
				if(!FOUND_GLOBAL_ERROR){
					Logging.warn(this, "getRoutingEntryHRG() couldn't determine an HRG based inter-cluster route from " + pFrom + " to " + pTo);
				}
			}
		}
		return tResult;
	}
