//TODO: razmotriti stanje outage na ako se algoritam enduje sa nekim fejlom.... da li brisati sam outage npr...
        private async Task OnEndAlgorithmCleanUp(long headBreakerGid)
        {
            var algorithmBaseLogString = $"{baseLogString} [HeadBreakerGid: 0x{headBreakerGid:X16}]";

            await StartedIsolationAlgorithms.TryRemoveAsync(headBreakerGid);

            await MonitoredHeadBreakerMeasurements.TryRemoveAsync(headBreakerGid);

            var enumerableCommandedElements = await CommandedElements.GetEnumerableDictionaryAsync();

            var commandedElementsToBeRemoved = enumerableCommandedElements.Values.Where(element => element.CorrespondingHeadElementGid == headBreakerGid);

            foreach (var element in commandedElementsToBeRemoved)
            {
                await CommandedElements.TryRemoveAsync(element.ElementGid);
            }

            var enumerableOptimumIsolationPoints = await OptimumIsolationPoints.GetEnumerableDictionaryAsync();

            var optimumIsolationPointsToBeRemovedGids = enumerableOptimumIsolationPoints.Where(kvp => kvp.Value == headBreakerGid).Select(kvp => kvp.Key);

            foreach (var gid in optimumIsolationPointsToBeRemovedGids)
            {
                await OptimumIsolationPoints.TryRemoveAsync(gid);
            }
        }
        public async Task Notify(IPublishableMessage message, string publisherName)
        {
            Logger.LogDebug($"{baseLogString} Notify method started.");

            while (!ReliableDictionariesInitialized)
            {
                await Task.Delay(1000);
            }

            try
            {
                if (message is MultipleDiscreteValueSCADAMessage multipleDiscreteValueSCADAMessage)
                {
                    Logger.LogDebug($"{baseLogString} MultipleDiscreteValueSCADAMessage received.");
                    var discreteData = multipleDiscreteValueSCADAMessage.Data;

                    #region HeadBreakers
                    var enumerableHeadBreakerMeasurements = await MonitoredHeadBreakerMeasurements.GetEnumerableDictionaryAsync();

                    foreach (var headMeasurementGid in enumerableHeadBreakerMeasurements.Keys)
                    {
                        if (!discreteData.ContainsKey(headMeasurementGid))
                        {
                            continue;
                        }

                        await MonitoredHeadBreakerMeasurements.SetAsync(headMeasurementGid, discreteData[headMeasurementGid]);
                    }
                    #endregion HeadBreakers

                    #region CommandedElements
                    var measurementProviderClient   = MeasurementProviderClient.CreateClient();
                    var enumerableCommandedElements = await CommandedElements.GetEnumerableDictionaryAsync();

                    foreach (var commandedElementGid in enumerableCommandedElements.Keys)
                    {
                        var measurementGid = (await measurementProviderClient.GetMeasurementsOfElement(commandedElementGid)).FirstOrDefault();
                        var measurement    = await measurementProviderClient.GetDiscreteMeasurement(measurementGid);

                        if (measurement is ArtificalDiscreteMeasurement)
                        {
                            await CommandedElements.TryRemoveAsync(commandedElementGid);

                            Logger.LogInformation($"{baseLogString} Notify => Command on element 0x{commandedElementGid:X16} executed (ArtificalDiscreteMeasurement). New value: {measurement.CurrentOpen}");
                            continue;
                        }

                        if (!discreteData.ContainsKey(measurementGid))
                        {
                            continue;
                        }

                        if (discreteData[measurementGid].Value == (ushort)enumerableCommandedElements[commandedElementGid].CommandingType)
                        {
                            if ((await CommandedElements.TryRemoveAsync(commandedElementGid)).HasValue)
                            {
                                Logger.LogInformation($"{baseLogString} Notify => Command on element 0x{commandedElementGid:X16} executed. New value: {discreteData[measurementGid].Value}");
                            }
                        }
                    }
                    #endregion CommandedElements
                }
                else if (message is OMSModelMessage omsModelMessage)
                {
                    Logger.LogDebug($"{baseLogString} OMSModelMessage received. Count {omsModelMessage.OutageTopologyModel.OutageTopology.Count}");

                    OutageTopologyModel topology = omsModelMessage.OutageTopologyModel;
                    await OutageTopologyModel.SetAsync(ReliableDictionaryNames.OutageTopologyModel, topology);

                    var reportingOutageClient = PotentialOutageReportingClient.CreateClient();

                    while (true)
                    {
                        var result = await PotentialOutagesQueue.TryDequeueAsync();

                        if (!result.HasValue)
                        {
                            break;
                        }

                        var command = result.Value;

                        await reportingOutageClient.ReportPotentialOutage(command.ElementGid, command.CommandOriginType, command.NetworkType);

                        Logger.LogInformation($"{baseLogString} PotentianOutageCommand executed. ElementGid: 0x{command.ElementGid:X16}, OriginType: {command.CommandOriginType}");
                    }
                }
                else
                {
                    Logger.LogWarning($"{baseLogString} Notify => unexpected type of message: {message.GetType()}");
                    return;
                }
            }
            catch (Exception e)
            {
                string errorMessage = $"{baseLogString} Notify => Exception: {e.Message}";
                Logger.LogError(errorMessage, e);
            }
        }