//******************************************************************************************************
// Devices.cs - Gbtc
//
// Copyright © 2010, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://www.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 05/06/2011 - Mehulbhai P Thakkar
// Generated original version of source code.
//
//******************************************************************************************************
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using GSF.PhasorProtocols.UI.DataModels;
using GSF.PhasorProtocols.UI.Modal;
using GSF.PhasorProtocols.UI.UserControls;
using GSF.TimeSeries.UI;
using GSF.TimeSeries.UI.Commands;
using GSF.TimeSeries.UI.DataModels;
namespace GSF.PhasorProtocols.UI.ViewModels
{
///
/// Class to hold bindable collection and current selection information for UI.
///
internal class Devices : PagedViewModelBase
{
#region [ Members ]
// Fields
private Dictionary m_nodeLookupList;
private Dictionary m_concentratorDeviceLookupList;
private Dictionary m_companyLookupList;
private Dictionary m_historianLookupList;
private Dictionary m_interconnectionLookupList;
private Dictionary m_protocolLookupList;
private Dictionary m_vendorDeviceLookupList;
private Dictionary m_timezoneLookupList;
private RelayCommand m_editCommand;
private RelayCommand m_phasorCommand;
private RelayCommand m_measurementCommand;
private RelayCommand m_copyCommand;
private RelayCommand m_initializeCommand;
private RelayCommand m_buildConnectionStringCommand;
private RelayCommand m_buildAlternateCommandChannelCommand;
private RelayCommand m_updateConfigurationCommand;
private RelayCommand m_configureConcentratorCommand;
private string m_runtimeID;
//private ObservableCollection m_devices;
private RelayCommand m_searchCommand;
private RelayCommand m_showAllCommand;
private bool m_stayOnConfigurationScreen;
private ObservableCollection m_pdcDevices;
private string m_searchText;
private IList m_allKeys;
#endregion
#region [ Constructors ]
///
/// Creates an instance of class.
///
///
///
/// to be edited.
public Devices(int itemsPerPage, bool autoSave = true, Device device = null)
: base(itemsPerPage, autoSave)
{
// When device is null, user wants to edit existing device's configuration. So we will load that by default.
if ((object)device != null)
{
CurrentItem = device;
OnPropertyChanged("IsNewRecord");
OnPropertyChanged("CanGoToPhasorOrMeasurement");
if (device.IsConcentrator)
PdcDevices = Device.GetDevices(null, "WHERE ParentID = " + device.ID);
}
}
#endregion
#region [ Properties ]
///
/// Gets or sets to build connection string.
///
public ICommand BuildConnectionStringCommand
{
get
{
if ((object)m_buildConnectionStringCommand == null)
m_buildConnectionStringCommand = new RelayCommand(BuildConnectionString);
return m_buildConnectionStringCommand;
}
}
///
/// Gets or sets to build alternate command channel.
///
public ICommand BuildAlternateCommandChannelCommand
{
get
{
if ((object)m_buildAlternateCommandChannelCommand == null)
m_buildAlternateCommandChannelCommand = new RelayCommand(BuildAlternateCommandChannel);
return m_buildAlternateCommandChannelCommand;
}
}
///
/// Gets or sets RuntimeID.
///
public string RuntimeID
{
get
{
return m_runtimeID;
}
set
{
m_runtimeID = value;
OnPropertyChanged("RuntimeID");
}
}
///
/// Gets type collection of defined in the database.
///
public Dictionary NodeLookupList
{
get
{
return m_nodeLookupList;
}
}
///
/// Gets type collection of concentrator defined in the database.
///
public Dictionary ConcentratorDeviceLookupList
{
get
{
return m_concentratorDeviceLookupList;
}
}
///
/// Gets type collection of defined in the database.
///
public Dictionary CompanyLookupList
{
get
{
return m_companyLookupList;
}
}
///
/// Gets type collection of defined in the database.
///
public Dictionary HistorianLookupList
{
get
{
return m_historianLookupList;
}
}
///
/// Gets type collection of defined in the database.
///
public Dictionary InterconnectionLookupList
{
get
{
return m_interconnectionLookupList;
}
}
///
/// Gets type collection of defined in the database.
///
public Dictionary ProtocolLookupList
{
get
{
return m_protocolLookupList;
}
}
///
/// Gets type collection of defined in the database.
///
public Dictionary VendorDeviceLookupList
{
get
{
return m_vendorDeviceLookupList;
}
}
///
/// Gets type collection of system time zones.
///
public Dictionary TimezoneLookupList
{
get
{
return m_timezoneLookupList;
}
}
///
/// Gets flag that determines if is a new record.
///
public override bool IsNewRecord
{
get
{
return CurrentItem.ID == 0;
}
}
///
/// Gets for edit operation.
///
public ICommand EditCommand
{
get
{
if ((object)m_editCommand == null)
m_editCommand = new RelayCommand(GoToEdit);
return m_editCommand;
}
}
///
/// Gets for copy operation.
///
public ICommand CopyCommand
{
get
{
if ((object)m_copyCommand == null)
m_copyCommand = new RelayCommand(MakeCopy);
return m_copyCommand;
}
}
///
/// Gets for updating configuration.
///
public ICommand UpdateConfigurationCommand
{
get
{
if ((object)m_updateConfigurationCommand == null)
m_updateConfigurationCommand = new RelayCommand(UpdateConfiguration);
return m_updateConfigurationCommand;
}
}
///
/// Gets to go to phasors configuration.
///
public ICommand PhasorCommand
{
get
{
if ((object)m_phasorCommand == null)
m_phasorCommand = new RelayCommand(GoToPhasors, () => CanGoToPhasorOrMeasurement);
return m_phasorCommand;
}
}
///
/// Gets a boolean flag indicating if Phasors and Measurements button are visible or not.
///
public bool CanGoToPhasorOrMeasurement
{
get
{
return CurrentItem.ID > 0;
}
}
///
/// Gets to go to measurements configuration.
///
public ICommand MeasurementCommand
{
get
{
if ((object)m_measurementCommand == null)
m_measurementCommand = new RelayCommand(GoToMeasurements, () => CanGoToPhasorOrMeasurement);
return m_measurementCommand;
}
}
///
/// Gets to send Initialize command to backed service.
///
public ICommand InitializeCommand
{
get
{
if ((object)m_initializeCommand == null)
m_initializeCommand = new RelayCommand(InitializeDevice, () => CanSave);
return m_initializeCommand;
}
}
///
/// Gets to search within measurements.
///
public ICommand SearchCommand
{
get
{
if ((object)m_searchCommand == null)
m_searchCommand = new RelayCommand(Search, param => true);
return m_searchCommand;
}
}
///
/// Gets to show all measurements.
///
public ICommand ShowAllCommand
{
get
{
if ((object)m_showAllCommand == null)
m_showAllCommand = new RelayCommand(ShowAll);
return m_showAllCommand;
}
}
public ICommand ConfigureConcentratorCommand
{
get
{
if ((object)m_configureConcentratorCommand == null)
m_configureConcentratorCommand = new RelayCommand(ConfigureConcentrator);
return m_configureConcentratorCommand;
}
}
public ObservableCollection PdcDevices
{
get
{
return m_pdcDevices;
}
set
{
m_pdcDevices = value;
OnPropertyChanged("PdcDevices");
}
}
public IList AllKeys
{
get
{
if ((object)m_allKeys == null)
m_allKeys = Device.LoadKeys(null, 0, "", SortMember, SortDirection);
return m_allKeys;
}
set
{
m_allKeys = value;
}
}
#endregion
#region [ Methods ]
///
/// Gets the primary key value of the .
///
/// The primary key value of the .
public override int GetCurrentItemKey()
{
return CurrentItem.ID;
}
///
/// Gets the string based named identifier of the .
///
/// The string based named identifier of the .
public override string GetCurrentItemName()
{
return CurrentItem.Name;
}
///
/// Creates a new instance of and assigns it to CurrentItem.
///
public override void Clear()
{
base.Clear();
// Reset all the dropdown fields so that first item displays as selected.
if (m_nodeLookupList.Count > 0)
CurrentItem.NodeID = m_nodeLookupList.First().Key;
if (m_concentratorDeviceLookupList.Count > 0)
CurrentItem.ParentID = m_concentratorDeviceLookupList.First().Key;
if (m_companyLookupList.Count > 0)
CurrentItem.CompanyID = m_companyLookupList.First().Key;
if (m_historianLookupList.Count > 0)
CurrentItem.HistorianID = m_historianLookupList.First().Key;
if (m_interconnectionLookupList.Count > 0)
CurrentItem.InterconnectionID = m_interconnectionLookupList.First().Key;
if (m_protocolLookupList.Count > 0)
CurrentItem.ProtocolID = m_protocolLookupList.First().Key;
if (m_vendorDeviceLookupList.Count > 0)
CurrentItem.VendorDeviceID = m_vendorDeviceLookupList.First().Key;
if (m_timezoneLookupList.Count > 0)
CurrentItem.TimeZone = m_timezoneLookupList.First().Key;
}
///
/// Initialization to be done before the initial call to .
///
public override void Initialize()
{
base.Initialize();
m_nodeLookupList = Node.GetLookupList(null);
m_concentratorDeviceLookupList = Device.GetLookupList(null, DeviceType.Concentrator, true);
m_companyLookupList = Company.GetLookupList(null, true);
m_historianLookupList = TimeSeries.UI.DataModels.Historian.GetLookupList(null, true, false);
m_interconnectionLookupList = Interconnection.GetLookupList(null, true);
m_protocolLookupList = Protocol.GetLookupList(null, true);
m_vendorDeviceLookupList = VendorDevice.GetLookupList(null, true);
m_timezoneLookupList = CommonFunctions.GetTimeZones(true);
}
///
/// Loads collection of information stored in the database.
///
/// This method is overridden because MethodInfo.Invoke in the base class did not like optional parameters.
public override void Load()
{
Mouse.OverrideCursor = Cursors.Wait;
List pageKeys;
try
{
if (OnBeforeLoadCanceled())
throw new OperationCanceledException("Load was canceled.");
if ((object)ItemsKeys == null)
{
ItemsKeys = Device.LoadKeys(null, 0, m_searchText, SortMember, SortDirection);
if ((object)SortSelector != null)
{
if (SortDirection == "ASC")
ItemsKeys = ItemsKeys.OrderBy(SortSelector).ToList();
else
ItemsKeys = ItemsKeys.OrderByDescending(SortSelector).ToList();
}
if (string.IsNullOrEmpty(m_searchText))
AllKeys = ItemsKeys;
}
pageKeys = ItemsKeys.Skip((CurrentPageNumber - 1) * ItemsPerPage).Take(ItemsPerPage).ToList();
ItemsSource = Device.Load(null, pageKeys);
OnLoaded();
}
catch (Exception ex)
{
if ((object)ex.InnerException != null)
{
Popup(ex.Message + Environment.NewLine + "Inner Exception: " + ex.InnerException.Message, "Load Devices Exception:", MessageBoxImage.Error);
CommonFunctions.LogException(null, "Load Devices", ex.InnerException);
}
else
{
Popup(ex.Message, "Load Devices Exception:", MessageBoxImage.Error);
CommonFunctions.LogException(null, "Load Devices", ex);
}
}
finally
{
Mouse.OverrideCursor = null;
}
}
///
/// Saves information into database.
///
public override void Save()
{
Mouse.OverrideCursor = Cursors.Wait;
try
{
Device originalDevice = null;
// If it is an existing device being modified, get prior state so we can determine if a rename occurred.
if (CurrentItem.ID > 0)
originalDevice = Device.GetDevice(null, "WHERE ID = " + CurrentItem.ID);
// Attempt to save base record before possible rename attempt as base record save can fail
base.Save();
try
{
// If renaming a phasor device (e.g., a PMU not a PDC), check if user would like to update device acronym in output streams - this happens here
// instead of in the view model such that a message box can be displayed in the UI to engage user about desire to update output streams. We only
// perform this task for phasor style connections since renaming subscribed devices, although functional, will not "stick" - renamed devices will
// be reverted back to their original names at the next meta-data refresh.
if (!CurrentItem.IsConcentrator && (object)originalDevice != null && string.Compare(CurrentItem.ProtocolCategory, "Phasor", StringComparison.OrdinalIgnoreCase) == 0 &&
(string.CompareOrdinal(CurrentItem.Acronym, originalDevice.Acronym) != 0 || string.CompareOrdinal(CurrentItem.Name, originalDevice.Name) != 0) &&
Confirm("Device was renamed, do you want to also update the device name where it may exist in output streams?", "Update Output Stream Device"))
{
ObservableCollection outputStreamDevices = OutputStreamDevice.GetOutputStreamDevices(null, "WHERE Acronym = '" + originalDevice.Acronym + "'");
foreach (OutputStreamDevice device in outputStreamDevices)
{
device.Acronym = CurrentItem.Acronym;
device.BpaAcronym = CurrentItem.Acronym.Substring(0, 4);
device.Name = CurrentItem.Name;
OutputStreamDevice.Save(null, device);
}
}
}
catch (Exception ex)
{
if ((object)ex.InnerException != null)
{
Popup(ex.Message + Environment.NewLine + "Inner Exception: " + ex.InnerException.Message, "Device Rename:", MessageBoxImage.Error);
CommonFunctions.LogException(null, "Device Rename", ex.InnerException);
}
else
{
Popup(ex.Message, "Device Rename Exception:", MessageBoxImage.Error);
CommonFunctions.LogException(null, "Device Rename", ex);
}
}
// If user is on form page then go back to list page after save.
if (ItemsPerPage == 0)
{
if (!m_stayOnConfigurationScreen)
CommonFunctions.LoadUserControl("Browse Devices", typeof(DeviceListUserControl));
}
}
catch (Exception ex)
{
if ((object)ex.InnerException != null)
{
Popup(ex.Message + Environment.NewLine + "Inner Exception: " + ex.InnerException.Message, "Save Device Exception:", MessageBoxImage.Error);
CommonFunctions.LogException(null, "Save Device", ex.InnerException);
}
else
{
Popup(ex.Message, "Save Device Exception:", MessageBoxImage.Error);
CommonFunctions.LogException(null, "Save Device", ex);
}
}
finally
{
Mouse.OverrideCursor = null;
}
}
///
/// Handles .
///
/// Parameter to use for the command provided by command parameter from UI.
private void GoToEdit(object parameter)
{
CommonFunctions.LoadUserControl("Manage Device Configuration", typeof(DeviceUserControl), (Device)parameter);
}
///
/// Handles .
///
/// Parameter to use for the command provided by command parameter from UI.
private void MakeCopy(object parameter)
{
Device deviceToCopy = (Device)parameter;
string newAcronym;
int i = 1;
// Find unique acronym.
do
{
newAcronym = deviceToCopy.Acronym + i;
i++;
}
while (DeviceExists(newAcronym));
deviceToCopy.Acronym = newAcronym; // Change acronym of the device before going to edit screen.
deviceToCopy.Name = "Copy of " + deviceToCopy.Name; // Change name of the device before going to edit screen.
deviceToCopy.ID = 0; // Set id to zero so that it will be added as a new device.
ItemsPerPage = 0; // Set this so that on Save() user will be sent back to list screen.
deviceToCopy.Enabled = false; // Always set enabled to false for copied device.
// Go to edit screen.
CommonFunctions.LoadUserControl("Manage Device Configuration", typeof(DeviceUserControl), deviceToCopy);
}
private void UpdateConfiguration(object parameter)
{
CommonFunctions.LoadUserControl("Input Device Configuration Wizard", typeof(InputWizardUserControl), (Device)parameter);
}
private bool DeviceExists(string acronym)
{
foreach (Device device in ItemsSource)
{
if (device.Acronym == acronym)
return true;
}
return false;
}
///
/// Handles .
///
private void GoToMeasurements()
{
CommonFunctions.LoadUserControl("Manage Measurements for " + CurrentItem.Acronym, typeof(PhasorMeasurementUserControl), CurrentItem.ID);
}
///
/// Handles .
///
private void GoToPhasors()
{
CommonFunctions.LoadUserControl("Manage Phasors for " + CurrentItem.Acronym, typeof(PhasorUserControl), CurrentItem.ID);
}
protected override void OnPropertyChanged(string propertyName)
{
base.OnPropertyChanged(propertyName);
if (propertyName == "CurrentItem")
{
if ((object)CurrentItem == null)
RuntimeID = string.Empty;
else
RuntimeID = CommonFunctions.GetRuntimeID("Device", CurrentItem.ID);
}
}
private void InitializeDevice()
{
try
{
if (!string.IsNullOrEmpty(RuntimeID))
{
if (Confirm("Do you want to send Initialize " + GetCurrentItemName() + "?", "Confirm Initialize"))
{
Device.NotifyService(CurrentItem);
Popup("Successfully sent Initialize command.", "Initialize", MessageBoxImage.Information);
}
}
}
catch (Exception ex)
{
Popup("ERROR: " + ex.Message, "Failed To Initialize", MessageBoxImage.Error);
}
}
private void BuildConnectionString()
{
if ((object)CurrentItem != null)
{
ConnectionStringBuilder csb = new ConnectionStringBuilder(ConnectionStringBuilder.ConnectionType.DeviceConnection);
if (!string.IsNullOrEmpty(CurrentItem.ConnectionString))
csb.ConnectionString = CurrentItem.ConnectionString;
csb.Closed += delegate
{
if (csb.DialogResult.GetValueOrDefault())
CurrentItem.ConnectionString = csb.ConnectionString;
};
csb.Owner = Application.Current.MainWindow;
csb.WindowStartupLocation = WindowStartupLocation.CenterOwner;
csb.ShowDialog();
}
}
private void BuildAlternateCommandChannel()
{
if ((object)CurrentItem != null)
{
ConnectionStringBuilder csb = new ConnectionStringBuilder(ConnectionStringBuilder.ConnectionType.AlternateCommandChannel);
if (!string.IsNullOrEmpty(CurrentItem.AlternateCommandChannel))
csb.ConnectionString = CurrentItem.AlternateCommandChannel;
if (CurrentItem.ProtocolID != null && m_protocolLookupList[(int)CurrentItem.ProtocolID] == "Gateway Transport")
csb.PgConnection = true;
else
csb.PgConnection = false;
csb.Closed += delegate
{
if (csb.DialogResult.GetValueOrDefault())
CurrentItem.AlternateCommandChannel = csb.ConnectionString;
};
csb.Owner = Application.Current.MainWindow;
csb.WindowStartupLocation = WindowStartupLocation.CenterOwner;
csb.ShowDialog();
}
}
///
/// Deletes current item from the database.
///
public override void Delete()
{
try
{
if (CurrentItem.IsConcentrator)
{
IList keys = Device.LoadKeys(null, CurrentItem.ID);
ObservableCollection deviceList = Device.Load(null, keys);
int outputStreamDeviceCount = 0;
string result;
foreach (Device device in deviceList)
{
outputStreamDeviceCount += OutputStreamDevice.GetOutputStreamDevices(null, "WHERE Acronym = '" + device.Acronym + "'").Count;
}
string confirm = "Are you sure you want to delete concentrator device?";
if (deviceList.Count > 1)
confirm += Environment.NewLine + "There are " + deviceList.Count.ToString() + " associated children devices.";
else if (deviceList.Count > 0)
confirm += Environment.NewLine + "There is " + deviceList.Count.ToString() + " associated child device.";
if (outputStreamDeviceCount > 1)
confirm += Environment.NewLine + "There are " + outputStreamDeviceCount.ToString() + " output stream devices that exist.";
else if (outputStreamDeviceCount > 0)
confirm += Environment.NewLine + "There is " + outputStreamDeviceCount.ToString() + " output stream device that exists.";
if (Confirm(confirm, "Delete Device"))
{
foreach (Device device in deviceList)
Device.Delete(null, device);
result = Device.Delete(null, CurrentItem);
DisplayStatusMessage(result);
}
}
else
{
ObservableCollection outputStreamDevices = OutputStreamDevice.GetOutputStreamDevices(null, "WHERE Acronym = '" + CurrentItem.Acronym + "'");
string confirm = "Are you sure you want to delete this device?";
if (outputStreamDevices.Count > 1)
confirm += Environment.NewLine + "It exists in " + outputStreamDevices.Count.ToString() + " output streams.";
else if (outputStreamDevices.Count > 0)
confirm += Environment.NewLine + "It exists in " + outputStreamDevices.Count.ToString() + " output stream.";
if (Confirm(confirm, "Delete Device"))
{
string result = Device.Delete(null, CurrentItem);
DisplayStatusMessage(result);
}
}
Device.NotifyService(null, CurrentItem.HistorianID);
CommonFunctions.LoadUserControl("Browse Devices", typeof(DeviceListUserControl));
}
catch (Exception ex)
{
if ((object)ex.InnerException != null)
{
Popup(ex.Message + Environment.NewLine + "Inner Exception: " + ex.InnerException.Message, "Delete Device Exception:", MessageBoxImage.Error);
CommonFunctions.LogException(null, "Delete Device", ex.InnerException);
}
else
{
Popup(ex.Message, "Delete Device Exception:", MessageBoxImage.Error);
CommonFunctions.LogException(null, "Delete Device", ex);
}
}
}
///
/// Handles .
///
/// string value to search for in measurement collection.
public void Search(object parameter)
{
if ((object)parameter != null && !string.IsNullOrEmpty(parameter.ToString()))
{
SetCurrentPageNumber(1);
m_searchText = parameter.ToString();
ItemsKeys = null;
Load();
}
}
///
/// Handles .
///
public void ShowAll()
{
if (!ReferenceEquals(AllKeys, ItemsKeys))
{
SetCurrentPageNumber(1);
m_searchText = null;
ItemsKeys = AllKeys;
Load();
}
}
private void ConfigureConcentrator()
{
if ((object)CurrentItem.ParentID != null && CurrentItem.ParentID > 0)
{
m_stayOnConfigurationScreen = true;
Device device = Device.GetDevice(null, "WHERE ID = " + CurrentItem.ParentID);
if ((object)device != null)
{
PdcDevices = Device.GetDevices(null, "WHERE ParentID = " + CurrentItem.ParentID);
CurrentItem = device;
}
}
}
#endregion
}
}