public HashSet <string> QueryFilteredTags(string tagFilter)
        {
            if (sc == null)
            {
                MessageBox.Show("First, establish the connection with the Historian server");

                return(null);
            }
            else
            {
                Connect();

                if (!IsConnected)
                {
                    Connect();
                }

                try
                {
                    Historian.TagQueryParams queryTags = new Historian.TagQueryParams {
                        PageSize = 100
                    };                                                                                    // PageSize is the batch size of the while loop below, not recommended to set higher than 500
                    Historian.ItemErrors itemErrors = new Historian.ItemErrors();
                    Historian.DataSet    dataSet    = new Historian.DataSet();

                    List <Historian.Tag> filteredTags = new List <Historian.Tag>();
                    List <Historian.Tag> tempTags;

                    queryTags.Criteria.TagnameMask = tagFilter; //filtering tags
                    //queryTags.Criteria.DataType = Historian.Tag.NativeDataType.VariableString; //

                    //execute the query and populate the list datatype
                    while (sc.ITags.Query(ref queryTags, out tempTags))
                    {
                        filteredTags.AddRange(tempTags);
                    }
                    filteredTags.AddRange(tempTags);

                    //impossible to have two tags with the same name, but... using distinct anyway...
                    return(new HashSet <string>(filteredTags.Select(e => e.Name).Distinct().ToList()));
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Tag query error: " + ex.Message);

                    return(null);
                }
            }
        }
        public List <TagDataModel> GetBadTags(string[] plants)
        {
            var badTagDatas = new List <TagDataModel>();

            try
            {
                Connect();

                if (!IsConnected)
                {
                    Connect();
                }

                foreach (string plant in plants) //for the tagname mask
                {
                    Historian.TagQueryParams queryTags = new Historian.TagQueryParams {
                        PageSize = 500
                    };                                                                                    // PageSize is the batch size of the while loop below, not recommended to set higher than 500
                    Historian.ItemErrors itemErrors = new Historian.ItemErrors();
                    Historian.DataSet    dataSet    = new Historian.DataSet();

                    List <Historian.Tag> tagDatas = new List <Historian.Tag>();
                    List <Historian.Tag> tempTagDatas;

                    queryTags.Criteria.TagnameMask        = $"BC.{plant}*"; //tagname mask
                    queryTags.Criteria.CollectionDisabled = false;
                    queryTags.Categories = Historian.Tag.Categories.Basic;

                    while (sc.ITags.Query(ref queryTags, out tempTagDatas))
                    {
                        tagDatas.AddRange(tempTagDatas);
                    }
                    tagDatas.AddRange(tempTagDatas);

                    for (int i = 0; i < tagDatas.Count; i++)
                    {
                        var badTagData = new TagDataModel
                        {
                            TagName = tagDatas[i].Name,
                            Desc    = tagDatas[i].Description
                        };

                        badTagDatas.Add(badTagData);
                    }

                    queryTags = new Historian.TagQueryParams {
                        PageSize = 500
                    };

                    queryTags.Criteria.TagnameMask        = $"BC.{plant}*";
                    queryTags.Criteria.CollectionDisabled = false;
                    queryTags.Categories = Historian.Tag.Categories.Engineering; //for engineering units and limits

                    tagDatas.Clear();
                    tempTagDatas.Clear();

                    string[] tagNames = badTagDatas.AsEnumerable().Select(r => r.TagName).ToArray(); //get only tagnames

                    while (sc.ITags.Query(ref queryTags, out tempTagDatas))
                    {
                        tagDatas.AddRange(tempTagDatas);
                    }
                    tagDatas.AddRange(tempTagDatas);

                    for (int i = 0; i < tagDatas.Count; i++)
                    {
                        var obj = badTagDatas.FirstOrDefault(x => x.TagName == tagDatas[i].Name); //get object by tagname
                        if (obj != null)
                        {
                            obj.EGU   = tagDatas[i].EngineeringUnits;
                            obj.LoEGU = tagDatas[i].LoEngineeringUnits.ToString();
                            obj.HiEGU = tagDatas[i].HiEngineeringUnits.ToString();
                        }
                    }

                    // query the latest values
                    Historian.DataQueryParams queryValueQuality = new Historian.CurrentValueQuery(tagNames)
                    {
                        Fields = Historian.DataFields.Value | Historian.DataFields.Quality | Historian.DataFields.Time
                    };

                    sc.IData.Query(ref queryValueQuality, out dataSet, out itemErrors);

                    for (int i = 0; i < tagNames.Length; i++)
                    {
                        var obj = badTagDatas.FirstOrDefault(x => x.TagName == tagNames[i]);

                        if (obj != null)
                        {
                            obj.Value     = dataSet[tagNames[i]].GetValue(0) != null ? dataSet[tagNames[i]].GetValue(0).ToString() : "-N/A-";
                            obj.Quality   = dataSet[tagNames[i]].GetQuality(0).ToString();
                            obj.TimeStamp = dataSet[tagNames[i]].GetTime(0).ToString("yyyy.MM.dd. HH:mm:ss");
                        }
                    }

                    badTagDatas = badTagDatas.Where(x => x.Quality.Contains("Bad")).ToList(); // filter to get only BAD qulity tags
                }

                return(badTagDatas);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Tag query error: " + ex.Message);
                throw;
            }
            finally
            {
                Disconnect();
            }
        }