private async static Task <bool> FindPairs(BasicFeatureLayer reservoirPairsLayer, BasicFeatureLayer reservoirSurfacesLayer, BasicFeatureLayer damLayer)
        {
            List <ReservoirPair> reservoirPairs = new List <ReservoirPair>();
            List <CandidateDam>  res1List       = new List <CandidateDam>();

            SharedFunctions.LoadDamCandidatesFromLayer(res1List, damLayer);
            List <ReservoirSurface> reservoirSurfaceList = new List <ReservoirSurface>();

            SharedFunctions.LoadReservoirSurfacesFromLayer(reservoirSurfaceList, reservoirSurfacesLayer);
            List <CandidateDam> res2List = new List <CandidateDam>(res1List);
            int analyzedCounter          = 0;
            int createdCounter           = 0;

            foreach (var dam1 in res1List)
            {
                res2List.Remove(dam1);
                foreach (var dam2 in res2List)
                {
                    try
                    {
                        analyzedCounter++;
                        CandidateDam lowerDam = null;
                        CandidateDam upperDam = null;
                        if (dam1.ContourHeight > dam2.ContourHeight)
                        {
                            lowerDam = dam2;
                            upperDam = dam1;
                        }
                        else
                        {
                            lowerDam = dam1;
                            upperDam = dam2;
                        }

                        //check for height-difference:
                        int usableHeightDifference = upperDam.ContourHeight - upperDam.DamHeight - lowerDam.ContourHeight;
                        if (usableHeightDifference < 50)
                        {
                            continue;
                        }

                        //check for horizontal distance
                        Coordinate3D lowerDamCenter            = new Coordinate3D((lowerDam.StartPoint.X + lowerDam.EndPoint.X) / 2, (lowerDam.StartPoint.Y + lowerDam.EndPoint.Y) / 2, (lowerDam.StartPoint.Z + lowerDam.EndPoint.Z) / 2);
                        Coordinate3D upperDamCenter            = new Coordinate3D((upperDam.StartPoint.X + upperDam.EndPoint.X) / 2, (upperDam.StartPoint.Y + upperDam.EndPoint.Y) / 2, (upperDam.StartPoint.Z + upperDam.EndPoint.Z) / 2);
                        decimal      distanceBetweenDamCenters = SharedFunctions.DistanceBetween(lowerDamCenter, upperDamCenter);
                        if (distanceBetweenDamCenters > 5000)
                        {
                            continue;
                        }

                        //check for reservoir overlap //NOT NECCESSARY due to height-difference check, where all corresponding cases are already filtered
                        //if (GeometryEngine.Instance.Overlaps(reservoirSurfaceList.Single(c => c.DamID == dam1.ObjectID).Polygon, reservoirSurfaceList.Single(c => c.DamID == dam1.ObjectID).Polygon))
                        //    continue;

                        //calculate CapacityInMWh:
                        long usableVolume = upperDam.ReservoirVolume;
                        if (lowerDam.ReservoirVolume < usableVolume)
                        {
                            usableVolume = lowerDam.ReservoirVolume;
                        }

                        //only assume 85% of the water as usable in reality
                        usableVolume = (long)(0.85 * usableVolume);
                        float capacityInMWh = (float)(1000 * 9.8 * usableHeightDifference * usableVolume * 0.9) / (float)((long)3600 * 1000000);

                        //calculate utilizationPercentage:
                        float capacityUtilization = 0;
                        if (upperDam.ReservoirVolume != 0)
                        {
                            capacityUtilization = (float)lowerDam.ReservoirVolume / upperDam.ReservoirVolume;
                        }
                        if (capacityUtilization > 1)
                        {
                            capacityUtilization = 1 / (float)capacityUtilization;
                        }

                        //check for Utilization of at least 75%
                        if (capacityUtilization < 0.75)
                        {
                            continue;
                        }

                        decimal capacityDistanceRatio = (decimal)capacityInMWh * 100 / distanceBetweenDamCenters;

                        List <Coordinate3D> coordinates = new List <Coordinate3D>()
                        {
                            lowerDamCenter, upperDamCenter
                        };
                        Polyline polyline = PolylineBuilder.CreatePolyline(coordinates);

                        ReservoirPair reservoirPair = new ReservoirPair();
                        reservoirPair.LowerDam               = lowerDam;
                        reservoirPair.UpperDam               = upperDam;
                        reservoirPair.LowerDamCenter         = lowerDamCenter;
                        reservoirPair.UpperDamCenter         = upperDamCenter;
                        reservoirPair.Polyline               = polyline;
                        reservoirPair.LowerDamID             = lowerDam.ObjectID;
                        reservoirPair.UpperDamID             = upperDam.ObjectID;
                        reservoirPair.CapacityInMWh          = capacityInMWh;
                        reservoirPair.Distance               = distanceBetweenDamCenters;
                        reservoirPair.LowerHeight            = lowerDam.ContourHeight;
                        reservoirPair.UpperHeight            = upperDam.ContourHeight;
                        reservoirPair.CapacityDistanceRatio  = capacityDistanceRatio;
                        reservoirPair.UsableHeightDifference = usableHeightDifference;
                        reservoirPair.CapacityUtilization    = capacityUtilization;

                        reservoirPairs.Add(reservoirPair);
                    }
                    catch (Exception ex)
                    {
                        SharedFunctions.Log("Error for attempted Pair with dam1: " + dam1.ObjectID + " and dam2: " + dam2.ObjectID + " (" + ex.Message + ")");
                    }
                }
            }
            //try to further minimize the reservoirPairs selection by only keeping
            //the best connection within a buffer of 100 m (around both dam center points)
            List <ReservoirPair> pairsToDelete = new List <ReservoirPair>();

            foreach (var reservoirPair in reservoirPairs.ToList())
            {
                if (pairsToDelete.Contains(reservoirPair))
                {
                    continue;
                }
                var similarPairs = reservoirPairs.Where(c => SharedFunctions.DistanceBetween(reservoirPair.LowerDamCenter, c.LowerDamCenter) <= 100 &&
                                                        SharedFunctions.DistanceBetween(reservoirPair.UpperDamCenter, c.UpperDamCenter) <= 100).ToList();
                if (similarPairs.Count > 1)
                {
                    var bestPair = similarPairs.OrderByDescending(c => c.CapacityDistanceRatio * (decimal)c.CapacityUtilization).First();
                    similarPairs.Remove(bestPair);
                    pairsToDelete = pairsToDelete.Union(similarPairs).ToList();
                }
            }
            foreach (var pairToDelete in pairsToDelete)
            {
                reservoirPairs.Remove(pairToDelete);
            }

            //insert the remaining objects into the DB
            foreach (var reservoirPair in reservoirPairs)
            {
                var attributes = new Dictionary <string, object>
                {
                    { "Shape", reservoirPair.Polyline },
                    { "LowerDamID", (long)reservoirPair.LowerDamID },
                    { "UpperDamID", (long)reservoirPair.UpperDamID },
                    { "CapacityInMWh", (float)reservoirPair.CapacityInMWh },
                    { "Distance", (long)reservoirPair.Distance },
                    { "LowerHeight", (short)reservoirPair.LowerHeight },
                    { "UpperHeight", (short)reservoirPair.UpperHeight },
                    { "CapacityDistanceRatio", (float)reservoirPair.CapacityDistanceRatio },
                    { "UsableHeightDifference", (short)reservoirPair.UsableHeightDifference },
                    { "CapacityUtilization", (float)reservoirPair.CapacityUtilization }
                };
                var createOperation = new EditOperation()
                {
                    Name = "Create reservoir pair", SelectNewFeatures = false
                };
                createOperation.Create(reservoirPairsLayer, attributes);
                await createOperation.ExecuteAsync();

                createdCounter++;
            }

            SharedFunctions.Log(analyzedCounter + " combinations analysed and " + createdCounter + " viable pairs found");

            await Project.Current.SaveEditsAsync();

            return(true);
        }