From 33ceff861f2a7f62cd874d43bc96484a26f4d4ab Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Tue, 26 Sep 2017 23:55:10 -0600 Subject: [PATCH] updates to phonebook search methods --- .../Codec/iHasDirectory.cs | 70 ++++-- .../Factory/DeviceFactory.cs | 222 +++++++++--------- .../VideoCodec/CiscoCodec/CiscoCodec.cs | 115 +++++++-- .../CiscoCodec/PhonebookDataClasses.cs | 132 ++++++++++- 4 files changed, 391 insertions(+), 148 deletions(-) diff --git a/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs b/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs index d90c03e0..6a920e82 100644 --- a/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs +++ b/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs @@ -5,26 +5,22 @@ using System.Text; using Crestron.SimplSharp; using PepperDash.Core; +using PepperDash.Essentials.Devices.Common.VideoCodec; namespace PepperDash.Essentials.Devices.Common.Codec { public interface iHasDirectory { - CodecDirectory Directory { get; } + CodecDirectory DirectoryRoot { get; } - /// - /// Searches the directory and returns a result - /// - /// - /// - void SearchDirectory(string searchString, string key); + void SearchDirectory(string searchString); + + void GetFolderContents(string folderId); } public class CodecDirectory { - public List Folders {get; private set;} - - public List Contacts { get; private set; } + public List DirectoryResults { get; private set; } public int Offset { get; private set; } @@ -32,16 +28,57 @@ namespace PepperDash.Essentials.Devices.Common.Codec public CodecDirectory() { - Folders = new List(); - Contacts = new List(); + DirectoryResults = new List(); + } + + public void AddFoldersToDirectory(List folders) + { + DirectoryResults.AddRange(folders); + + SortDirectory(); + } + + public void AddContactsToDirectory(List contacts) + { + DirectoryResults.AddRange(contacts); + + SortDirectory(); + } + + /// + /// Formats the DirectoryResults list to display all folders alphabetically, then all contacts alphabetically + /// + private void SortDirectory() + { + var sortedFolders = new List(); + + sortedFolders.AddRange(DirectoryResults.Where(f => f is DirectoryFolder)); + + sortedFolders.OrderBy(f => f.Name); + + var sortedContacts = new List(); + + sortedContacts.AddRange(DirectoryResults.Where(c => c is DirectoryContact)); + + sortedFolders.OrderBy(c => c.Name); + + DirectoryResults.Clear(); + + DirectoryResults.AddRange(sortedFolders); + + DirectoryResults.AddRange(sortedContacts); } } - public class DirectoryFolder + public class DirectoryItem + { + public string Name { get; set; } + } + + public class DirectoryFolder : DirectoryItem { public List Contacts { get; set; } public string FolderId { get; set; } - public string Name { get; set; } public DirectoryFolder ParentFolder { get; set; } public DirectoryFolder() @@ -51,11 +88,10 @@ namespace PepperDash.Essentials.Devices.Common.Codec } } - public class DirectoryContact + public class DirectoryContact : DirectoryItem { public string ContactId { get; set; } - public DirectoryFolder Folder { get; set; } - public string Name { get; set; } + public string FolderId { get; set; } public string Title { get; set; } public List ContactMethods { get; set; } } diff --git a/Essentials Devices Common/Essentials Devices Common/Factory/DeviceFactory.cs b/Essentials Devices Common/Essentials Devices Common/Factory/DeviceFactory.cs index e8dedd90..1dc88996 100644 --- a/Essentials Devices Common/Essentials Devices Common/Factory/DeviceFactory.cs +++ b/Essentials Devices Common/Essentials Devices Common/Factory/DeviceFactory.cs @@ -1,110 +1,110 @@ -using System; -using System.Collections.Generic; -using Crestron.SimplSharp; -using Crestron.SimplSharp.CrestronIO; -using Crestron.SimplSharpPro; - -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Config; - +using System; +using System.Collections.Generic; +using Crestron.SimplSharp; +using Crestron.SimplSharp.CrestronIO; +using Crestron.SimplSharpPro; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; + using PepperDash.Essentials.Devices.Common.DSP; -using PepperDash.Essentials.Devices.Common.VideoCodec; - -using PepperDash.Essentials.Devices.Common; - -namespace PepperDash.Essentials.Devices.Common -{ - public class DeviceFactory - { - public static IKeyed GetDevice(DeviceConfig dc) - { - var key = dc.Key; - var name = dc.Name; - var type = dc.Type; - var properties = dc.Properties; - - var typeName = dc.Type.ToLower(); - var groupName = dc.Group.ToLower(); - - if (typeName == "appletv") - { - //var ir = IRPortHelper.GetIrPort(properties); - //if (ir != null) - // return new AppleTV(key, name, ir.Port, ir.FileName); - - var irCont = IRPortHelper.GetIrOutputPortController(dc); - return new AppleTV(key, name, irCont); - } - - else if (typeName == "basicirdisplay") - { - var ir = IRPortHelper.GetIrPort(properties); - if (ir != null) - return new BasicIrDisplay(key, name, ir.Port, ir.FileName); - } - - else if (typeName == "biamptesira") - { - var comm = CommFactory.CreateCommForDevice(dc); - var props = JsonConvert.DeserializeObject( - properties.ToString()); - return new BiampTesiraForteDsp(key, name, comm, props); - } - - else if (typeName == "cenrfgwex") - { - return CenRfgwController.GetNewExGatewayController(key, name, - properties.Value("id"), properties.Value("gatewayType")); - } - - else if (typeName == "cenerfgwpoe") - { - return CenRfgwController.GetNewErGatewayController(key, name, - properties.Value("id"), properties.Value("gatewayType")); - } - - else if (groupName == "discplayer") // (typeName == "irbluray") - { - if (properties["control"]["method"].Value() == "ir") - { - var irCont = IRPortHelper.GetIrOutputPortController(dc); - return new IRBlurayBase(key, name, irCont); - } - else if (properties["control"]["method"].Value() == "com") - { - Debug.Console(0, "[{0}] COM Device type not implemented YET!", key); - } - } - - else if (typeName == "genericaudiooutwithvolume") - { - var zone = dc.Properties.Value("zone"); - return new GenericAudioOutWithVolume(key, name, - dc.Properties.Value("volumeDeviceKey"), zone); - } - - else if (groupName == "genericsource") - { - return new GenericSource(key, name); - } - - else if (typeName == "inroompc") - { - return new InRoomPc(key, name); - } - - else if (typeName == "laptop") - { - return new Laptop(key, name); - } - - else if (typeName == "mockvc") - { - return new PepperDash.Essentials.Devices.Common.VideoCodec - .MockVC(key, name); +using PepperDash.Essentials.Devices.Common.VideoCodec; + +using PepperDash.Essentials.Devices.Common; + +namespace PepperDash.Essentials.Devices.Common +{ + public class DeviceFactory + { + public static IKeyed GetDevice(DeviceConfig dc) + { + var key = dc.Key; + var name = dc.Name; + var type = dc.Type; + var properties = dc.Properties; + + var typeName = dc.Type.ToLower(); + var groupName = dc.Group.ToLower(); + + if (typeName == "appletv") + { + //var ir = IRPortHelper.GetIrPort(properties); + //if (ir != null) + // return new AppleTV(key, name, ir.Port, ir.FileName); + + var irCont = IRPortHelper.GetIrOutputPortController(dc); + return new AppleTV(key, name, irCont); + } + + else if (typeName == "basicirdisplay") + { + var ir = IRPortHelper.GetIrPort(properties); + if (ir != null) + return new BasicIrDisplay(key, name, ir.Port, ir.FileName); + } + + else if (typeName == "biamptesira") + { + var comm = CommFactory.CreateCommForDevice(dc); + var props = JsonConvert.DeserializeObject( + properties.ToString()); + return new BiampTesiraForteDsp(key, name, comm, props); + } + + else if (typeName == "cenrfgwex") + { + return CenRfgwController.GetNewExGatewayController(key, name, + properties.Value("id"), properties.Value("gatewayType")); + } + + else if (typeName == "cenerfgwpoe") + { + return CenRfgwController.GetNewErGatewayController(key, name, + properties.Value("id"), properties.Value("gatewayType")); + } + + else if (groupName == "discplayer") // (typeName == "irbluray") + { + if (properties["control"]["method"].Value() == "ir") + { + var irCont = IRPortHelper.GetIrOutputPortController(dc); + return new IRBlurayBase(key, name, irCont); + } + else if (properties["control"]["method"].Value() == "com") + { + Debug.Console(0, "[{0}] COM Device type not implemented YET!", key); + } + } + + else if (typeName == "genericaudiooutwithvolume") + { + var zone = dc.Properties.Value("zone"); + return new GenericAudioOutWithVolume(key, name, + dc.Properties.Value("volumeDeviceKey"), zone); + } + + else if (groupName == "genericsource") + { + return new GenericSource(key, name); + } + + else if (typeName == "inroompc") + { + return new InRoomPc(key, name); + } + + else if (typeName == "laptop") + { + return new Laptop(key, name); + } + + else if (typeName == "mockvc") + { + return new PepperDash.Essentials.Devices.Common.VideoCodec + .MockVC(key, name); } else if (typeName == "ciscocodec") @@ -131,9 +131,9 @@ namespace PepperDash.Essentials.Devices.Common { var irCont = IRPortHelper.GetIrOutputPortController(dc); return new Roku2(key, name, irCont); - } - - return null; - } - } + } + + return null; + } + } } \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs index 43687cee..55bf355c 100644 --- a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs +++ b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs @@ -14,13 +14,16 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Devices.Common.Codec; +using PepperDash.Essentials.Devices.Common.VideoCodec; namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { enum eCommandType { SessionStart, SessionEnd, Command, GetStatus, GetConfiguration }; - public class CiscoCodec : VideoCodecBase, IHasCallHistory, iHasCallFavorites + public class CiscoCodec : VideoCodecBase, IHasCallHistory, iHasCallFavorites, iHasDirectory { + public event EventHandler UpcomingMeetingWarning; + public IBasicCommunication Communication { get; private set; } public CommunicationGather PortGather { get; private set; } public CommunicationGather JsonGather { get; private set; } @@ -43,13 +46,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco private CiscoCodecStatus.RootObject CodecStatus; - private CiscoCodecPhonebook.RootObject CodecPhonebook; + //private CiscoCodecPhonebook.RootObject CodecPhonebook; public CodecCallHistory CallHistory { get; private set; } public CodecCallFavorites CallFavorites { get; private set; } - public CodecDirectory Directory { get; private set; } + public CodecDirectory DirectoryRoot { get; private set; } /// /// Gets and returns the scaled volume of the codec @@ -199,14 +202,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco CodecConfiguration = new CiscoCodecConfiguration.RootObject(); CodecStatus = new CiscoCodecStatus.RootObject(); - CodecPhonebook = new CiscoCodecPhonebook.RootObject(); CallHistory = new CodecCallHistory(); CallFavorites = new CodecCallFavorites(); CallFavorites.Favorites = props.Favorites; - Directory = new CodecDirectory(); + DirectoryRoot = new CodecDirectory(); //Set Feedback Actions CodecStatus.Status.Audio.Volume.ValueChangedAction = VolumeLevelFeedback.FireUpdate; @@ -268,7 +270,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco // Get bookings for the day //SendText("xCommand Bookings List Days: 1 DayOffset: 0"); - GetPhonebook(); + GetPhonebookFolders(); } public void SetCommDebug(string s) @@ -512,20 +514,40 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } else if (response.IndexOf("\"PhonebookSearchResult\":{") > -1) { - JsonConvert.PopulateObject(response, CodecPhonebook); + var codecPhonebook = new CiscoCodecPhonebook.RootObject(); if (!PhonebookSyncState.InitialPhonebookMessageWasReceived) { + // Check if the phonebook has any folders PhonebookSyncState.InitialPhonebookMessageReceived(); - PhonebookSyncState.SetPhonebookHasFolders(CodecPhonebook.CommandResponse.PhonebookSearchResult.Folder.Count > 0); + PhonebookSyncState.SetPhonebookHasFolders(codecPhonebook.CommandResponse.PhonebookSearchResult.Folder.Count > 0); + + if (PhonebookSyncState.PhonebookHasFolders) + { + DirectoryRoot.AddFoldersToDirectory(CiscoCodecPhonebook.GetRootFoldersFromSearchResult(codecPhonebook.CommandResponse.PhonebookSearchResult)); + } + + // Get the number of contacts in the phonebook + GetPhonebookContacts(); } - - Directory = CiscoCodecPhonebook.ConvertCiscoPhonebookToGeneric(CodecPhonebook.CommandResponse.PhonebookSearchResult); - - if (Debug.Level > 1) + else if (!PhonebookSyncState.NumberOfContactsWasReceived) { - //Print phonebook contents + // Store the total number of contacts in the phonebook + PhonebookSyncState.SetNumberOfContacts(Int32.Parse(codecPhonebook.CommandResponse.PhonebookSearchResult.ResultInfo.TotalRows.Value)); + + DirectoryRoot.AddContactsToDirectory(CiscoCodecPhonebook.GetRootContactsFromSearchResult(codecPhonebook.CommandResponse.PhonebookSearchResult)); + } + else if (PhonebookSyncState.InitialSyncComplete) + { + JsonConvert.PopulateObject(response, codecPhonebook); + + if (Debug.Level > 1) + { + //Print phonebook contents + } + + // Fire some sort of callback delegate to the UI that requested the directory search results } } else if (response.IndexOf("\"BookingsListResult\":{") > -1) @@ -598,10 +620,34 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco SendText("xCommand CallHistory Recents Limit: 20 Order: OccurrenceTime"); } - private void GetPhonebook() + private void GetPhonebookFolders() { // Get Phonebook Folders (determine local/corporate from config, and set results limit) - SendText(string.Format("xCommand Phonebook Search PhonebookType: {0} ContactType: Folder Limit: {1}", PhonebookMode, PhonebookResultsLimit)); + SendText(string.Format("xCommand Phonebook Search PhonebookType: {0} ContactType: Folder", PhonebookMode)); + } + + private void GetPhonebookContacts() + { + // Get Phonebook Folders (determine local/corporate from config, and set results limit) + SendText(string.Format("xCommand Phonebook Search PhonebookType: {0} ContactType: Contact", PhonebookMode)); + } + + /// + /// Searches the codec phonebook for all contacts matching the search string + /// + /// + public void SearchDirectory(string searchString) + { + SendText(string.Format("xCommand Phonebook Search SearchString: \"{0}\" PhonebookType: {1} ContactType: Contact, Limit: {2}", searchString, PhonebookMode, PhonebookResultsLimit)); + } + + /// + /// // Get contents of a specific folder in the phonebook + /// + /// + public void GetFolderContents(string folderId) + { + SendText(string.Format("xCommand Phonebook Search FolderId: {0} PhonebookType: {1} ContactType: Contact, Limit: {2}", folderId, PhonebookMode, PhonebookResultsLimit)); } public override void Dial(string s) @@ -857,14 +903,41 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } } + /// + /// Used to track the status of syncronizing the phonebook values when connecting to a codec or refreshing the phonebook info + /// public class CodecPhonebookSyncState : IKeyed { + bool _InitialSyncComplete; + + public event EventHandler InitialSyncCompleted; + public string Key { get; private set; } + public bool InitialSyncComplete + { + get { return _InitialSyncComplete; } + private set + { + if (value == true) + { + var handler = InitialSyncCompleted; + if (handler != null) + handler(this, new EventArgs()); + } + _InitialSyncComplete = value; + } + } + + public bool InitialPhonebookMessageWasReceived { get; private set; } + public bool NumberOfContactsWasReceived { get; private set; } + public bool PhonebookHasFolders { get; private set; } + public int NumberOfContacts { get; private set; } + public CodecPhonebookSyncState(string key) { Key = key; @@ -880,12 +953,24 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public void SetPhonebookHasFolders(bool value) { PhonebookHasFolders = value; + + Debug.Console(1, this, "Phonebook has folders: {0}", PhonebookHasFolders); + } + + public void SetNumberOfContacts(int contacts) + { + NumberOfContacts = contacts; + NumberOfContactsWasReceived = true; + + Debug.Console(1, this, "Phonebook contains {0} contacts.", NumberOfContacts); } public void CodecDisconnected() { InitialPhonebookMessageWasReceived = false; PhonebookHasFolders = false; + NumberOfContacts = 0; + NumberOfContactsWasReceived = false; } } diff --git a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/PhonebookDataClasses.cs b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/PhonebookDataClasses.cs index 50809a6d..a5be6309 100644 --- a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/PhonebookDataClasses.cs +++ b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/PhonebookDataClasses.cs @@ -147,6 +147,122 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } + + /// + /// Extracts the folders with no ParentFolder and returns them sorted alphabetically + /// + /// + /// + public static List GetRootFoldersFromSearchResult(PhonebookSearchResult result) + { + var rootFolders = new List(); + + if (result.Folder.Count > 0) + { + return null; + } + else if (result.Folder.Count > 0) + { + if (Debug.Level > 1) + Debug.Console(1, "Phonebook Folders:\n"); + + foreach (Folder f in result.Folder) + { + var folder = new DirectoryFolder(); + + folder.Name = f.Name.Value; + folder.FolderId = f.FolderId.Value; + + if (f.ParentFolderId == null) + rootFolders.Add(folder); + + if (Debug.Level > 1) + Debug.Console(1, "+ {0}", folder.Name); + } + } + + rootFolders.OrderBy(f => f.Name); + + return rootFolders; + } + + + public static List GetRootContactsFromSearchResult(PhonebookSearchResult result) + { + var rootContacts = new List(); + + if (result.Contact.Count == 0) + { + return null; + } + else if (result.Contact.Count > 0) + { + if (Debug.Level > 1) + Debug.Console(1, "Root Contacts:\n"); + + foreach (Contact c in result.Contact) + { + var contact = new DirectoryContact(); + + + if (c.FolderId == null) + { + contact.Name = c.Name.Value; + contact.ContactId = c.ContactId.Value; + contact.Title = c.Title.Value; + contact.FolderId = c.FolderId.Value; + + if (Debug.Level == 1) + Debug.Console(1, "{0}\nContact Methods:", contact.Name); + + foreach (ContactMethod m in c.ContactMethod) + { + eContactMethodCallType callType = eContactMethodCallType.Unknown; + if (m.CallType != null) + { + if (m.CallType.Value.ToLower() == "audio") + callType = eContactMethodCallType.Audio; + else if (m.CallType.Value.ToLower() == "video") + callType = eContactMethodCallType.Video; + } + + eContactMethodDevice device = eContactMethodDevice.Unknown; + + if (m.Device.Value.ToLower() == "mobile") + device = eContactMethodDevice.Mobile; + else if (m.Device.Value.ToLower() == "telephone") + device = eContactMethodDevice.Telephone; + else if (m.Device.Value.ToLower() == "video") + device = eContactMethodDevice.Video; + else if (m.Device.Value.ToLower() == "other") + device = eContactMethodDevice.Other; + + if (Debug.Level > 1) + Debug.Console(1, "Number: {0} CallType: {1} Device: {2}", m.Number.Value, callType, device); + + contact.ContactMethods.Add(new PepperDash.Essentials.Devices.Common.Codec.ContactMethod() + { + Number = m.Number.Value, + ContactMethodId = m.ContactMethodId.Value, + CallType = callType, + Device = device + }); + } + + rootContacts.Add(contact); + } + + if (Debug.Level == 1) + Debug.Console(1, "{0}", contact.Name); + } + } + + rootContacts.OrderBy(f => f.Name); + + return rootContacts; + } + + /// /// Converts data returned from a cisco codec to the generic Directory format. /// @@ -154,8 +270,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public static CodecDirectory ConvertCiscoPhonebookToGeneric(PhonebookSearchResult result) { + +#warning Modify this to return a flat list of mixed folders/contacts var directory = new Codec.CodecDirectory(); + var folders = new List(); + + var contacts = new List(); + if (result.Folder.Count > 0) { foreach (Folder f in result.Folder) @@ -167,11 +289,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec if (f.ParentFolderId != null) { - - folder.ParentFolder = directory.Folders.FirstOrDefault(fld => fld.FolderId.Equals(f.ParentFolderId.Value)); + // + folder.ParentFolder = folders.FirstOrDefault(fld => fld.FolderId.Equals(f.ParentFolderId.Value)); } - directory.Folders.Add(folder); + folders.Add(folder); } } @@ -188,7 +310,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec // Go find the folder to which this contact belongs and store it if(!string.IsNullOrEmpty(c.FolderId.Value)) { - contact.Folder = directory.Folders.FirstOrDefault(f => f.FolderId.Equals(c.FolderId.Value)); + //contact.Folder = directory.Folders.FirstOrDefault(f => f.FolderId.Equals(c.FolderId.Value)); } foreach (ContactMethod m in c.ContactMethod) @@ -221,7 +343,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec Device = device }); } - directory.Contacts.Add(contact); + //directory.Contacts.Add(contact); } }