//---------------------------------------------------------------------------//
// Search the domain with the range entity centroids and construct the
// graph. This will update the state of the object.
void ParallelSearch::search( 
    const EntityIterator& range_iterator,
    const Teuchos::RCP<EntityLocalMap>& range_local_map,
    const Teuchos::ParameterList& parameters )
{
    // Set the parameters with the local map.
    range_local_map->setParameters( parameters );

    // Empty range flag.
    d_empty_range = ( 0 == range_iterator.size() );

    // Reset the state of the object.
    d_range_owner_ranks.clear();
    d_domain_to_range_map.clear();
    d_range_to_domain_map.clear();
    d_parametric_coords.clear();

    // Perform a coarse global search to redistribute the range entities.
    Teuchos::Array<EntityId> range_entity_ids;
    Teuchos::Array<int> range_owner_ranks;
    Teuchos::Array<double> range_centroids;
    d_coarse_global_search->search( 
	range_iterator, range_local_map, parameters,
	range_entity_ids, range_owner_ranks, range_centroids );

    // If needed, extract the range entities that were missed during the
    // coarse global search.
    Teuchos::Array<EntityId> found_range_entity_ids;
    Teuchos::Array<int> found_range_ranks;
    Teuchos::Array<EntityId> missed_range_entity_ids;
    Teuchos::Array<int> missed_range_ranks;
    if ( d_track_missed_range_entities )
    {
	missed_range_entity_ids = Teuchos::Array<EntityId>( 
	    d_coarse_global_search->getMissedRangeEntityIds() );
	missed_range_ranks.assign( missed_range_entity_ids.size(),
				   d_comm->getRank() );
    }

    // Only do the local search if there are local domain entities.
    Teuchos::Array<int> export_range_ranks;
    Teuchos::Array<EntityId> export_data;
    if ( !d_empty_domain )
    {
	// For each range centroid, perform a local search.
	int num_range = range_entity_ids.size();
	Teuchos::Array<Entity> domain_neighbors;
	Teuchos::Array<Entity> domain_parents;
	Teuchos::Array<double> reference_coordinates;
	Teuchos::Array<double> local_coords( d_physical_dim );
	int num_parents = 0;
	for ( int n = 0; n < num_range; ++n )
	{
	    // Perform a coarse local search to get the nearest domain
	    // entities to the point.
	    d_coarse_local_search->search( 
		range_centroids(d_physical_dim*n,d_physical_dim),
		parameters,
		domain_neighbors );
	
	    // Perform a fine local search to get the entities the point maps
	    // to.
	    d_fine_local_search->search( 
		domain_neighbors,
		range_centroids(d_physical_dim*n,d_physical_dim),
		parameters,
		domain_parents,
		reference_coordinates );

	    // Store the potentially multiple parametric realizations of the
	    // point.
	    std::unordered_map<EntityId,Teuchos::Array<double> > ref_map;
	    num_parents = domain_parents.size();
	    for ( int p = 0; p < num_parents; ++p )
	    {
		// Store the range data in the domain parallel decomposition.
		local_coords().assign( 
		    reference_coordinates(d_physical_dim*p,d_physical_dim) );
		d_range_owner_ranks.emplace(
		    range_entity_ids[n], range_owner_ranks[n] );
		d_domain_to_range_map.emplace(
		    domain_parents[p].id(), range_entity_ids[n] );
		ref_map.emplace(
		    domain_parents[p].id(), local_coords );

		// Extract the data to communicate back to the range parallel
		// decomposition. 
		export_range_ranks.push_back( range_owner_ranks[n] );
		export_data.push_back( range_entity_ids[n] );
		export_data.push_back( domain_parents[p].id() );
		export_data.push_back( 
		    Teuchos::as<EntityId>(d_comm->getRank()) );
	    }

	    // If we found parents for the point, store them.
	    if ( num_parents > 0 )
	    {
		d_parametric_coords.emplace( range_entity_ids[n], ref_map );

		// If we are tracking missed entities, also track those that
		// we found so we can determine if an entity was found after
		// being sent to multiple destinations.
		if ( d_track_missed_range_entities )
		{
		    found_range_entity_ids.push_back( range_entity_ids[n] );
		    found_range_ranks.push_back( range_owner_ranks[n] );
		}
	    }
	    
	    // Otherwise, if we are tracking missed entities report this.
	    else if ( d_track_missed_range_entities )
	    {
		missed_range_entity_ids.push_back( range_entity_ids[n] );
		missed_range_ranks.push_back( range_owner_ranks[n] );
	    }
	}
    }

    // Back-communicate the domain entities in which we found each range
    // entity to complete the mapping.
    Tpetra::Distributor domain_to_range_dist( d_comm );
    int num_import = 
	domain_to_range_dist.createFromSends( export_range_ranks() );
    Teuchos::Array<EntityId> domain_data( 3*num_import );
    Teuchos::ArrayView<const EntityId> export_data_view = export_data();
    domain_to_range_dist.doPostsAndWaits( export_data_view, 3, domain_data() );

    // Store the domain data in the range parallel decomposition.
    for ( int i = 0; i < num_import; ++i )
    {
	d_domain_owner_ranks.emplace(
	    domain_data[3*i+1], domain_data[3*i+2] );
	d_range_to_domain_map.emplace(
	    domain_data[3*i], domain_data[3*i+1] );
    }

    // If we are tracking missed entities, back-communicate the missing entities
    // and found entities to determine which entities are actually missing.
    if ( d_track_missed_range_entities )
    {
	// Back-communicate the missing entities.
	Tpetra::Distributor missed_range_dist( d_comm );
	int num_import_missed = 
	    missed_range_dist.createFromSends( missed_range_ranks() );
	Teuchos::Array<EntityId> import_missed( num_import_missed );
	Teuchos::ArrayView<const EntityId> missed_view = 
	    missed_range_entity_ids();
	missed_range_dist.doPostsAndWaits( missed_view, 1, import_missed() );

	// Back-communicate the found entities.
	Tpetra::Distributor found_range_dist( d_comm );
	int num_import_found = 
	    found_range_dist.createFromSends( found_range_ranks() );
	Teuchos::Array<EntityId> import_found( num_import_found );
	Teuchos::ArrayView<const EntityId> found_view = 
	    found_range_entity_ids();
	found_range_dist.doPostsAndWaits( found_view, 1, import_found() );

	// Intersect the found and missed entities to determine if there are any
	// that were found on one process but missed on another.
	std::sort( import_missed.begin(), import_missed.end() );
	std::sort( import_found.begin(), import_found.end() );
	Teuchos::Array<EntityId> false_positive_missed(
	    import_missed.size() + import_found.size() );
	auto false_positive_end = 
	    std::set_intersection( import_missed.begin(), import_missed.end(),
				   import_found.begin(), import_found.end(),
				   false_positive_missed.begin() );

	// Create a list of missed entities without the false positives.
	d_missed_range_entity_ids.resize( num_import_missed );
	auto missed_range_end = std::set_difference( 
	    import_missed.begin(), import_missed.end(),
	    false_positive_missed.begin(), false_positive_end,
	    d_missed_range_entity_ids.begin() );

	// Create a unique list of missed entities without the false positives.
	std::sort( d_missed_range_entity_ids.begin(), missed_range_end );
	auto missed_range_unique_end = std::unique(
	    d_missed_range_entity_ids.begin(), missed_range_end );
	d_missed_range_entity_ids.resize(
	    std::distance(d_missed_range_entity_ids.begin(),
			  missed_range_unique_end) );
    }
}
// This is called when user presses enter in the location input
// or selects a location from the typed locations dropdown.
void LLNavigationBar::onLocationSelection()
{
	std::string typed_location = mCmbLocation->getSimple();
	LLStringUtil::trim(typed_location);

	// Will not teleport to empty location.
	if (typed_location.empty())
		return;
	//get selected item from combobox item
	LLSD value = mCmbLocation->getSelectedValue();
	if(value.isUndefined() && !mCmbLocation->getTextEntry()->isDirty())
	{
		// At this point we know that: there is no selected item in list and text field has NOT been changed
		// So there is no sense to try to change the location
		return;
	}
	/* since navbar list support autocompletion it contains several types of item: landmark, teleport hystory item,
	 * typed by user slurl or region name. Let's find out which type of item the user has selected 
	 * to make decision about adding this location into typed history. see mSaveToLocationHistory
	 * Note:
	 * Only TYPED_REGION_SLURL item will be added into LLLocationHistory 
	 */  
	
	if(value.has("item_type"))
	{

		switch(value["item_type"].asInteger())
		{
		case LANDMARK:
			
			if(value.has("AssetUUID"))
			{
				
				gAgent.teleportViaLandmark( LLUUID(value["AssetUUID"].asString()));
				return;
			}
			else
			{
				LLInventoryModel::item_array_t landmark_items =
						LLLandmarkActions::fetchLandmarksByName(typed_location,
								FALSE);
				if (!landmark_items.empty())
				{
					gAgent.teleportViaLandmark( landmark_items[0]->getAssetUUID());
					return; 
				}
			}
			break;
			
		case TELEPORT_HISTORY:
			//in case of teleport item was selected, teleport by position too.
		case TYPED_REGION_SLURL:
			if(value.has("global_pos"))
			{
				gAgent.teleportViaLocation(LLVector3d(value["global_pos"]));
				return;
			}
			break;
			
		default:
			break;		
		}
	}
	//Let's parse slurl or region name
	
	std::string region_name;
	LLVector3 local_coords(128, 128, 0);
	S32 x = 0, y = 0, z = 0;
	// Is the typed location a SLURL?
	if (LLSLURL::isSLURL(typed_location))
	{
		// Yes. Extract region name and local coordinates from it.
		if (LLURLSimString::parse(LLSLURL::stripProtocol(typed_location), &region_name, &x, &y, &z))
				local_coords.set(x, y, z);
		else
			return;
	}
	// we have to do this check after previous, because LLUrlRegistry contains handlers for slurl too  
	//but we need to know whether typed_location is a simple http url.
	else if (LLUrlRegistry::instance().isUrl(typed_location)) 
	{
		// display http:// URLs in the media browser, or
		// anything else is sent to the search floater
		LLWeb::loadURL(typed_location);
		return;
	}
	else
	{
		// assume that an user has typed the {region name} or possible {region_name, parcel}
		region_name  = typed_location.substr(0,typed_location.find(','));
	}
	
	// Resolve the region name to its global coordinates.
	// If resolution succeeds we'll teleport.
	LLWorldMapMessage::url_callback_t cb = boost::bind(
			&LLNavigationBar::onRegionNameResponse, this,
			typed_location, region_name, local_coords, _1, _2, _3, _4);
	mSaveToLocationHistory = true;
	LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name, cb, std::string("unused"), false);
}