private async Task <bool> SendCommands(IsolationAlgorithm algorithm, Dictionary <long, DiscreteCommandingType> commands, Dictionary <long, CommandedElement> commandedElements)
        {
            var algorithmBaseLogString = $"{baseLogString} [HeadBreakerGid: 0x{algorithm.HeadBreakerGid:X16}]";

            if (!await lifecycleHelper.SendMultipleScadaCommandAsync(commands, commandedElements, CommandOriginType.ISOLATING_ALGORITHM_COMMAND))
            {
                string message = $"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Sending multiple command failed.";
                Logger.LogError(message);
                return(false);
            }

            commands.Keys.ToList().ForEach(async commandedElementGid =>
            {
                var commandedElement = new CommandedElement()
                {
                    ElementGid = commandedElementGid,
                    CorrespondingHeadElementGid = algorithm.HeadBreakerGid,
                    CommandingType = commands[commandedElementGid],
                };

                await CommandedElements.SetAsync(commandedElementGid, commandedElement);
                await ElementsToBeIgnoredInReportPotentialOutage.SetAsync(commandedElementGid, DateTime.UtcNow);
                Logger.LogDebug($"{algorithmBaseLogString} SendCommands => Element 0x{commandedElementGid:X16} set to collection '{ReliableDictionaryNames.ElementsToBeIgnoredInReportPotentialOutage}' at {DateTime.UtcNow}.");
            });

            await StartedIsolationAlgorithms.SetAsync(algorithm.HeadBreakerGid, algorithm);

            return(true);
        }
        private async Task <bool> SendCommands(IsolationAlgorithm algorithm, Dictionary <long, DiscreteCommandingType> commands, Dictionary <long, CommandedElement> commandedElements)
        {
            var algorithmBaseLogString = $"{baseLogString} [HeadBreakerGid: 0x{algorithm.HeadBreakerGid:X16}]";

            if (!await lifecycleHelper.SendMultipleScadaCommandAsync(commands, commandedElements, CommandOriginType.ISOLATING_ALGORITHM_COMMAND))
            {
                string message = $"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Sending multiple command failed.";
                Logger.LogError(message);
                return(false);
            }

            commands.Keys.ToList().ForEach(async commandedElementGid =>
            {
                var commandedElement = new CommandedElement()
                {
                    ElementGid = commandedElementGid,
                    CorrespondingHeadElementGid = algorithm.HeadBreakerGid,
                    CommandingType = commands[commandedElementGid],
                };
                await CommandedElements.SetAsync(commandedElementGid, commandedElement);

                algorithm.ElementsCommandedInCurrentCycle.Add(commandedElementGid);
            });

            await StartedIsolationAlgorithms.SetAsync(algorithm.HeadBreakerGid, algorithm);

            return(true);
        }
        private async Task <bool> StartLocationAndIsolationAlgorithm(OutageEntity outageEntity, OutageTopologyModel topology)
        {
            long reportedGid = outageEntity.DefaultIsolationPoints.First().EquipmentId;

            if (!topology.GetElementByGid(reportedGid, out OutageTopologyElement topologyElement))
            {
                Logger.LogError($"{baseLogString} StartLocationAndIsolationAlgorithm => element with gid 0x{reportedGid:X16} not found in outage topology model.");
                return(false);
            }

            long upBreaker;
            long outageElementGid = -1;

            Logger.LogInformation($"{baseLogString} StartLocationAndIsolationAlgorithm => Entering 10 sec delay.");
            await Task.Delay(10_000);

            Logger.LogInformation($"{baseLogString} StartLocationAndIsolationAlgorithm => 10 sec delay ended.");

            var outageSimulatorClient   = OutageSimulatorClient.CreateClient();
            var outageModelAccessClient = OutageModelAccessClient.CreateClient();

            //Da li je prijaveljen element OutageElement
            if (await outageSimulatorClient.IsOutageElement(reportedGid))
            {
                outageElementGid = reportedGid;
            }
            //Da li je mozda na ACL-novima ispod prijavljenog elementa
            else
            {
                for (int i = 0; i < topologyElement.SecondEnd.Count; i++)
                {
                    var potentialOutageElementGid = topologyElement.SecondEnd[i];

                    if (!(await outageSimulatorClient.IsOutageElement(potentialOutageElementGid)))
                    {
                        continue;
                    }

                    if (outageElementGid == -1)
                    {
                        outageElementGid = potentialOutageElementGid;
                        outageEntity.OutageElementGid = outageElementGid;
                        //outageEntity.AffectedConsumers = await lifecycleHelper.GetAffectedConsumersFromDatabase(lifecycleHelper.GetAffectedConsumers(outageElementGid, topology, NetworkType.NON_SCADA_NETWORK));
                    }
                    else
                    {
                        //KAKO SE ULAZI U OVAJ ELSE? => u else se ulazi tako sto se ide kroz for i prvi element se oznaci kao outage element, zatim se pronaje jos neki... znaci ovo je nacin da se kreira drugi, treci outage, na racvanju ispod elementa, po for-u....
                        var entity = new OutageEntity()
                        {
                            OutageElementGid = potentialOutageElementGid,
                            ReportTime       = DateTime.UtcNow
                        };

                        await outageModelAccessClient.AddOutage(entity);
                    }
                }
            }

            //Tragamo za ACL-om gore ka source-u
            while (outageElementGid == -1 && !topologyElement.IsRemote && topologyElement.DmsType != "ENERGYSOURCE")
            {
                if (await outageSimulatorClient.IsOutageElement(topologyElement.Id))
                {
                    outageElementGid = topologyElement.Id;
                    outageEntity.OutageElementGid = outageElementGid;
                }

                topology.GetElementByGid(topologyElement.FirstEnd, out topologyElement);
            }

            if (outageElementGid == -1)
            {
                outageEntity.OutageState = OutageState.REMOVED;
                await outageModelAccessClient.RemoveOutage(outageEntity);

                Logger.LogError($"{baseLogString} StartLocationAndIsolationAlgorithm => End of feeder no outage detected.");
                return(false);
            }

            topology.GetElementByGidFirstEnd(outageEntity.OutageElementGid, out topologyElement);
            while (topologyElement.DmsType != "BREAKER")
            {
                topology.GetElementByGidFirstEnd(topologyElement.Id, out topologyElement);
            }

            upBreaker = topologyElement.Id;
            long nextBreaker = lifecycleHelper.GetNextBreaker(outageEntity.OutageElementGid, topology);

            if (!topology.OutageTopology.ContainsKey(nextBreaker))
            {
                string message = $"{baseLogString} StartLocationAndIsolationAlgorithm => Breaker (next breaker) with id: 0x{nextBreaker:X16} is not in topology";
                Logger.LogError(message);
                throw new Exception(message);
            }

            long outageElement = topology.OutageTopology[nextBreaker].FirstEnd;

            if (!topology.OutageTopology[upBreaker].SecondEnd.Contains(outageElement))
            {
                string message = $"{baseLogString} StartLocationAndIsolationAlgorithm => Outage element with gid: 0x{outageElement:X16} is not on a second end of current breaker id";
                Logger.LogError(message);
                throw new Exception(message);
            }

            outageEntity.OptimumIsolationPoints = await lifecycleHelper.GetEquipmentEntityAsync(new List <long>() { upBreaker, nextBreaker });

            outageEntity.IsolatedTime = DateTime.UtcNow;
            outageEntity.OutageState  = OutageState.ISOLATED;

            await outageModelAccessClient.UpdateOutage(outageEntity);

            var commands = new Dictionary <long, DiscreteCommandingType>
            {
                { upBreaker, DiscreteCommandingType.OPEN },
                { nextBreaker, DiscreteCommandingType.OPEN },
            };

            var enumerableCommandedElements = await CommandedElements.GetEnumerableDictionaryAsync();

            if (!await lifecycleHelper.SendMultipleScadaCommandAsync(commands, enumerableCommandedElements, CommandOriginType.LOCATION_AND_ISOLATING_ALGORITHM_COMMAND))
            {
                string message = $"{baseLogString} StartLocationAndIsolationAlgorithm => Sending multiple command failed.";
                Logger.LogError(message);
                return(false);
            }

            commands.Keys.ToList().ForEach(async commandedElementGid =>
            {
                await ElementsToBeIgnoredInReportPotentialOutage.SetAsync(commandedElementGid, DateTime.UtcNow);
                Logger.LogDebug($"{baseLogString} SendCommands => Element 0x{commandedElementGid:X16} set to collection '{ReliableDictionaryNames.ElementsToBeIgnoredInReportPotentialOutage}' at {DateTime.UtcNow}.");
            });

            return(true);
        }