private async Task <AnalogMeasurement> GetPopulatedAnalogMeasurement(ResourceDescription rs)
        {
            string verboseMessage = $"{baseLogString} entering GetPopulatedAnalogMeasurement method.";

            Logger.LogVerbose(verboseMessage);

            AnalogMeasurement measurement = new AnalogMeasurement();

            try
            {
                measurement.Id            = rs.Id;
                measurement.Address       = rs.GetProperty(ModelCode.MEASUREMENT_ADDRESS).AsString();
                measurement.IsInput       = rs.GetProperty(ModelCode.MEASUREMENT_ISINPUT).AsBool();
                measurement.CurrentValue  = rs.GetProperty(ModelCode.ANALOG_CURRENTVALUE).AsFloat();
                measurement.MaxValue      = rs.GetProperty(ModelCode.ANALOG_MAXVALUE).AsFloat();
                measurement.MinValue      = rs.GetProperty(ModelCode.ANALOG_MINVALUE).AsFloat();
                measurement.NormalValue   = rs.GetProperty(ModelCode.ANALOG_NORMALVALUE).AsFloat();
                measurement.Deviation     = rs.GetProperty(ModelCode.ANALOG_DEVIATION).AsFloat();
                measurement.ScalingFactor = rs.GetProperty(ModelCode.ANALOG_SCALINGFACTOR).AsFloat();
                measurement.SignalType    = (AnalogMeasurementType)rs.GetProperty(ModelCode.ANALOG_SIGNALTYPE).AsEnum();

                var connection = await GetAllReferencedElements(rs);

                if (connection.Count < 0)
                {
                    Logger.LogError($"{baseLogString} GetPopulatedAnalogMeasurement => Analog measurement with GID: {rs.Id:X16} is not connected to any element.");
                }
                else if (connection.Count > 1)
                {
                    Logger.LogWarning($"{baseLogString} GetPopulatedAnalogMeasurement => Analog measurement with GID: {rs.Id:X16} is connected to more then one element.");

                    if (!await MeasurementToConnectedTerminalMap.ContainsKeyAsync(rs.Id))
                    {
                        await MeasurementToConnectedTerminalMap.SetAsync(rs.Id, connection.First());
                    }
                }
                else
                {
                    if (!await MeasurementToConnectedTerminalMap.ContainsKeyAsync(rs.Id))
                    {
                        await MeasurementToConnectedTerminalMap.SetAsync(rs.Id, connection.First());
                    }
                }
            }
            catch (Exception e)
            {
                Logger.LogError($"{baseLogString} GetPopulatedAnalogMeasurement => Failed to populate analog measurement with GID {rs.Id:X16}." +
                                $"{Environment.NewLine} Exception message: {e.Message}" +
                                $"{Environment.NewLine} Stack trace: {e.StackTrace}");
            }
            return(measurement);
        }
        private async Task <DiscreteMeasurement> GetPopulatedDiscreteMeasurement(ResourceDescription rs)
        {
            string verboseMessage = $"{baseLogString} entering GetPopulatedDiscreteMeasurement method.";

            Logger.LogVerbose(verboseMessage);

            DiscreteMeasurement measurement = new DiscreteMeasurement();

            try
            {
                measurement.Id              = rs.Id;
                measurement.Address         = rs.GetProperty(ModelCode.MEASUREMENT_ADDRESS).AsString();
                measurement.IsInput         = rs.GetProperty(ModelCode.MEASUREMENT_ISINPUT).AsBool();
                measurement.CurrentOpen     = rs.GetProperty(ModelCode.DISCRETE_CURRENTOPEN).AsBool();
                measurement.MaxValue        = rs.GetProperty(ModelCode.DISCRETE_MAXVALUE).AsInt();
                measurement.MinValue        = rs.GetProperty(ModelCode.DISCRETE_MINVALUE).AsInt();
                measurement.NormalValue     = rs.GetProperty(ModelCode.DISCRETE_NORMALVALUE).AsInt();
                measurement.MeasurementType = (DiscreteMeasurementType)rs.GetProperty(ModelCode.DISCRETE_MEASUREMENTTYPE).AsEnum();

                var connection = await GetAllReferencedElements(rs);

                if (connection.Count < 0)
                {
                    Logger.LogError($"{baseLogString} GetPopulatedDiscreteMeasurement => Discrete measurement with GID {rs.Id:X16} is not connected to any element.");
                }
                else if (connection.Count > 1)
                {
                    Logger.LogWarning($"{baseLogString} GetPopulatedDiscreteMeasurement => Discrete measurement with GID {rs.Id:X16} is connected to more then one element.");
                    if (!await MeasurementToConnectedTerminalMap.ContainsKeyAsync(rs.Id))
                    {
                        await MeasurementToConnectedTerminalMap.SetAsync(rs.Id, connection.First());
                    }
                }
                else
                {
                    if (!await MeasurementToConnectedTerminalMap.ContainsKeyAsync(rs.Id))
                    {
                        await MeasurementToConnectedTerminalMap.SetAsync(rs.Id, connection.First());
                    }
                }
            }
            catch (Exception e)
            {
                Logger.LogError($"[NMSManager] Failed to populate discrete measurement with GID: {rs.Id:X16}." +
                                $"{Environment.NewLine} Exception message: {e.Message}" +
                                $"{Environment.NewLine} Stack trace: {e.StackTrace}");
            }
            return(measurement);
        }
        private void PutMeasurementsInElements(IMeasurement measurement)
        {
            string message = $"[NMSManager]Putting measurement with GID 0x{measurement.Id.ToString("X16")} in element.";

            if (MeasurementToConnectedTerminalMap.TryGetValue(measurement.Id, out long terminalId))
            {
                if (TerminalToConnectedElementsMap.TryGetValue(terminalId, out List <long> connectedElements))
                {
                    try
                    {
                        var elementId = connectedElements.Find(
                            e => GetDMSTypeOfTopologyElement(e) != DMSType.CONNECTIVITYNODE &&
                            GetDMSTypeOfTopologyElement(e) != DMSType.ANALOG);

                        if (TopologyElements.TryGetValue(elementId, out ITopologyElement element))
                        {
                            element.Measurements.Add(measurement.Id, measurement.GetMeasurementType());
                            measurement.ElementId = elementId;

                            if (measurement.GetMeasurementType().Equals(AnalogMeasurementType.FEEDER_CURRENT.ToString()))
                            {
                                //element = new Feeder(element);
                                TopologyElements[elementId] = new Feeder(element);
                            }
                        }
                        else
                        {
                            logger.LogWarn($"{message} Element with GID {elementId.ToString("X")} does not exist in elements dictionary.");
                        }
                    }
                    catch (Exception)
                    {
                        logger.LogWarn($"{message} Failed to find appropriate element for mesuremnt with GID {measurement.Id.ToString("X")}. There is no conducting equipment connected to common terminal.");
                    }
                }
                else
                {
                    logger.LogWarn($"{message} Terminal with GID 0x{terminalId.ToString("X16")} does not exist in terminal to element map.");
                }
            }
            else
            {
                logger.LogWarn($"{message} Measurement with GID 0x{measurement.Id.ToString("X16")} does not exist in mesurement to terminal map.");
            }
        }
        private AnalogMeasurement GetPopulatedAnalogMeasurement(ResourceDescription rs)
        {
            AnalogMeasurement measurement = new AnalogMeasurement();

            try
            {
                measurement.Id            = rs.Id;
                measurement.Address       = rs.GetProperty(ModelCode.MEASUREMENT_ADDRESS).AsString();
                measurement.IsInput       = rs.GetProperty(ModelCode.MEASUREMENT_ISINPUT).AsBool();
                measurement.CurrentValue  = rs.GetProperty(ModelCode.ANALOG_CURRENTVALUE).AsFloat();
                measurement.MaxValue      = rs.GetProperty(ModelCode.ANALOG_MAXVALUE).AsFloat();
                measurement.MinValue      = rs.GetProperty(ModelCode.ANALOG_MINVALUE).AsFloat();
                measurement.NormalValue   = rs.GetProperty(ModelCode.ANALOG_NORMALVALUE).AsFloat();
                measurement.Deviation     = rs.GetProperty(ModelCode.ANALOG_DEVIATION).AsFloat();
                measurement.ScalingFactor = rs.GetProperty(ModelCode.ANALOG_SCALINGFACTOR).AsFloat();
                measurement.SignalType    = (AnalogMeasurementType)rs.GetProperty(ModelCode.ANALOG_SIGNALTYPE).AsEnum();

                var connection = GetAllReferencedElements(rs);
                if (connection.Count < 0)
                {
                    logger.LogWarn($"Analog measurement with GID: 0x{rs.Id:X16} is not connected to any element.");
                }
                else if (connection.Count > 1)
                {
                    logger.LogWarn($"Analog measurement with GID: 0x{rs.Id:X16} is connected to more then one element.");
                    MeasurementToConnectedTerminalMap.Add(rs.Id, connection.First());
                }
                else
                {
                    MeasurementToConnectedTerminalMap.Add(rs.Id, connection.First());
                }
            }
            catch (Exception)
            {
                logger.LogDebug($"Failed to populate analog measurement with GID: 0x{rs.Id:X16}.");
            }
            return(measurement);
        }
        private DiscreteMeasurement GetPopulatedDiscreteMeasurement(ResourceDescription rs)
        {
            DiscreteMeasurement measurement = new DiscreteMeasurement();

            try
            {
                measurement.Id              = rs.Id;
                measurement.Address         = rs.GetProperty(ModelCode.MEASUREMENT_ADDRESS).AsString();
                measurement.IsInput         = rs.GetProperty(ModelCode.MEASUREMENT_ISINPUT).AsBool();
                measurement.CurrentOpen     = rs.GetProperty(ModelCode.DISCRETE_CURRENTOPEN).AsBool();
                measurement.MaxValue        = rs.GetProperty(ModelCode.DISCRETE_MAXVALUE).AsInt();
                measurement.MinValue        = rs.GetProperty(ModelCode.DISCRETE_MINVALUE).AsInt();
                measurement.NormalValue     = rs.GetProperty(ModelCode.DISCRETE_NORMALVALUE).AsInt();
                measurement.MeasurementType = (DiscreteMeasurementType)rs.GetProperty(ModelCode.DISCRETE_MEASUREMENTTYPE).AsEnum();

                var connection = GetAllReferencedElements(rs);
                if (connection.Count < 0)
                {
                    logger.LogWarn($"[NMSManager] Discrete measurement with GID: 0x{rs.Id:X16} is not connected to any element.");
                }
                else if (connection.Count > 1)
                {
                    logger.LogWarn($"[NMSManager] Discrete measurement with GID: 0x{rs.Id:X16} is connected to more then one element.");
                    MeasurementToConnectedTerminalMap.Add(rs.Id, connection.First());
                }
                else
                {
                    MeasurementToConnectedTerminalMap.Add(rs.Id, connection.First());
                }
            }
            catch (Exception ex)
            {
                logger.LogError($"[NMSManager] Failed to populate discrete measurement with GID: 0x{rs.Id:X16}. Exception message: {ex.Message}");
            }
            return(measurement);
        }
        public bool TryGetAllModelEntities(
            out Dictionary <long, ITopologyElement> topologyElements,
            out Dictionary <long, List <long> > elementConnections,
            out HashSet <long> reclosers,
            out List <long> energySources)
        {
            TopologyElements.Clear();
            Measurements.Clear();
            EnergySources.Clear();
            ElementConnections.Clear();
            MeasurementToConnectedTerminalMap.Clear();
            TerminalToConnectedElementsMap.Clear();
            BaseVoltages.Clear();
            Reclosers.Clear();

            bool success = true;

            try
            {
                logger.LogInfo("Getting all network model elements and converting them...");
                GetBaseVoltages().Wait();
                Parallel.For(0, ConcreteModels.Count, (i) =>
                {
                    var model = ConcreteModels.ElementAt(i);
                    if (model != ModelCode.BASEVOLTAGE)
                    {
                        List <ModelCode> properties = modelResourcesDesc.GetAllPropertyIds(model);
                        var elements = networkModelGDA.GetExtentValues(model, properties).Result;
                        foreach (var element in elements)
                        {
                            TransformToTopologyElement(element);
                        }
                    }
                });

                foreach (var measurement in Measurements.Values)
                {
                    PutMeasurementsInElements(measurement);
                    Provider.Instance.MeasurementProvider.AddMeasurementElementPair(measurement.Id, measurement.ElementId);
                }

                foreach (var element in TopologyElements.Values)
                {
                    if (element.Measurements.Count == 0)
                    {
                        CreateNoScadaMeasurement(element);
                    }
                }

                topologyElements   = TopologyElements;
                elementConnections = ElementConnections;
                reclosers          = Reclosers;
                energySources      = EnergySources;
            }
            catch (Exception ex)
            {
                logger.LogError($"[NMSManager] Failed in get all network model elements. Exception message: {ex.Message}");
                topologyElements   = null;
                elementConnections = null;
                reclosers          = null;
                energySources      = null;
                success            = false;
            }
            return(success);
        }
        private async Task <long> PutMeasurementsInElements(IMeasurement measurement)
        {
            string verboseMessage = $"{baseLogString} entering PutMeasurementsInElements method. Measurement GID {measurement?.Id:X16}.";

            Logger.LogVerbose(verboseMessage);

            var enumerableMeasurementToConnectedTerminalMap = await MeasurementToConnectedTerminalMap.GetEnumerableDictionaryAsync();

            if (enumerableMeasurementToConnectedTerminalMap.TryGetValue(measurement.Id, out long terminalId))
            {
                var enumerableTerminalToConnectedElementsMap = await TerminalToConnectedElementsMap.GetEnumerableDictionaryAsync();

                if (enumerableTerminalToConnectedElementsMap.TryGetValue(terminalId, out List <long> connectedElements))
                {
                    try
                    {
                        var elementId = connectedElements.Find(
                            e => GetDMSTypeOfTopologyElement(e) != DMSType.CONNECTIVITYNODE &&
                            GetDMSTypeOfTopologyElement(e) != DMSType.ANALOG);

                        var enumerableTopologyElements = await TopologyElements.GetEnumerableDictionaryAsync();

                        if (enumerableTopologyElements.TryGetValue(elementId, out ITopologyElement element))
                        {
                            if (!element.Measurements.ContainsKey(measurement.Id))
                            {
                                element.Measurements.Add(measurement.Id, measurement.GetMeasurementType());
                            }
                            else
                            {
                                Logger.LogWarning($"{baseLogString} PutMeasurementsInElements => element.Measurements contains key: 0x{measurement.Id:X16}");
                            }

                            measurement.ElementId = elementId;

                            if (measurement is DiscreteMeasurement)
                            {
                                var measurementProviderClient = MeasurementProviderClient.CreateClient();
                                await measurementProviderClient.AddDiscreteMeasurement((DiscreteMeasurement)measurement);
                            }

                            if (measurement.GetMeasurementType().Equals(AnalogMeasurementType.FEEDER_CURRENT.ToString()))
                            {
                                await TopologyElements.SetAsync(elementId, new Feeder(element));
                            }
                            else
                            {
                                await TopologyElements.SetAsync(elementId, element);
                            }
                        }
                        else
                        {
                            Logger.LogError($"{baseLogString} PutMeasurementsInElement => Element with GID 0x{elementId:16X} does not exist in elements dictionary.");
                        }
                    }
                    catch (Exception e)
                    {
                        Logger.LogError($"{baseLogString} PutMeasurementsInElement =>  {e.Message} {Environment.NewLine} {e.StackTrace}");
                        //Logger.LogError($"{baseLogString} PutMeasurementsInElement =>  Failed to find appropriate element for mesuremnt with GID {measurement.Id:16X}. There is no conducting equipment connected to common terminal.");
                    }
                }
                else
                {
                    Logger.LogError($"{baseLogString} PutMeasurementsInElement => Terminal with GID 0x{terminalId:X16} does not exist in terminal to element map.");
                }
            }
            else
            {
                Logger.LogError($"{baseLogString} PutMeasurementsInElement => Measurement with GID {measurement.Id:X16} does not exist in mesurement to terminal map.");
            }
            return(measurement.ElementId);
        }
        public async Task <IModelDelta> TryGetAllModelEntitiesAsync()
        {
            string verboseMessage = $"{baseLogString} entering TryGetAllModelEntities method.";

            Logger.LogVerbose(verboseMessage);

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

            ModelDelta modelDelta = new ModelDelta();

            try
            {
                //var clearTasks = new List<Task>
                //{
                await TopologyElements.ClearAsync();

                await Measurements.ClearAsync();

                await EnergySources.ClearAsync();

                await ElementConnections.ClearAsync();

                await MeasurementToConnectedTerminalMap.ClearAsync();

                await TerminalToConnectedElementsMap.ClearAsync();

                await BaseVoltages.ClearAsync();

                await Reclosers.ClearAsync();

                //};

                //Task.WaitAll(clearTasks.ToArray());

                await energySources.SetAsync(ReliableDictionaryNames.EnergySources, new List <long>());

                await reclosers.SetAsync(ReliableDictionaryNames.Reclosers, new HashSet <long>());

                Logger.LogDebug($"{baseLogString} TryGetAllModelEntities => Getting all network model elements and converting them.");

                await GetBaseVoltagesAsync();

                foreach (var model in ConcreteModels)
                {
                    if (model != ModelCode.BASEVOLTAGE)
                    {
                        List <ModelCode> properties = modelResourcesDesc.GetAllPropertyIds(model);
                        var elements = await networkModelGda.GetExtentValuesAsync(model, properties);

                        foreach (var element in elements)
                        {
                            try
                            {
                                await TransformToTopologyElementAsync(element);
                            }
                            catch (Exception e)
                            {
                                Logger.LogError($"{baseLogString} TryGetAllModelEntitiesAsync failed." +
                                                $" {Environment.NewLine} {e.Message} " +
                                                $"{Environment.NewLine} {e.StackTrace}");
                            }
                        }
                    }
                }


                //Parallel.For(0, ConcreteModels.Count, async (i) =>
                //{
                //	var model = ConcreteModels.ElementAt(i);
                //	if (model != ModelCode.BASEVOLTAGE)
                //	{
                //		List<ModelCode> properties = modelResourcesDesc.GetAllPropertyIds(model);
                //		var elements = await networkModelGda.GetExtentValuesAsync(model, properties);
                //		foreach (var element in elements)
                //		{
                //			try
                //			{
                //				await TransformToTopologyElementAsync(element);
                //			}
                //			catch (Exception e)
                //			{
                //				Logger.LogError($"{baseLogString} TryGetAllModelEntitiesAsync failed." +
                //					$" {Environment.NewLine} {e.Message} " +
                //					$"{Environment.NewLine} {e.StackTrace}");
                //			}
                //		}
                //	}
                //});

                var enumerableMeasurements = await Measurements.GetEnumerableDictionaryAsync();

                List <IMeasurement> updatedMeasurements = new List <IMeasurement>(enumerableMeasurements.Count);
                foreach (var measurement in enumerableMeasurements.Values)
                {
                    var elementId = await PutMeasurementsInElements(measurement);

                    var measurementProviderClient = MeasurementProviderClient.CreateClient();
                    await measurementProviderClient.AddMeasurementElementPair(measurement.Id, elementId);

                    updatedMeasurements.Add(measurement);
                }

                foreach (var updatedMeas in updatedMeasurements)
                {
                    await Measurements.SetAsync(updatedMeas.Id, updatedMeas);
                }

                var enumerableTopologyElements = await TopologyElements.GetEnumerableDictionaryAsync();

                List <ITopologyElement> updatedElements = new List <ITopologyElement>(enumerableTopologyElements.Count);
                foreach (var element in enumerableTopologyElements.Values)
                {
                    if (element.Measurements.Count == 0)
                    {
                        await CreateNoScadaMeasurementAsync(element);

                        updatedElements.Add(element);
                    }
                }

                foreach (var updatedEl in updatedElements)
                {
                    await TopologyElements.SetAsync(updatedEl.Id, updatedEl);
                }

                modelDelta.TopologyElements   = enumerableTopologyElements;
                modelDelta.ElementConnections = await ElementConnections.GetEnumerableDictionaryAsync();

                var reclosersResult = await Reclosers.TryGetValueAsync(ReliableDictionaryNames.Reclosers);

                if (reclosersResult.HasValue)
                {
                    modelDelta.Reclosers = reclosersResult.Value;
                }
                else
                {
                    Logger.LogWarning($"{baseLogString} Reliable collection '{ReliableDictionaryNames.Reclosers}' was not defined yet. Handling...");
                    await Reclosers.SetAsync(ReliableDictionaryNames.Reclosers, new HashSet <long>());

                    modelDelta.Reclosers = new HashSet <long>();
                }

                var enegySourcesResult = await EnergySources.TryGetValueAsync(ReliableDictionaryNames.EnergySources);

                if (reclosersResult.HasValue)
                {
                    modelDelta.EnergySources = enegySourcesResult.Value;
                }
                else
                {
                    Logger.LogWarning($"{baseLogString} Reliable collection '{ReliableDictionaryNames.EnergySources}' was not defined yet. Handling...");
                    await EnergySources.SetAsync(ReliableDictionaryNames.EnergySources, new List <long>());

                    modelDelta.EnergySources = new List <long>();
                }
            }
            catch (Exception e)
            {
                string message = $"{baseLogString} TryGetAllModelEntities => Failed in get all network model elements." +
                                 $"{Environment.NewLine} Exception message: {e.Message}" +
                                 $"{Environment.NewLine} Stack trace: {e.StackTrace}";
                Logger.LogError(message);
                throw new Exception(message);
            }

            return(modelDelta);
        }