using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; using C4IT.FASD.Base; using C4IT.FASD.Cockpit.Communication; using C4IT.MultiLanguage; using FasdDesktopUi.Basics.Services.RelationService; using FasdDesktopUi.Basics.Services.SupportCaseSearchService; using static C4IT.Logging.cLogManager; namespace FasdDesktopUi.Basics { public interface ISearchUiProvider { SupportCaseSearchService SearchService { get; } void SetSearchHistoryVisibility(bool isVisible); void ShowLoadingTextItem(string itemText); void ShowSearchRelations(cSearchHistorySearchResultEntry SearchHistoryEntry, IRelationService relationService, ISearchUiProvider SearchUiProvider); void SetPendingInformationClasses(HashSet informationClasses); void UpdatePendingInformationClasses(HashSet informationClasses); } public class cSearchManager { public const int constMaxHistoryEntryCount = 5; // max. number of entries in the search result history public const int RefreshPeriod = 60; // time in seconds until the data should be refreshed private static cSearchManager _Instance = null; public static cSearchManager Instance { get { return (_Instance is null) ? _Instance = new cSearchManager() : _Instance; } } public List HistoryList { get; private set; } = new List(); private cSearchManager() { } public void AddEntry(cSearchHistoryEntryBase Entry) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { // restict the max. history length while (HistoryList.Count >= constMaxHistoryEntryCount) HistoryList.RemoveAt(0); // check if we have already the same entry in the list cSearchHistoryEntryBase alreadyExists = null; foreach (var _entry in HistoryList) if (_entry.DisplayText == Entry.DisplayText) { alreadyExists = _entry; break; } // and remove the duplacated entry if (alreadyExists != null) HistoryList.Remove(alreadyExists); // and the new entry at least HistoryList.Add(Entry); } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } } public void ReplaceEntry(cSearchHistoryEntryBase Entry, cSearchHistoryEntryBase EntryToReplace) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { HistoryList.Remove(EntryToReplace); AddEntry(Entry); } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } } private class cUserInfo { internal string account; internal string domain; internal string type; public override bool Equals(object obj) { if (this is null && obj is null) return true; if (this is null || obj is null) return false; if (!(obj is cUserInfo userInfo)) return false; return (type == userInfo.type && account == userInfo.account && domain == userInfo.domain); } public override int GetHashCode() { return base.GetHashCode(); } } private static cUserInfo GetUserInfo(cF4sdApiSearchResultRelation searchRelation) { try { if (searchRelation?.Infos is null) return null; searchRelation.Infos.TryGetValue("UserAccountType", out var _accountType); searchRelation.Infos.TryGetValue("UserAccount", out var _account); searchRelation.Infos.TryGetValue("UserDomain", out var _domain); switch (searchRelation.Type) { case enumF4sdSearchResultClass.User: if (string.IsNullOrEmpty(_account)) searchRelation.Infos.TryGetValue("account", out _account); if (string.IsNullOrEmpty(_domain)) searchRelation.Infos.TryGetValue("domain", out _domain); break; case enumF4sdSearchResultClass.Computer: case enumF4sdSearchResultClass.MobileDevice: case enumF4sdSearchResultClass.VirtualSession: if (string.IsNullOrEmpty(_account)) searchRelation.Infos.TryGetValue("relation_account", out _account); if (string.IsNullOrEmpty(_domain)) searchRelation.Infos.TryGetValue("relation_domain", out _domain); break; default: return null; } return new cUserInfo() { account = _account, domain = _domain, type = _accountType }; } catch (Exception E) { LogException(E); } return null; } /// /// Add identifier to relation name, if there are relations with different user infos. /// /// internal static void ResolveRelations(List relations) { try { cUserInfo firstUserInfo = null; var resolveAccount = false; foreach (var relation in relations) { relation.DisplayName = relation.Name; if (relation.Type is enumF4sdSearchResultClass.Ticket) continue; var userInfo = GetUserInfo(relation); if (firstUserInfo is null) firstUserInfo = userInfo; resolveAccount = resolveAccount || !firstUserInfo.Equals(userInfo); } if (!resolveAccount) return; foreach (var relation in relations) { if (relation.Type is enumF4sdSearchResultClass.Ticket || relation.Type is enumF4sdSearchResultClass.VirtualSession || relation.Type is enumF4sdSearchResultClass.MobileDevice) continue; string relationName = relation.Name; var userInfo = GetUserInfo(relation); switch (userInfo.type) { case "Local": relationName = cMultiLanguageSupport.GetItem("UserSerach.AdvancedInfo.LocalUser"); break; case "Azure": relationName = cMultiLanguageSupport.GetItem("UserSerach.AdvancedInfo.AzureUser"); break; default: relationName = cMultiLanguageSupport.GetItem("UserSerach.AdvancedInfo.AdUser"); break; } relationName = string.Format(relationName, relation.DisplayName, userInfo.account, userInfo.domain); relation.DisplayName = relationName; } } catch (Exception ex) { LogException(ex); } } public static async Task> GetCaseRelationsAsync(List SearchResults, cF4sdApiSearchResultRelation CaseRelation = null) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { var firstSearchResultData = SearchResults.First(); // get SearchResult relation data var CaseRelations = await cFasdCockpitCommunicationBase.Instance.GetSearchResultRelations(firstSearchResultData.Type, SearchResults); // add the passed CaseRelation if it not within the result var addRelation = CaseRelation != null; if (addRelation) foreach (var _caseRelation in CaseRelations) { if (_caseRelation.isEqual(CaseRelation)) { addRelation = false; break; } } if (addRelation) CaseRelations.Add(CaseRelation); // if we have no relation, create a 'dummy' relation to relate to the search result itself if (CaseRelations?.Count == 0) { var _dummyRelation = new cF4sdApiSearchResultRelation(firstSearchResultData); CaseRelations.Add(_dummyRelation); } if (CaseRelations?.Count > 0) CaseRelations = CaseRelations.OrderByDescending(relation => relation.Type) .ThenBy(relation => relation.LastUsed) .ThenBy(relation => relation.UsingLevel) .ToList(); return CaseRelations; } catch (Exception E) { LogException(E); } finally { LogMethodEnd(CM); } return null; } } public abstract class cSearchHistoryEntryBase { public string DisplayText { get; private set; } public bool isSeen { get; set; } = false; protected DateTime LastRefresh = DateTime.MinValue; public List SelectedSearchResult { get; private set; } public List Relations { get; protected set; } public ISearchUiProvider SearchUiProvider { get; private set; } public cSearchHistoryEntryBase(string DisplayText, List selectedSearchResult, List relations, ISearchUiProvider SearchUiProvider) { this.DisplayText = DisplayText; this.isSeen = isSeen; this.SelectedSearchResult = selectedSearchResult; this.Relations = relations; this.SearchUiProvider = SearchUiProvider; LastRefresh = DateTime.UtcNow; } public abstract Task RefreshAsync(); public bool ShouldRefresh() { return (DateTime.UtcNow - LastRefresh).TotalSeconds > cSearchManager.RefreshPeriod; } } public class cSearchHistorySearchResultEntry : cSearchHistoryEntryBase { public string HeaderText { get; private set; } public cSearchHistorySearchResultEntry(string DisplayText, string HeaderText, List selectedSearchResult, List relations, ISearchUiProvider SearchUiProvider) : base(DisplayText, selectedSearchResult, relations, SearchUiProvider) { this.HeaderText = HeaderText; LastRefresh = DateTime.UtcNow; } public async override Task RefreshAsync() { if (ShouldRefresh()) { var RetVal = await cSearchManager.GetCaseRelationsAsync(SelectedSearchResult); if (RetVal != null) { Relations = RetVal; LastRefresh = DateTime.UtcNow; } } } } public class cSearchHistoryRelationEntry : cSearchHistoryEntryBase { public cF4sdApiSearchResultRelation SelectedRelation { get; private set; } public cSearchHistoryRelationEntry(string DisplayText, List selectedSearchResult, List relations, cF4sdApiSearchResultRelation selectedRealtion, ISearchUiProvider SearchUiProvider) : base(DisplayText, selectedSearchResult, relations, SearchUiProvider) { SelectedRelation = selectedRealtion; } public async override Task RefreshAsync() { if (ShouldRefresh()) { var RetVal = await cSearchManager.GetCaseRelationsAsync(SelectedSearchResult, SelectedRelation); if (RetVal != null) { Relations = RetVal; LastRefresh = DateTime.UtcNow; } } } } }