/// <summary>
        /// Resets the available range labels
        /// </summary>
        private void UpdateAvailableRanges()
        {
            List <Range> availableFrom = null;
            List <Range> availableTo   = null;

            // Get the ranges and connections based on whether we are port-strand or strand-port
            #region Determine Direction
            if (cboFrom.SelectedItem is FiberCableWrapper &&
                cboTo.SelectedItem is ConnectableDeviceWrapper)
            {
                FiberCableWrapper        cable  = (FiberCableWrapper)cboFrom.SelectedItem;
                ConnectableDeviceWrapper device = (ConnectableDeviceWrapper)cboTo.SelectedItem;

                availableFrom = SpliceAndConnectionUtils.GetAvailableRanges(cable, device.IsCableFromEnd);
                availableTo   = SpliceAndConnectionUtils.GetAvailableRanges(device, PortType.Input);
            }
            else if (cboFrom.SelectedItem is DeviceWrapper &&
                     cboTo.SelectedItem is ConnectableCableWrapper)
            {
                DeviceWrapper           device = (DeviceWrapper)cboFrom.SelectedItem;
                ConnectableCableWrapper cable  = (ConnectableCableWrapper)cboTo.SelectedItem;

                availableFrom = SpliceAndConnectionUtils.GetAvailableRanges(device, PortType.Output);
                availableTo   = SpliceAndConnectionUtils.GetAvailableRanges(cable, cable.IsThisFromEnd);
            }
            #endregion

            lblAvailableFrom.Text = GetAvailableRangesString(availableFrom);
            lblAvailableTo.Text   = GetAvailableRangesString(availableTo);
        }
        /// <summary>
        /// Load the B dropdown with spliceable cables
        /// </summary>
        /// <param name="helper">SpliceEditorHelper</param>
        /// <param name="cableA">A Cable</param>
        private void PopulateBCables(FiberSpliceHelper helper, FiberCableWrapper cableA)
        {
            try
            {
                // Clear anything that is dependent on what we are about to load
                ClearGrid();
                cboCableB.Items.Clear();
                lblAvailableA.Text = "";
                lblAvailableB.Text = "";

                SpliceClosureWrapper splice = cboSpliceClosure.SelectedItem as SpliceClosureWrapper;
                if (null != splice)
                {
                    List <SpliceableCableWrapper> spliceableCables = _spliceHelper.GetSpliceableCables(cableA, splice);
                    for (int i = 0; i < spliceableCables.Count; i++)
                    {
                        cboCableB.Items.Add(spliceableCables[i]);
                    }

                    if (0 < cboCableB.Items.Count)
                    {
                        cboCableB.SelectedItem = cboCableB.Items[0];
                    }
                }
            }
            catch (Exception e)
            {
                _logHelper.addLogEntry(DateTime.Now.ToString(), "ERROR", "Splice Connection Window (PopulateBCables): ", e.Message);
            }
        }
        /// <summary>
        /// Prompts the user about saving pending edits
        /// </summary>
        /// <param name="spliceWrapper"></param>
        /// <param name="cableAWrapper"></param>
        /// <param name="cableBWrapper"></param>
        /// <returns>False if the user chooses to cancel what they were doing; True if they choose Yes or No
        /// (which means they are OK with what they are doing)</returns>
        private bool IsUserSure(SpliceClosureWrapper spliceWrapper, FiberCableWrapper cableAWrapper, SpliceableCableWrapper cableBWrapper)
        {
            bool result = true;

            // Assume they do not want to save and do want to continue
            DialogResult dialogResult = DialogResult.No;

            dialogResult = MessageBox.Show("You have unsaved edits. Would you like to save them before closing?", "Connection Editor", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
            if (DialogResult.Cancel == dialogResult)
            {
                // The user isn't sure about what they are doing and wants to cancel it
                result = false;
            }
            else if (DialogResult.Yes == dialogResult)
            {
                bool isSaveOk = SaveChanges(spliceWrapper, cableAWrapper, cableBWrapper);
                if (!isSaveOk)
                {
                    // They wanted to save but it didn't work. They probably got a message telling them what to fix. Cancel
                    // whatever they were doing so that they have a chance to do so
                    result = false;
                }
            }

            return(result);
        }
        /// <summary>
        /// Load the A dropdown with selected cables
        /// </summary>
        /// <param name="helper">SpliceEditorHelper</param>
        private void PopulateACables(FiberSpliceHelper helper, SpliceClosureWrapper spliceWrapper)
        {
            try
            {
                // Clear anything that is dependent on what we are about to load
                ClearGrid();
                cboCableA.Items.Clear();
                cboCableB.Items.Clear();
                lblAvailableA.Text = "";
                lblAvailableB.Text = "";

                List <ESRI.ArcGIS.Geodatabase.IFeature> selectedCables = helper.GetConnectedCables(spliceWrapper);
                ESRI.ArcGIS.Carto.IFeatureLayer         ftLayer        = _hookHelper.FindFeatureLayer(ConfigUtil.FiberCableFtClassName);
                int displayIdx = ftLayer.FeatureClass.FindField(ftLayer.DisplayField);

                for (int i = 0; i < selectedCables.Count; i++)
                {
                    FiberCableWrapper w = new FiberCableWrapper(selectedCables[i], displayIdx);
                    cboCableA.Items.Add(w);
                }

                if (0 < cboCableA.Items.Count)
                {
                    cboCableA.SelectedItem = cboCableA.Items[0];
                }
            }
            catch (Exception e)
            {
                _logHelper.addLogEntry(DateTime.Now.ToString(), "ERROR", "Splice Connection Window (PopulateACables): ", e.Message);
            }
        }
Beispiel #5
0
        /// <summary>
        /// Generates a splice closure at the coincident endpoint. Does not start an edit operation.
        /// </summary>
        /// <param name="cableA">Cable A</param>
        /// <param name="cableB">Cable B</param>
        /// <returns>SpliceClosureWRapper based on new feature</returns>
        private SpliceClosureWrapper GenerateSpliceClosure(FiberCableWrapper cableA, SpliceableCableWrapper cableB)
        {
            SpliceClosureWrapper wrapper = null;

            #region Validation
            if (null == cableA)
            {
                throw new ArgumentNullException("cableA");
            }

            if (null == cableB)
            {
                throw new ArgumentNullException("cableB");
            }

            if (ESRI.ArcGIS.Editor.esriEditState.esriStateNotEditing == _editor.EditState)
            {
                throw new InvalidOperationException("You must be editing to perform this operation");
            }
            #endregion

            // Populate an IPID; we will need it
            Guid   g          = Guid.NewGuid();
            string spliceIpid = g.ToString("B").ToUpper();

            try
            {
                ESRI.ArcGIS.Geometry.IPolyline line = cableB.Feature.Shape as ESRI.ArcGIS.Geometry.IPolyline;
                if (null != line)
                {
                    ESRI.ArcGIS.Geometry.IPoint splicePoint = null;

                    if (cableB.IsThisFromEnd)
                    {
                        splicePoint = line.FromPoint;
                    }
                    else
                    {
                        splicePoint = line.ToPoint;
                    }

                    ESRI.ArcGIS.Geodatabase.IFeatureClass spliceClosureFtClass = _wkspHelper.FindFeatureClass(ConfigUtil.SpliceClosureFtClassName);
//                    ESRI.ArcGIS.Geodatabase.IFeatureClass spliceClosureFtClass = GdbUtils.GetFeatureClass(cableA.Feature.Class, ConfigUtil.SpliceClosureFtClassName);
                    ESRI.ArcGIS.Geodatabase.IFeature spliceFt = spliceClosureFtClass.CreateFeature();

                    spliceFt.Shape = splicePoint;
                    spliceFt.set_Value(spliceClosureFtClass.Fields.FindField(ConfigUtil.IpidFieldName), spliceIpid);
                    spliceFt.Store();

                    wrapper = new SpliceClosureWrapper(spliceFt);
                }
            }
            catch
            {
                wrapper = null;
            }

            return(wrapper);
        }
Beispiel #6
0
        /// <summary>
        /// Deletes all splices for a cable to any other at any splice closure
        /// </summary>
        /// <param name="cable">Cable</param>
        /// <param name="isExistingOperation">Are we already in an edit operation?</param>
        /// <returns>Success</returns>
        public bool BreakAllSplices(FiberCableWrapper cable, bool isExistingOperation)
        {
            bool success         = false;
            bool isOperationOpen = false;

            #region Validation
            if (null == cable)
            {
                throw new ArgumentNullException("cable");
            }

            if (ESRI.ArcGIS.Editor.esriEditState.esriStateNotEditing == _editor.EditState)
            {
                throw new InvalidOperationException("You must be editing to perform this operation");
            }
            #endregion

            if (!isExistingOperation)
            {
                _editor.StartOperation();
                isOperationOpen = true;
            }

            try
            {
                ESRI.ArcGIS.Geodatabase.ITable spliceTable = _wkspHelper.FindTable(ConfigUtil.FiberSpliceTableName);
//                ESRI.ArcGIS.Geodatabase.ITable spliceTable = GdbUtils.GetTable(cable.Feature.Class, ConfigUtil.FiberSpliceTableName);
                ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass();

                // A and B is arbitrary, so we check the given combinations going both ways. The structure is:
                // Where either the A or B cableID is our cable ID
                filter.WhereClause = string.Format("{0}='{1}' OR {2}='{1}'",
                                                   ConfigUtil.ACableIdFieldName,
                                                   cable.IPID,
                                                   ConfigUtil.BCableIdFieldName);

                spliceTable.DeleteSearchedRows(filter);
                ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(filter);

                if (isOperationOpen)
                {
                    _editor.StopOperation("Break Splices");
                    isOperationOpen = false;
                }

                success = true;
            }
            catch
            {
                if (isOperationOpen)
                {
                    _editor.AbortOperation();
                }

                success = false;
            }

            return(success);
        }
        /// <summary>
        /// Gets a list of all strand numbers from a cable that are spliced on the given end
        /// </summary>
        /// <param name="cable">Cable to check</param>
        /// <param name="isFromEnd">True to check from end, False to check to end</param>
        /// <returns>List of int</returns>
        private static List <int> GetSplicedStrands(FiberCableWrapper cable, bool isFromEnd)
        {
            if (null == cable)
            {
                throw new ArgumentNullException("cable");
            }

            List <int> result = new List <int>();

            using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser())
            {
                ESRI.ArcGIS.Geodatabase.ITable fiberSpliceTable = TelecomWorkspaceHelper.Instance().FindTable(ConfigUtil.FiberSpliceTableName);
//                ESRI.ArcGIS.Geodatabase.ITable fiberSpliceTable = GdbUtils.GetTable(cable.Feature.Class, ConfigUtil.FiberSpliceTableName);
                ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass();
                releaser.ManageLifetime(filter);
                filter.WhereClause = string.Format("{0}='{1}' AND {2}='{3}'",
                                                   ConfigUtil.ACableIdFieldName,
                                                   cable.IPID,
                                                   ConfigUtil.IsAFromEndFieldName,
                                                   (isFromEnd ? "T" : "F"));

                ESRI.ArcGIS.Geodatabase.ICursor spliceCursor = fiberSpliceTable.Search(filter, true);
                ESRI.ArcGIS.Geodatabase.IRow    spliceRow    = spliceCursor.NextRow();
                int fiberIdIdx = fiberSpliceTable.FindField(ConfigUtil.AFiberNumberFieldName);

                while (null != spliceRow)
                {
                    result.Add((int)spliceRow.get_Value(fiberIdIdx));

                    ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(spliceRow);
                    spliceRow = spliceCursor.NextRow();
                }

                ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(spliceCursor);

                filter.WhereClause = string.Format("{0}='{1}' AND {2}='{3}'",
                                                   ConfigUtil.BCableIdFieldName,
                                                   cable.IPID,
                                                   ConfigUtil.IsBFromEndFieldName,
                                                   (isFromEnd ? "T" : "F")); spliceCursor = fiberSpliceTable.Search(filter, true);

                spliceRow  = spliceCursor.NextRow();
                fiberIdIdx = fiberSpliceTable.FindField(ConfigUtil.BFiberNumberFieldName);

                while (null != spliceRow)
                {
                    result.Add((int)spliceRow.get_Value(fiberIdIdx));

                    ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(spliceRow);
                    spliceRow = spliceCursor.NextRow();
                }

                ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(spliceCursor);
            }

            return(result);
        }
Beispiel #8
0
        /// <summary>
        /// Cable features can have related:
        ///         splices,
        ///         connections,
        ///         strands
        ///         buffer tubes,
        ///         maintenance loop
        /// </summary>
        /// <param name="cableFeature">Deleted IFeature</param>
        private void CascadeFiberCableDelete(ESRI.ArcGIS.Geodatabase.IFeature cableFeature)
        {
            FiberCableWrapper cable = new FiberCableWrapper(cableFeature);

            // Delete splices (to other cables)
            _spliceHelper.BreakAllSplices(cable, true);

            // Delete connections (to equipment)
            _connectionHelper.BreakAllConnections(cable, true);
        }
        /// <summary>
        /// The form is closing; check for unsaved edits to the grid
        /// </summary>
        private void SpliceEditorForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (btnSave.Enabled)
            {
                SpliceClosureWrapper   spliceWrapper = cboSpliceClosure.SelectedItem as SpliceClosureWrapper;
                FiberCableWrapper      cableA        = cboCableA.SelectedItem as FiberCableWrapper;
                SpliceableCableWrapper cableB        = cboCableB.SelectedItem as SpliceableCableWrapper;

                e.Cancel = !IsUserSure(spliceWrapper, cableA, cableB);
            }
        }
        /// <summary>
        /// Loads the grid with existing splice ranges between the given features
        /// </summary>
        /// <param name="spliceWrapper">Selected Splice Closure</param>
        /// <param name="cableA">Selected Cable A</param>
        /// <param name="cableB">Selected Cable B</param>
        private void LoadExistingRecords(SpliceClosureWrapper spliceWrapper, FiberCableWrapper cableA, SpliceableCableWrapper cableB)
        {
            ClearGrid();

            if (null != spliceWrapper && null != cableA && null != cableB)
            {
                List <FiberSplice> rangesAtoB = SpliceAndConnectionUtils.GetSplicedRanges(cableA, cableB, spliceWrapper);
                for (int i = 0; i < rangesAtoB.Count; i++)
                {
                    FiberSplice fiberSplice = rangesAtoB[i];
                    int         rowIdx      = grdSplices.Rows.Add(fiberSplice.ARange, fiberSplice.BRange, fiberSplice.Loss, fiberSplice.Type);
                    grdSplices.Rows[rowIdx].ReadOnly = true; // Allow this to be deleted, but not edited.

                    Range a        = fiberSplice.ARange;
                    Range b        = fiberSplice.BRange;
                    int   numUnits = a.High - a.Low + 1;
                    for (int offset = 0; offset < numUnits; offset++)
                    {
                        int aUnit = a.Low + offset;
                        int bUnit = b.Low + offset;

                        FiberSplice originalSplice = new FiberSplice(new Range(aUnit, aUnit), new Range(bUnit, bUnit), fiberSplice.Loss, fiberSplice.Type);
                        _original[aUnit] = originalSplice;
                    }
                }

                // These are valid for display because it is these two cables at this splice, the A and B side assignment is
                // arbitrary. We do need to reverse them in the display though. For example is Cable X (1-12) is spliced to
                // Cable Y (36-47), and they have selected X/Y in the form -- the grid should show X's units on the left and
                // Y's on the right. Here we are requesting them as Y/X though.
                List <FiberSplice> rangesBtoA = SpliceAndConnectionUtils.GetSplicedRanges((FiberCableWrapper)cboCableB.SelectedItem, (FiberCableWrapper)cboCableA.SelectedItem, spliceWrapper);
                for (int i = 0; i < rangesBtoA.Count; i++)
                {
                    FiberSplice fiberSplice = rangesBtoA[i];
                    int         rowIdx      = grdSplices.Rows.Add(fiberSplice.BRange, fiberSplice.ARange, fiberSplice.Loss, fiberSplice.Type);
                    grdSplices.Rows[rowIdx].ReadOnly = true; // Allow this to be deleted, but not edited.

                    Range a        = fiberSplice.ARange;
                    Range b        = fiberSplice.BRange;
                    int   numUnits = a.High - a.Low + 1;
                    for (int offset = 0; offset < numUnits; offset++)
                    {
                        int aUnit = a.Low + offset;
                        int bUnit = b.Low + offset;

                        FiberSplice originalSplice = new FiberSplice(new Range(bUnit, bUnit), new Range(aUnit, aUnit), fiberSplice.Loss, fiberSplice.Type);
                        _original[bUnit] = originalSplice;
                    }
                }
            }

            btnSave.Enabled = false;
            btnSave.Tag     = false; // No edits made yet
        }
        /// <summary>
        /// Update the dropdowns of features on the UI
        /// </summary>
        /// <param name="helper">Helper class</param>
        private void PopulateDropDowns(FiberDeviceConnectionHelper helper)
        {
            // Clear the existing choices
            cboFrom.Items.Clear();
            cboTo.Items.Clear();
            lblAvailableFrom.Text = "";
            lblAvailableTo.Text   = "";

            // Get the features and the display index for use when creating the wrapper
            ESRI.ArcGIS.Carto.IFeatureLayer ftLayer = _hookHelper.FindFeatureLayer(ConfigUtil.FiberCableFtClassName);
            int displayIdx = ftLayer.FeatureClass.FindField(ftLayer.DisplayField);

            // Get the selected features
            List <ESRI.ArcGIS.Geodatabase.IFeature> selectedFts = _hookHelper.GetSelectedFeatures(ftLayer);

            // Add each of the fiber features to the drop down
            for (int ftIdx = 0; ftIdx < selectedFts.Count; ftIdx++)
            {
                FiberCableWrapper w = new FiberCableWrapper(selectedFts[ftIdx], displayIdx);
                cboFrom.Items.Add(w);
            }

            // Now do that same thing for each of the device feature classes
            string[] deviceClassNames = ConfigUtil.DeviceFeatureClassNames;
            for (int deviceClassIdx = 0; deviceClassIdx < deviceClassNames.Length; deviceClassIdx++)
            {
                string ftClassName = deviceClassNames[deviceClassIdx];

                // Get the features and the display index for use when creating the wrapper
                ftLayer = _hookHelper.FindFeatureLayer(ftClassName);
                if (ftLayer != null) // what if layer removed from map
                {
                    selectedFts = _hookHelper.GetSelectedFeatures(ftLayer);

                    displayIdx = ftLayer.FeatureClass.FindField(ftLayer.DisplayField);

                    for (int ftIdx = 0; ftIdx < selectedFts.Count; ftIdx++)
                    {
                        DeviceWrapper w = new DeviceWrapper(selectedFts[ftIdx], displayIdx);
                        cboFrom.Items.Add(w);
                    }
                }
            }

            // Preselect the first choice
            if (0 < cboFrom.Items.Count)
            {
                cboFrom.SelectedItem = cboFrom.Items[0];
            }
        }
        /// <summary>
        /// The user changed a different cable for the B cable
        /// </summary>
        private void cboCableB_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!_isReverting)
            {
                bool isChangeAccepted = !btnSave.Enabled; // If the save button is disabled, there aren't edits to prompt about

                // Get the current A cable and splice
                FiberCableWrapper    cableA = cboCableA.SelectedItem as FiberCableWrapper;
                SpliceClosureWrapper splice = cboSpliceClosure.SelectedItem as SpliceClosureWrapper;

                if (!isChangeAccepted)
                {
                    // Get the B Cable that was selected before the index changed, so we can prompt for unsaved edits
                    SpliceableCableWrapper preChangeB = null;
                    if (-1 < _lastSelectedBIdx &&
                        _lastSelectedBIdx < cboCableB.Items.Count)
                    {
                        preChangeB = cboCableB.Items[_lastSelectedBIdx] as SpliceableCableWrapper;
                    }

                    isChangeAccepted = IsUserSure(splice, cableA, preChangeB);
                }

                if (isChangeAccepted)
                {
                    _lastSelectedBIdx = cboCableB.SelectedIndex;
                    SpliceableCableWrapper cableB = cboCableB.SelectedItem as SpliceableCableWrapper;

                    if (null != cableA &&
                        null != cableB &&
                        null != splice)
                    {
                        lblAvailableA.Text = GetAvailableRangeString(cableA, cableB.IsOtherFromEnd);
                        lblAvailableB.Text = GetAvailableRangeString(cableB, cableB.IsThisFromEnd);

                        LoadExistingRecords(splice, cableA, cableB);
                    }
                }
                else
                {
                    // Cancel the change by re-selecting the previous from feature
                    _isReverting            = true;
                    cboCableB.SelectedIndex = _lastSelectedBIdx;
                    _isReverting            = false;
                }
            }
        }
        /// <summary>
        /// Creates a label string for the available ranges of a cable at a certain end
        /// </summary>
        /// <param name="cable">Cable to check</param>
        /// <param name="isFromEnd">End to check</param>
        /// <returns>string</returns>
        private string GetAvailableRangeString(FiberCableWrapper cable, bool isFromEnd)
        {
            List <Range> availableRanges = SpliceAndConnectionUtils.GetAvailableRanges(cable, isFromEnd);
            string       result          = "No available ranges!";

            if (0 < availableRanges.Count)
            {
                StringBuilder availableLabel = new StringBuilder(64);
                for (int i = 0; i < availableRanges.Count; i++)
                {
                    availableLabel.AppendFormat("{0},", availableRanges[i].ToString());
                }
                availableLabel.Remove(availableLabel.Length - 1, 1);
                result = string.Format("Available: {0}", availableLabel.ToString());
            }

            return(result);
        }
        /// <summary>
        /// Finds ranges of fibers that are not yet spliced or connected
        /// </summary>
        /// <param name="cable">Cable to check</param>
        /// <param name="isFromEnd">Flag of which side of the cable to check</param>
        /// <returns>List of Range</returns>
        public static List <Range> GetAvailableRanges(FiberCableWrapper cable, bool isFromEnd)
        {
            List <Range> result = new List <Range>();

            if (null == cable)
            {
                throw new ArgumentNullException("cable");
            }

            List <int> usedStrands = new List <int>();

            usedStrands.AddRange(GetSplicedStrands(cable, isFromEnd));   // Gets the ones that are spliced to another cable
            usedStrands.AddRange(GetConnectedStrands(cable, isFromEnd)); // Gets the ones that are connected to a device
            usedStrands.Sort();

            List <Range> splicedRanges = MergeRanges(usedStrands);

//            int? fiberCount = GdbUtils.GetDomainedIntName(cable.Feature, ConfigUtil.NumberOfFibersFieldName);
            int?fiberCount = cable.fibers;

            if (null != fiberCount)
            {
                int lowFiber = 1;

                for (int i = 0; i < splicedRanges.Count; i++)
                {
                    Range range = splicedRanges[i];
                    if (lowFiber != range.Low)
                    {
                        // We are good until this range starts
                        result.Add(new Range(lowFiber, range.Low - 1));
                    }

                    lowFiber = range.High + 1;
                }

                if (lowFiber <= fiberCount)
                {
                    result.Add(new Range(lowFiber, (int)fiberCount));
                }
            }

            return(result);
        }
        /// <summary>
        /// Determines if all given ranges are available (neither spliced nor connected)
        /// </summary>
        /// <param name="units">Units to check</param>
        /// <param name="cableWrapper">Cable to check</param>
        /// <param name="isFromEnd">Flag of which end we are checking</param>
        /// <returns>True if they are all available</returns>
        public static bool AreRangesAvailable(ICollection <int> units, FiberCableWrapper cableWrapper, bool isFromEnd)
        {
            bool result = true;

            List <int> splicedStrands   = GetSplicedStrands(cableWrapper, isFromEnd);
            List <int> connectedStrands = GetConnectedStrands(cableWrapper, isFromEnd);

            foreach (int unit in units)
            {
                if (splicedStrands.Contains(unit) ||
                    connectedStrands.Contains(unit))
                {
                    result = false;
                    break;
                }
            }

            return(result);
        }
        /// <summary>
        /// Returns devices at the endpoints of the given cable
        /// </summary>
        /// <param name="deviceWrapper">Cable to check</param>
        /// <returns>List of ConnectableDeviceWrapper</returns>
        public List <ConnectableDeviceWrapper> GetCoincidentDevices(FiberCableWrapper fiberCableWrapper)
        {
            List <ConnectableDeviceWrapper> result = new List <ConnectableDeviceWrapper>();

            if (null == fiberCableWrapper)
            {
                throw new ArgumentNullException("fiberCableWrapper");
            }

            ESRI.ArcGIS.Geometry.IPolyline cableGeometry = (ESRI.ArcGIS.Geometry.IPolyline)fiberCableWrapper.Feature.Shape;
            string[] deviceFtClassNames = ConfigUtil.DeviceFeatureClassNames;

            double buffer = _hookHelper.ConvertPixelsToMapUnits(1);

            for (int i = 0; i < deviceFtClassNames.Length; i++)
            {
                string ftClassName = deviceFtClassNames[i];

                ESRI.ArcGIS.Carto.IFeatureLayer ftLayer = _hookHelper.FindFeatureLayer(ftClassName);
                if (ftLayer == null)
                {
                    // Layer might not be in the map so just skip if not found.
                    continue;
                }
                ESRI.ArcGIS.Geodatabase.IFeatureClass ftClass = ftLayer.FeatureClass;
                int displayIdx = ftClass.FindField(ftLayer.DisplayField);

                List <ESRI.ArcGIS.Geodatabase.IFeature> fromFts = GdbUtils.GetFeaturesWithCoincidentVertices(cableGeometry.FromPoint, ftClass, false, buffer);
                for (int fromIdx = 0; fromIdx < fromFts.Count; fromIdx++)
                {
                    result.Add(new ConnectableDeviceWrapper(fromFts[fromIdx], true, displayIdx));
                }

                List <ESRI.ArcGIS.Geodatabase.IFeature> toFts = GdbUtils.GetFeaturesWithCoincidentVertices(cableGeometry.ToPoint, ftClass, false, buffer);
                for (int toIdx = 0; toIdx < toFts.Count; toIdx++)
                {
                    result.Add(new ConnectableDeviceWrapper(toFts[toIdx], false, displayIdx));
                }
            }

            return(result);
        }
        /// <summary>
        /// The user changed a different cable for the A cable
        /// </summary>
        private void cboCableA_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!_isReverting)
            {
                bool isChangeAccepted = !btnSave.Enabled; // If the save button is disabled, there aren't edits to prompt about

                if (!isChangeAccepted)
                {
                    // Get the current B cable and splice, and the A Cable that was selected before the index changed,
                    // so we can prompt for unsaved edits
                    SpliceClosureWrapper   splice = cboSpliceClosure.SelectedItem as SpliceClosureWrapper;
                    SpliceableCableWrapper cableB = cboCableB.SelectedItem as SpliceableCableWrapper;

                    FiberCableWrapper preChangeA = null;
                    if (-1 < _lastSelectedAIdx &&
                        _lastSelectedAIdx < cboCableA.Items.Count)
                    {
                        preChangeA = cboCableA.Items[_lastSelectedAIdx] as FiberCableWrapper;
                    }

                    isChangeAccepted = IsUserSure(splice, preChangeA, cableB);
                }

                if (isChangeAccepted)
                {
                    _lastSelectedAIdx = cboCableA.SelectedIndex;

                    FiberCableWrapper cableA = cboCableA.SelectedItem as FiberCableWrapper;
                    if (null != cableA)
                    {
                        PopulateBCables(_spliceHelper, cableA);
                    }
                }
                else
                {
                    // Cancel the change by re-selecting the previous from feature
                    _isReverting            = true;
                    cboCableA.SelectedIndex = _lastSelectedAIdx;
                    _isReverting            = false;
                }
            }
        }
        /// <summary>
        /// The user has clicked the save button
        /// </summary>
        private void btnSave_Click(object sender, EventArgs e)
        {
            try
            {
                SpliceClosureWrapper   spliceWrapper = cboSpliceClosure.SelectedItem as SpliceClosureWrapper;
                FiberCableWrapper      cableA        = cboCableA.SelectedItem as FiberCableWrapper;
                SpliceableCableWrapper cableB        = cboCableB.SelectedItem as SpliceableCableWrapper;

                SaveChanges(spliceWrapper, cableA, cableB);

                lblAvailableA.Text = GetAvailableRangeString(cableA, cableB.IsOtherFromEnd);
                lblAvailableB.Text = GetAvailableRangeString(cableB, cableB.IsThisFromEnd);
            }
            catch (Exception ex)
            {
                _logHelper.addLogEntry(DateTime.Now.ToString(), "ERROR", "Error saving connections.", ex.ToString());

                MessageBox.Show("Error saving connections: \n" + ex.ToString());
            }
        }
        /// <summary>
        /// Gets the connections for the current combo drop down status
        /// </summary>
        private List <Connection> getConnections()
        {
            List <Connection> connections = null;

            if (cboFrom.SelectedItem is FiberCableWrapper &&
                cboTo.SelectedItem is ConnectableDeviceWrapper)
            {
                FiberCableWrapper        cable  = (FiberCableWrapper)cboFrom.SelectedItem;
                ConnectableDeviceWrapper device = (ConnectableDeviceWrapper)cboTo.SelectedItem;
                connections = _connectionHelper.GetConnections(cable, device, device.IsCableFromEnd, PortType.Input);
            }
            else if (cboFrom.SelectedItem is DeviceWrapper &&
                     cboTo.SelectedItem is ConnectableCableWrapper)
            {
                DeviceWrapper           device = (DeviceWrapper)cboFrom.SelectedItem;
                ConnectableCableWrapper cable  = (ConnectableCableWrapper)cboTo.SelectedItem;
                connections = _connectionHelper.GetConnections(cable, device, cable.IsThisFromEnd, PortType.Output);
            }

            return(connections);
        }
        /// <summary>
        /// Determines if a cable has any connections or splices on its strands
        /// </summary>
        /// <param name="cableWrapper">Cable to check</param>
        /// <returns>True if any strand is connected or spliced</returns>
        public static bool HasAnyConnections(FiberCableWrapper cableWrapper)
        {
            int?fiberCount = cableWrapper.fibers;

            List <Range> ranges = null;

            bool isFromClear = true;
            bool isToClear   = true;

            if (null != fiberCount && 0 < fiberCount)
            {
                ranges      = GetAvailableRanges(cableWrapper, true);
                isFromClear = AreRangesWholeUnitCount(ranges, (int)fiberCount);

                ranges    = GetAvailableRanges(cableWrapper, false);
                isToClear = AreRangesWholeUnitCount(ranges, (int)fiberCount);
            }

            // If either end is not clear, there are connections
            return(!isFromClear || !isToClear);
        }
        /// <summary>
        /// Determines if all the ranges fall between 1 to fibercount
        /// </summary>
        /// <param name="ranges">Ranges to check</param>
        /// <param name="cable">Cable to check on</param>
        /// <returns>True if valid ranges</returns>
        public static bool AreRangesWithinFiberCount(List <Range> ranges, FiberCableWrapper cable)
        {
            bool result = true;

            #region Validation
            if (null == cable)
            {
                throw new ArgumentNullException("cable");
            }

            if (null == ranges)
            {
                throw new ArgumentNullException("ranges");
            }
            #endregion

//            int? fiberCount = GdbUtils.GetDomainedIntName(cable.Feature, ConfigUtil.NumberOfFibersFieldName);

            int?fiberCount = cable.fibers;

            if (null == fiberCount)
            {
                result = false;
            }
            else
            {
                foreach (Range r in ranges)
                {
                    if (r.High > fiberCount ||
                        1 > r.Low)
                    {
                        result = false;
                        break;
                    }
                }
            }

            return(result);
        }
        /// <summary>
        /// Break all connections for a given cable
        /// </summary>
        /// <param name="cable">Cable to break connections</param>
        /// <param name="isExistingOperation">Should we start/stop the edit operation, or are we already in one?</param>
        /// <returns>Success</returns>
        public bool BreakAllConnections(FiberCableWrapper cable, bool isExistingOperation)
        {
            bool success         = false;
            bool isOperationOpen = false;

            #region Validation
            if (null == cable)
            {
                throw new ArgumentNullException("cable");
            }

            if (ESRI.ArcGIS.Editor.esriEditState.esriStateNotEditing == _editor.EditState)
            {
                throw new InvalidOperationException("You must be editing to perform this operation");
            }
            #endregion

            if (!isExistingOperation)
            {
                _editor.StartOperation();
                isOperationOpen = true;
            }

            try
            {
                using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser())
                {
                    ESRI.ArcGIS.Geodatabase.IFeatureClass cableFtClass = cable.Feature.Class as ESRI.ArcGIS.Geodatabase.IFeatureClass;
                    ESRI.ArcGIS.Geodatabase.IQueryFilter  filter       = new ESRI.ArcGIS.Geodatabase.QueryFilterClass();
                    releaser.ManageLifetime(filter);

                    filter.WhereClause = string.Format("{0}='{1}'", ConfigUtil.ConnectedCableFieldName, cable.IPID);
                    filter.SubFields   = string.Format("{0},{1},{2}", ConfigUtil.ConnectedCableFieldName, ConfigUtil.ConnectedFiberFieldName, ConfigUtil.ConnectedEndFieldName);

                    string[] deviceClassNames = ConfigUtil.DeviceFeatureClassNames;
                    for (int i = 0; i < deviceClassNames.Length; i++)
                    {
                        string deviceClassName = deviceClassNames[i];


                        ESRI.ArcGIS.Geodatabase.IFeatureClass deviceFtClass = _wkspHelper.FindFeatureClass(deviceClassName);
//                        ESRI.ArcGIS.Geodatabase.IFeatureClass deviceFtClass = GdbUtils.GetFeatureClass(cableFtClass, deviceClassName);
                        ESRI.ArcGIS.Geodatabase.ITable     portTable = ConfigUtil.GetPortTable(deviceFtClass);
                        ESRI.ArcGIS.Geodatabase.IRowBuffer buffer    = portTable.CreateRowBuffer();
                        // We want to set them to null, so we can just send the empty buffer
                        portTable.UpdateSearchedRows(filter, buffer);

                        ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(buffer);
                    }

                    if (isOperationOpen)
                    {
                        _editor.StopOperation("Break Connections");
                        isOperationOpen = false;
                    }

                    success = true;
                }
            }
            catch
            {
                if (isOperationOpen)
                {
                    _editor.AbortOperation();
                }

                success = false;
            }

            return(success);
        }
        /// <summary>
        /// Deletes given connections between cable to device
        /// </summary>
        /// <param name="cable">Cable</param>
        /// <param name="device">Device</param>
        /// <param name="units">Units to connect</param>
        /// <param name="portType">Input or Output?</param>
        /// <param name="isExistingOperation">Flag to control whether we need to wrap this in an edit operation</param>
        /// <returns>Success</returns>
        public bool BreakConnections(FiberCableWrapper cable, DeviceWrapper device, Dictionary <int, int> units, PortType portType, bool isExistingOperation)
        {
            bool success         = false;
            bool isOperationOpen = false;

            #region Validation
            if (null == cable)
            {
                throw new ArgumentNullException("cable");
            }

            if (null == device)
            {
                throw new ArgumentNullException("device");
            }

            if (null == units)
            {
                throw new ArgumentNullException("units");
            }

            if (ESRI.ArcGIS.Editor.esriEditState.esriStateNotEditing == _editor.EditState)
            {
                throw new InvalidOperationException("You must be editing to perform this operation");
            }
            #endregion

            if (0 < units.Count)
            {
                if (!isExistingOperation)
                {
                    _editor.StartOperation();
                    isOperationOpen = true;
                }

                try
                {
                    ESRI.ArcGIS.Geodatabase.IFeatureClass      deviceFtClass  = device.Feature.Class as ESRI.ArcGIS.Geodatabase.IFeatureClass;
                    ESRI.ArcGIS.Geodatabase.IRelationshipClass deviceHasPorts = ConfigUtil.GetPortRelationship(deviceFtClass);
                    if (null == deviceFtClass)
                    {
                        throw new Exception("Unable to find port relationship class.");
                    }

                    ESRI.ArcGIS.Geodatabase.ITable portTable = deviceHasPorts.DestinationClass as ESRI.ArcGIS.Geodatabase.ITable;
                    if (null == portTable)
                    {
                        throw new Exception("Invalid destination on port relationship class.");
                    }

                    using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser())
                    {
                        ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass();
                        releaser.ManageLifetime(filter);

                        StringBuilder inList = new StringBuilder(1024);
                        foreach (KeyValuePair <int, int> pair in units)
                        {
                            string appendFormat = "{0},";
                            if (PortType.Input == portType)
                            {
                                inList.AppendFormat(appendFormat, pair.Key);
                            }
                            else
                            {
                                inList.AppendFormat(appendFormat, pair.Value);
                            }
                        }
                        inList.Remove(inList.Length - 1, 1);

                        string format = "{0}='{1}' AND {2}='{3}' AND {4}='{5}' AND {6} IN ({7})";
                        filter.WhereClause = string.Format(format,
                                                           deviceHasPorts.OriginForeignKey,
                                                           device.Feature.get_Value(deviceFtClass.FindField(deviceHasPorts.OriginPrimaryKey)),
                                                           ConfigUtil.ConnectedCableFieldName,
                                                           cable.IPID,
                                                           ConfigUtil.PortTypeFieldName,
                                                           (PortType.Input == portType ? "1" : "2"),
                                                           ConfigUtil.ConnectedFiberFieldName,
                                                           inList.ToString());

                        filter.SubFields = string.Format("{0},{1},{2}", ConfigUtil.ConnectedEndFieldName, ConfigUtil.ConnectedFiberFieldName, ConfigUtil.ConnectedCableFieldName);

                        ESRI.ArcGIS.Geodatabase.IRowBuffer buffer = portTable.CreateRowBuffer();
                        releaser.ManageLifetime(buffer);
                        // We want to set them to null, so we can just send the empty buffer
                        portTable.UpdateSearchedRows(filter, buffer);

                        if (isOperationOpen)
                        {
                            _editor.StopOperation("Break Connections");
                            isOperationOpen = false;
                        }

                        success = true;
                    }
                }
                catch
                {
                    if (isOperationOpen)
                    {
                        _editor.AbortOperation();
                    }

                    success = false;
                }
            }

            return(success);
        }
        /// <summary>
        /// Creates given connections between cable and device
        /// </summary>
        /// <param name="cable">Cable</param>
        /// <param name="device">Device</param>
        /// <param name="units">Units to connect</param>
        /// <param name="isFromEnd">Is it the cable's from end?</param>
        /// <param name="portType">Input or Output?</param>
        /// <param name="isExistingOperation">Flag to control whether we need to wrap this in a new edit operation</param>
        /// <returns>Success</returns>
        public bool MakeConnections(FiberCableWrapper cable, DeviceWrapper device, Dictionary <int, int> units, bool isFromEnd, PortType portType, bool isExistingOperation)
        {
            bool success         = false;
            bool isOperationOpen = false;

            #region Validation
            if (null == cable)
            {
                throw new ArgumentNullException("cable");
            }

            if (null == device)
            {
                throw new ArgumentNullException("device");
            }

            if (null == units)
            {
                throw new ArgumentNullException("units");
            }

            if (ESRI.ArcGIS.Editor.esriEditState.esriStateNotEditing == _editor.EditState)
            {
                throw new InvalidOperationException("You must be editing to perform this operation");
            }
            #endregion

            if (!isExistingOperation)
            {
                _editor.StartOperation();
                isOperationOpen = true;
            }

            try
            {
                ESRI.ArcGIS.Geodatabase.IFeatureClass      deviceFtClass  = device.Feature.Class as ESRI.ArcGIS.Geodatabase.IFeatureClass;
                ESRI.ArcGIS.Geodatabase.IRelationshipClass deviceHasPorts = ConfigUtil.GetPortRelationship(deviceFtClass);
                if (null == deviceHasPorts)
                {
                    throw new Exception("Unable to get port relationship class.");
                }

                ESRI.ArcGIS.Geodatabase.ITable portTable = deviceHasPorts.DestinationClass as ESRI.ArcGIS.Geodatabase.ITable;
                if (null == portTable)
                {
                    throw new Exception("Invalid destination on port relationship class.");
                }

                int    portIdIdx      = portTable.FindField(ConfigUtil.PortIdFieldName);
                int    fiberNumberIdx = portTable.FindField(ConfigUtil.ConnectedFiberFieldName);
                int    cableIdIdx     = portTable.FindField(ConfigUtil.ConnectedCableFieldName);
                int    isFromEndIdx   = portTable.FindField(ConfigUtil.ConnectedEndFieldName);
                string isFromEndValue = isFromEnd ? "T" : "F";

                Dictionary <int, int> portsAsKeys = units;
                if (PortType.Input == portType)
                {
                    portsAsKeys = new Dictionary <int, int>();
                    foreach (KeyValuePair <int, int> pair in units)
                    {
                        portsAsKeys[pair.Value] = pair.Key;
                    }
                }

                using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser())
                {
                    ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass();
                    releaser.ManageLifetime(filter);

                    string format = "{0}='{1}' AND {2}='{3}'";
                    filter.WhereClause = string.Format(format,
                                                       deviceHasPorts.OriginForeignKey,
                                                       device.Feature.get_Value(deviceFtClass.FindField(deviceHasPorts.OriginPrimaryKey)),
                                                       ConfigUtil.PortTypeFieldName,
                                                       (PortType.Input == portType ? "1" : "2"));

                    // Non recylcing cursor since we are doing updates.
                    ESRI.ArcGIS.Geodatabase.ICursor portCursor = portTable.Update(filter, false);
                    releaser.ManageLifetime(portCursor);

                    ESRI.ArcGIS.Geodatabase.IRow portRow = portCursor.NextRow();
                    while (null != portRow)
                    {
                        object portIdObj = portRow.get_Value(portIdIdx);
                        if (DBNull.Value != portIdObj)
                        {
                            int portId = System.Convert.ToInt32(portIdObj);
                            if (portsAsKeys.ContainsKey(portId))
                            {
                                portRow.set_Value(cableIdIdx, cable.IPID);
                                portRow.set_Value(isFromEndIdx, isFromEndValue);
                                portRow.set_Value(fiberNumberIdx, portsAsKeys[portId]);
                                portRow.Store();
                            }
                        }

                        ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(portRow);
                        portRow = portCursor.NextRow();
                    }

                    if (isOperationOpen)
                    {
                        _editor.StopOperation("Create Connections");
                        isOperationOpen = false;
                    }

                    success = true;
                }
            }
            catch (Exception ex)
            {
                if (isOperationOpen)
                {
                    _editor.AbortOperation();
                }

                success = false;

                throw new Exception("Save operation failed.");
            }

            return(success);
        }
        /// <summary>
        /// Returns a list of connections between the cable and the device, at the cable's given end, to the device's given port type
        /// </summary>
        /// <param name="cable">Cable to check</param>
        /// <param name="device">Device to check</param>
        /// <param name="isFromEnd">Digitized end of cable</param>
        /// <param name="portType">Input or output</param>
        /// <returns>List of Connection</returns>
        public List <Connection> GetConnections(FiberCableWrapper cable, DeviceWrapper device, bool isFromEnd, PortType portType)
        {
            if (null == cable)
            {
                throw new ArgumentNullException("cable");
            }

            if (null == device)
            {
                throw new ArgumentNullException("device");
            }

            List <Connection> result  = new List <Connection>();
            List <int>        ports   = new List <int>();
            List <int>        strands = new List <int>();

            using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser())
            {
                ESRI.ArcGIS.Geodatabase.IFeatureClass      deviceFtClass  = device.Feature.Class as ESRI.ArcGIS.Geodatabase.IFeatureClass;
                ESRI.ArcGIS.Geodatabase.IRelationshipClass deviceHasPorts = ConfigUtil.GetPortRelationship(deviceFtClass);
                if (null == deviceHasPorts)
                {
                    throw new Exception("Unable to find port relationship class.");
                }

                ESRI.ArcGIS.Geodatabase.ITable portTable = deviceHasPorts.DestinationClass as ESRI.ArcGIS.Geodatabase.ITable;
                if (null == portTable)
                {
                    throw new Exception("Invalid destination on port relationship class.");
                }

                ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass();
                releaser.ManageLifetime(filter);
                filter.WhereClause = string.Format("{0}='{1}' AND {2}='{3}' AND {4}='{5}' AND {6}='{7}' AND {8} IS NOT NULL AND {9} IS NOT NULL",
                                                   deviceHasPorts.OriginForeignKey,
                                                   device.Feature.get_Value(deviceFtClass.FindField(deviceHasPorts.OriginPrimaryKey)),
                                                   ConfigUtil.ConnectedCableFieldName,
                                                   cable.IPID,
                                                   ConfigUtil.PortTypeFieldName,
                                                   (PortType.Input == portType ? "1" : "2"),
                                                   ConfigUtil.ConnectedEndFieldName,
                                                   (isFromEnd ? "T" : "F"),
                                                   ConfigUtil.ConnectedFiberFieldName,
                                                   ConfigUtil.PortIdFieldName);


                // ORDER BY does not work outside of SDE.
                // Removing for now, should not be important.
                string orderFormat = "ORDER BY {0}";
                if (PortType.Input == portType)
                {
//                    ((ESRI.ArcGIS.Geodatabase.IQueryFilterDefinition2)filter).PostfixClause = string.Format(orderFormat, ConfigUtil.ConnectedFiberFieldName);
                }
                else
                {
//                    ((ESRI.ArcGIS.Geodatabase.IQueryFilterDefinition2)filter).PostfixClause = string.Format(orderFormat, ConfigUtil.PortIdFieldName);
                }

                ESRI.ArcGIS.Geodatabase.ICursor portCursor = portTable.Search(filter, true);
                ESRI.ArcGIS.Geodatabase.IRow    portRow    = portCursor.NextRow();

                int portIdIdx      = portTable.FindField(ConfigUtil.PortIdFieldName);
                int fiberNumberIdx = portTable.FindField(ConfigUtil.ConnectedFiberFieldName);

                while (null != portRow)
                {
                    ports.Add((int)portRow.get_Value(portIdIdx));
                    strands.Add((int)portRow.get_Value(fiberNumberIdx));

                    ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(portRow);
                    portRow = portCursor.NextRow();
                }

                ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(portCursor);
            }


            List <Range> portRanges   = SpliceAndConnectionUtils.MergeRanges(ports);
            List <Range> strandRanges = SpliceAndConnectionUtils.MergeRanges(strands);

            if (PortType.Input == portType)
            {
                result = SpliceAndConnectionUtils.MatchUp(strandRanges, portRanges);
            }
            else
            {
                result = SpliceAndConnectionUtils.MatchUp(portRanges, strandRanges);
            }

            return(result);
        }
        /// <summary>
        /// Check changes to the grid and save them to the database
        /// </summary>
        /// <param name="splice">The associated splice closure</param>
        /// <param name="cableA">A cable</param>
        /// <param name="cableB">The other cable</param>
        /// <returns>Success</returns>
        private bool SaveChanges(SpliceClosureWrapper splice, FiberCableWrapper cableA, SpliceableCableWrapper cableB)
        {
            bool   result        = false;
            string isNotOkString = string.Empty;

            Dictionary <int, FiberSplice> currentGrid = new Dictionary <int, FiberSplice>();
            List <int> currentBStrands = new List <int>();

            try
            {
                int aIdx    = colRangeA.Index;
                int bIdx    = colRangeB.Index;
                int lossIdx = colLoss.Index;
                int typeIdx = grdSplices.Columns[colType.Name].Index; // If we had to use colTypeText, it will be using the same name

                // Less than count-1 lets us avoid the insert row
                for (int i = 0; i < grdSplices.Rows.Count - 1; i++)
                {
                    if (grdSplices[aIdx, i].Value == null || grdSplices[bIdx, i].Value == null)
                    {
                        isNotOkString = "A or B unit range missing.";
                    }
                    if (0 < isNotOkString.Length)
                    {
                        // No need to check the rest if this one was not OK
                        break;
                    }

                    List <Range> aRanges = SpliceAndConnectionUtils.ParseRanges(grdSplices[aIdx, i].Value.ToString());
                    List <Range> bRanges = SpliceAndConnectionUtils.ParseRanges(grdSplices[bIdx, i].Value.ToString());

                    if (!SpliceAndConnectionUtils.AreCountsEqual(aRanges, bRanges))
                    {
                        isNotOkString = "Number of units from A to B must match on each row.";
                    }
                    else if (!SpliceAndConnectionUtils.AreRangesWithinFiberCount(aRanges, cableA))
                    {
                        isNotOkString = "Selected units exceed fiber count for cable A.";
                    }
                    else if (!SpliceAndConnectionUtils.AreRangesWithinFiberCount(bRanges, cableB))
                    {
                        isNotOkString = "Selected units exceed fiber count for cable B.";
                    }

                    if (0 < isNotOkString.Length)
                    {
                        // No need to check the rest if this one was not OK
                        break;
                    }

                    List <Connection> matchedUp = SpliceAndConnectionUtils.MatchUp(aRanges, bRanges);
                    foreach (Connection range in matchedUp)
                    {
                        Range a        = range.ARange;
                        Range b        = range.BRange;
                        int   numUnits = a.High - a.Low + 1;
                        for (int offset = 0; offset < numUnits; offset++)
                        {
                            int aUnit = a.Low + offset;
                            int bUnit = b.Low + offset;

                            if (currentGrid.ContainsKey(aUnit))
                            {
                                isNotOkString = string.Format("Duplicate splicing found for A Strand {0}", aUnit);
                                // No need to check the rest if this one was not OK
                                break;
                            }
                            else if (currentBStrands.Contains(bUnit))
                            {
                                isNotOkString = string.Format("Duplicate splicing found for B Strand {0}", bUnit);
                                // No need to check the rest if this one was not OK
                                break;
                            }
                            else
                            {
                                object lossObj = grdSplices[lossIdx, i].Value;
                                object typeObj = grdSplices[typeIdx, i].Value;

                                double?loss = null;
                                if (null != lossObj)
                                {
                                    double dblLoss = -1;
                                    if (double.TryParse(lossObj.ToString(), out dblLoss))
                                    {
                                        loss = dblLoss;
                                    }
                                    else
                                    {
                                        MessageBox.Show("Loss value on row {0} could not be parsed. Using null.", "Splice Editor", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                                    }
                                }

                                FiberSplice fiberSplice = new FiberSplice(new Range(aUnit, aUnit), new Range(bUnit, bUnit), loss, typeObj);
                                currentGrid[aUnit] = fiberSplice;
                                currentBStrands.Add(bUnit);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                isNotOkString = ex.Message;
            }


            // Check the ranges are within the feature's units
            List <int> checkToUnits   = new List <int>();
            List <int> checkFromUnits = new List <int>();

            // Anything that is in the current grid, we will see if it is available. But if it was deleted, we can ignore
            // checking its availabilty, because we are about to free it up. Also if it was original, we can ignore it,
            // since we are reprocessing it. Duplicates ON the grid have already been checked for.
            // NOTE: We can simplify this to just check original, since any deleted ones were in the original.
            foreach (FiberSplice checkSplice in currentGrid.Values)
            {
                int unit = checkSplice.BRange.Low;
                checkToUnits.Add(unit);
            }

            foreach (FiberSplice checkSplice in _original.Values)
            {
                int unit = checkSplice.BRange.Low;
                if (checkToUnits.Contains(unit))
                {
                    checkToUnits.Remove(unit);
                }
            }

            foreach (int fromUnit in currentGrid.Keys)
            {
                if (!_original.ContainsKey(fromUnit))
                {
                    checkFromUnits.Add(fromUnit);
                }
            }

            if (!SpliceAndConnectionUtils.AreRangesAvailable(checkFromUnits, cableA, cableB.IsOtherFromEnd))
            {
                isNotOkString = "Some A units are not in the available ranges for the A Cable.";
            }
            else if (!SpliceAndConnectionUtils.AreRangesAvailable(checkToUnits, cableB, cableB.IsThisFromEnd))
            {
                isNotOkString = "Some B units are not in the available ranges for the B Cable.";
            }

            if (0 < isNotOkString.Length)
            {
                string message = string.Format("{0}\nPlease correct this and try again.", isNotOkString);
                MessageBox.Show(message, "Splice Editor", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                if (null != cableA && null != cableB)
                {
                    // For the deleted ones, if they were added back, don't delete them...
                    List <int> keys = new List <int>();
                    keys.AddRange(_deleted.Keys);
                    foreach (int key in keys)
                    {
                        if (currentGrid.ContainsKey(key))
                        {
                            FiberSplice fiberSplice = currentGrid[key];
                            if (fiberSplice.BRange.Low == _deleted[key].BRange.Low &&
                                fiberSplice.Loss == _deleted[key].Loss &&
                                fiberSplice.Type == _deleted[key].Type)
                            {
                                // It is added back, so don't delete it
                                _deleted.Remove(key);
                            }
                        }
                    }

                    if (0 < _deleted.Count)
                    {
                        _spliceHelper.BreakSplices(cableA, cableB, splice, _deleted, false);
                    }

                    // For the added ones, if they already exist or are not available, don't add them
                    // Since we already know they are in the fiber count range, the only problem would be if they were already
                    // spliced. This would be the case if (1) it was part of the original or (2) has already appeared higher
                    // on the currentGrid. (2) is handled when building currentGrid, by checking if the aUnit or bUnit was already used.
                    keys.Clear();
                    keys.AddRange(currentGrid.Keys);
                    foreach (int key in keys)
                    {
                        if (_original.ContainsKey(key))
                        {
                            FiberSplice fiberSplice = currentGrid[key];
                            if (fiberSplice.BRange.Low == _original[key].BRange.Low &&
                                fiberSplice.Loss == _original[key].Loss &&
                                fiberSplice.Type == _original[key].Type)
                            {
                                // It was on the original, so we don't need to create it
                                currentGrid.Remove(key);
                            }
                        }
                    }

                    if (0 < currentGrid.Count)
                    {
                        _spliceHelper.CreateSplices(cableA, cableB, splice, currentGrid, false);
                    }

                    // These are no longer part of the originals
                    foreach (KeyValuePair <int, FiberSplice> deletedPair in _deleted)
                    {
                        _original.Remove(deletedPair.Key);
                    }

                    // These are now part of the originals
                    foreach (KeyValuePair <int, FiberSplice> addedPair in currentGrid)
                    {
                        _original[addedPair.Key] = addedPair.Value;
                    }

                    _deleted.Clear(); // The grid is fresh

                    // Set the existing rows as committed data. Less than count-1 lets us avoid the insert row
                    for (int i = 0; i < grdSplices.Rows.Count - 1; i++)
                    {
                        grdSplices.Rows[i].ReadOnly = true;
                    }

                    btnSave.Enabled = false;
                    btnSave.Tag     = false; // No edits made yet
                    result          = true;
                }
            }

            return(result);
        }
        /// <summary>
        /// Ripple down from the desired start point tracing and highlighting the results.
        /// </summary>
        public void TraceTriggered(FeatureWrapper feature, int unit, PortType port = PortType.Input)
        {
            try
            {
                if (null == feature)
                {
                    throw new ArgumentNullException("FeatureWrapper");
                }

                FiberCableWrapper fiberCableWrapper = feature as FiberCableWrapper;
                DeviceWrapper     deviceWrapper     = feature as DeviceWrapper;
                int fiberNumber = unit;

                _startedOnFiber = true;
                if (null != deviceWrapper)
                {
                    fiberCableWrapper = GetConnectedFiber(deviceWrapper, unit, port, out fiberNumber);
                    _startedOnFiber   = false;
                }

                List <Range> traceRange = new List <Range>(new Range[] { new Range(fiberNumber, fiberNumber) });

                if (null != fiberCableWrapper)
                {
                    if (SpliceAndConnectionUtils.AreRangesWithinFiberCount(traceRange, fiberCableWrapper))
                    {
                        ESRI.ArcGIS.Geodatabase.IFeature ft = fiberCableWrapper.Feature;

                        _traceResults.Clear();
                        _traceResults = TracePath(ft, fiberNumber, true);
                        _traceResults.Reverse(); // This went down the "from end", so they are backwards

                        _startFiberIdx = _traceResults.Count;

                        // Now add ourselves
                        _traceResults.Add(ft);
                        _traceResults.Add(GetFiberRecord(ft, fiberNumber));

                        // Now add everything going the other way
                        List <ESRI.ArcGIS.Geodatabase.IRow> resultsAtToEnd = TracePath(ft, fiberNumber, false);
                        _traceResults.AddRange(resultsAtToEnd);

                        if (TraceCompleted != null)
                        {
                            TraceCompleted(this, null);
                        }
                    }
                    else
                    {
                        System.Windows.Forms.MessageBox.Show("Fiber strand number is not within the fiber cable's number of fibers.", "Telecom Trace", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
                    }
                }
                else
                {
                    System.Windows.Forms.MessageBox.Show("No fiber cable / strand was specified, or none was connected to the specified port.", "Telecom Trace", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
                }

                // ---------------------------------------
                // This causes a refresh of the selection
                // and we see the results of the trace on
                // the map
                // ---------------------------------------
                _hookHelper.ActiveView.PartialRefresh(ESRI.ArcGIS.Carto.esriViewDrawPhase.esriViewGeoSelection, null, null);
                //               ActiveView.PartialRefresh(ESRI.ArcGIS.Carto.esriViewDrawPhase.esriViewGeoSelection, null, null);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Trace.WriteLine(ex.Message, "ERROR");
                System.Diagnostics.Trace.WriteLine(ex.StackTrace, "DETAILS");
            }
            finally
            {
            }
        }
        private FiberCableWrapper GetConnectedFiber(DeviceWrapper device, int portId, PortType portType, out int fiberNumber)
        {
            FiberCableWrapper result = null;

            fiberNumber = -1;

            ESRI.ArcGIS.Geodatabase.IFeatureClass      deviceFtClass  = (ESRI.ArcGIS.Geodatabase.IFeatureClass)device.Feature.Class;
            ESRI.ArcGIS.Geodatabase.IRelationshipClass deviceHasPorts = ConfigUtil.GetPortRelationship(deviceFtClass);
            if (null == deviceHasPorts)
            {
                throw new Exception("Device to port relationship is missing or cannot be opened.");
            }

            ESRI.ArcGIS.Geodatabase.ITable portTable = deviceHasPorts.DestinationClass as ESRI.ArcGIS.Geodatabase.ITable;
            if (null == portTable)
            {
                throw new Exception("Port table is missing or cannot be opened.");
            }


            using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser())
            {
                ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass();
                releaser.ManageLifetime(filter);
                filter.WhereClause = string.Format("{0}='{1}' AND {2}={3} AND {4}='{5}'",
                                                   deviceHasPorts.OriginForeignKey,
                                                   device.Feature.get_Value(deviceFtClass.FindField(deviceHasPorts.OriginPrimaryKey)),
                                                   ConfigUtil.PortIdFieldName,
                                                   portId,
                                                   ConfigUtil.PortTypeFieldName,
                                                   PortType.Input == portType ? 1 : 2);

                ESRI.ArcGIS.Geodatabase.ICursor cursor = portTable.Search(filter, false);
                releaser.ManageLifetime(cursor);
                ESRI.ArcGIS.Geodatabase.IRow portRow = cursor.NextRow();

                if (null != portRow)
                {
                    //releaser.ManageLifetime(portRow);

                    object cableIdValue = portRow.get_Value(portTable.FindField(ConfigUtil.ConnectedCableFieldName));
                    if (DBNull.Value != cableIdValue)
                    {
                        ESRI.ArcGIS.Geodatabase.IFeatureClass cableFtClass = _wkspHelper.FindFeatureClass(ConfigUtil.FiberCableFtClassName);
                        filter.WhereClause = string.Format("{0}='{1}'", ConfigUtil.IpidFieldName, cableIdValue);
                        ESRI.ArcGIS.Geodatabase.IFeatureCursor cableCursor = cableFtClass.Search(filter, false);
                        releaser.ManageLifetime(cableCursor);

                        ESRI.ArcGIS.Geodatabase.IFeature cable = cableCursor.NextFeature();
                        if (null != cable)
                        {
                            result = new FiberCableWrapper(cable);
                            object fiberNumberValue = portRow.get_Value(portTable.FindField(ConfigUtil.ConnectedFiberFieldName));
                            if (DBNull.Value != fiberNumberValue)
                            {
                                int.TryParse(fiberNumberValue.ToString(), out fiberNumber);
                            }
                        }
                    }
                }
            }

            return(result);
        }
        /// <summary>
        /// A "from" item has been selected; load "to" choices
        /// </summary>
        private void cboFrom_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!_isReverting)
            {
                bool isChangeAccepted = !btnSave.Enabled; // If the save button is disabled, there is no reason to cancel the change

                if (!isChangeAccepted)
                {
                    // Get the current to feature and the from feature that was selected before the index changed, so we can
                    // prompt for unsaved edits
                    FeatureWrapper to            = cboTo.SelectedItem as FeatureWrapper;
                    FeatureWrapper preChangeFrom = null;
                    if (-1 < _lastSelectedFromIdx &&
                        _lastSelectedFromIdx < cboFrom.Items.Count)
                    {
                        preChangeFrom = cboFrom.Items[_lastSelectedFromIdx] as FeatureWrapper;
                    }

                    isChangeAccepted = IsUserSure(preChangeFrom, to);
                }

                if (isChangeAccepted)
                {
                    // The current index is committed
                    _lastSelectedFromIdx = cboFrom.SelectedIndex;

                    // Unload anything that is dependent on the selection of the From Feature
                    ClearGrid();
                    cboTo.Items.Clear();
                    lblAvailableFrom.Text = "";
                    lblAvailableTo.Text   = "";

                    if (null != cboFrom.SelectedItem)
                    {
                        FiberCableWrapper cableWrapper  = cboFrom.SelectedItem as FiberCableWrapper;
                        DeviceWrapper     deviceWrapper = cboFrom.SelectedItem as DeviceWrapper;

                        if (null != cableWrapper)
                        {
                            List <ConnectableDeviceWrapper> devices = _connectionHelper.GetCoincidentDevices(cableWrapper);

                            for (int i = 0; i < devices.Count; i++)
                            {
                                cboTo.Items.Add(devices[i]);
                            }
                        }
                        else if (null != deviceWrapper)
                        {
                            List <ConnectableCableWrapper> cables = _connectionHelper.GetCoincidentCables(deviceWrapper);

                            for (int i = 0; i < cables.Count; i++)
                            {
                                cboTo.Items.Add(cables[i]);
                            }
                        }

                        // Preselect the first item
                        if (0 < cboTo.Items.Count)
                        {
                            cboTo.SelectedItem = cboTo.Items[0];
                        }
                    }
                }
                else
                {
                    // Cancel the change by re-selecting the previous from feature
                    _isReverting          = true;
                    cboFrom.SelectedIndex = _lastSelectedFromIdx;
                    _isReverting          = false;
                }
            }
        }
        /// <summary>
        /// Check changes to the grid and save them to the database
        /// </summary>
        /// <param name="from">From feature</param>
        /// <param name="to">To feature</param>
        /// <returns>Success</returns>
        private bool SaveChanges(FeatureWrapper from, FeatureWrapper to)
        {
            bool   result        = false;
            string isNotOkString = string.Empty;

            Dictionary <int, int> currentGrid = new Dictionary <int, int>();
            FiberCableWrapper     cable       = null;
            DeviceWrapper         device      = null;
            bool     isFromEnd = false;
            PortType portType  = PortType.Input;

            #region Detect Direction
            try
            {
                if (from is FiberCableWrapper && to is ConnectableDeviceWrapper)
                {
                    cable     = cboFrom.SelectedItem as FiberCableWrapper;
                    device    = cboTo.SelectedItem as DeviceWrapper;
                    isFromEnd = ((ConnectableDeviceWrapper)device).IsCableFromEnd;
                    portType  = PortType.Input;
                }
                else if (from is DeviceWrapper && to is ConnectableCableWrapper)
                {
                    device    = cboFrom.SelectedItem as DeviceWrapper;
                    cable     = cboTo.SelectedItem as FiberCableWrapper;
                    isFromEnd = ((ConnectableCableWrapper)cable).IsThisFromEnd;
                    portType  = PortType.Output;
                }
                else
                {
                    isNotOkString = "Must connect a cable to a device, or device to a cable.";
                }
            }
            catch (Exception ex)
            {
                isNotOkString = ex.Message;
            }
            #endregion

            try
            {
                if (null != cable && null != device)
                {
                    // Only continue if we have a valid setup
                    try
                    {
                        int aIdx = colFromRange.Index;
                        int bIdx = colToRange.Index;

                        // Less than count-1 lets us avoid the insert row
                        for (int i = 0; i < grdConnections.Rows.Count - 1; i++)
                        {
                            object       aRanges    = (grdConnections[aIdx, i].Value != null ? grdConnections[aIdx, i].Value : "");
                            object       bRanges    = (grdConnections[bIdx, i].Value != null ? grdConnections[bIdx, i].Value : "");
                            List <Range> fromRanges = SpliceAndConnectionUtils.ParseRanges(aRanges.ToString());
                            List <Range> toRanges   = SpliceAndConnectionUtils.ParseRanges(bRanges.ToString());

                            // Check that counts match up
                            if (!SpliceAndConnectionUtils.AreCountsEqual(fromRanges, toRanges))
                            {
                                isNotOkString = "Number of units from A to B must match on each row.";
                            }

                            // Check the ranges are within the feature's units
                            if (PortType.Input == portType)
                            {
                                if (!SpliceAndConnectionUtils.AreRangesWithinFiberCount(fromRanges, cable))
                                {
                                    isNotOkString = "Selected units exceed fiber count for cable.";
                                }
                                else if (!SpliceAndConnectionUtils.AreRangesWithinPortCount(toRanges, device, portType))
                                {
                                    isNotOkString = "Selected units exceed input port count for device.";
                                }
                            }
                            else
                            {
                                if (!SpliceAndConnectionUtils.AreRangesWithinFiberCount(toRanges, cable))
                                {
                                    isNotOkString = "Selected units exceed fiber count for cable.";
                                }
                                else if (!SpliceAndConnectionUtils.AreRangesWithinPortCount(fromRanges, device, portType))
                                {
                                    isNotOkString = "Selected units exceed output port count for device.";
                                }
                            }

                            if (0 < isNotOkString.Length)
                            {
                                // No need to check the rest if this one was not OK
                                break;
                            }

                            List <Connection> matchedUp = SpliceAndConnectionUtils.MatchUp(fromRanges, toRanges);
                            foreach (Connection connection in matchedUp)
                            {
                                Range a        = connection.ARange;
                                Range b        = connection.BRange;
                                int   numUnits = a.High - a.Low + 1;
                                for (int offset = 0; offset < numUnits; offset++)
                                {
                                    int aUnit = a.Low + offset;
                                    int bUnit = b.Low + offset;

                                    if (currentGrid.ContainsKey(aUnit) ||
                                        currentGrid.ContainsValue(bUnit))
                                    {
                                        isNotOkString = string.Format("Duplicate connection found from {0} to {1}.", aUnit, bUnit);
                                        // No need to check the rest if this one was not OK
                                        break;
                                    }
                                    else
                                    {
                                        currentGrid[aUnit] = bUnit;
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        isNotOkString = ex.Message;
                        MessageBox.Show(ex.Message);
                    }

                    // Check the ranges are within the feature's units
                    List <int> checkToUnits   = new List <int>();
                    List <int> checkFromUnits = new List <int>();

                    // Anything that is in the current grid, we will see if it is available. But if it was deleted, we can ignore
                    // checking its availabilty, because we are about to free it up. Also if it was original, we can ignore it,
                    // since we are reprocessing it. Duplicates ON the grid have already been checked for.
                    // NOTE: We can simplify this to just check original, since any deleted ones were in the original.
                    foreach (int toUnit in currentGrid.Values)
                    {
                        if (!_original.ContainsValue(toUnit))
                        {
                            checkToUnits.Add(toUnit);
                        }
                    }

                    foreach (int fromUnit in currentGrid.Keys)
                    {
                        if (!_original.ContainsKey(fromUnit))
                        {
                            checkFromUnits.Add(fromUnit);
                        }
                    }

                    if (PortType.Input == portType)
                    {
                        if (!SpliceAndConnectionUtils.AreRangesAvailable(checkToUnits, device, portType))
                        {
                            isNotOkString = "Some To units are not in the available ranges for the device.";
                        }
                        else if (!SpliceAndConnectionUtils.AreRangesAvailable(checkFromUnits, cable, isFromEnd))
                        {
                            isNotOkString = "Some From units are not in the available ranges for the cable.";
                        }
                    }
                    else
                    {
                        if (!SpliceAndConnectionUtils.AreRangesAvailable(checkFromUnits, device, portType))
                        {
                            isNotOkString = "Some From units are not in the available ranges for the device.";
                        }
                        else if (!SpliceAndConnectionUtils.AreRangesAvailable(checkToUnits, cable, isFromEnd))
                        {
                            isNotOkString = "Some To units are not in the available ranges for the cable.";
                        }
                    }

                    if (0 == isNotOkString.Length)
                    {
                        // For the deleted ones, if they were added back, don't delete them...
                        List <int> keys = new List <int>();
                        keys.AddRange(_deleted.Keys);
                        foreach (int key in keys)
                        {
                            if (currentGrid.ContainsKey(key) &&
                                currentGrid[key] == _deleted[key])
                            {
                                // It is added back, so don't delete it
                                _deleted.Remove(key);
                            }
                        }

                        _connectionHelper.BreakConnections(cable, device, _deleted, portType, false);

                        // For the added ones, if they already exist or are not available, don't add them
                        // Since we already know they are in the fiber count range, the only problem would be if they were already
                        // spliced. This would be the case if (1) it was part of the original, (2) has already appeared higher
                        // on the currentGrid, (3) is spliced to something else. (2) is handled when building currentGrid, by checking
                        // if the aUnit or bUnit was already used and (3) is checked in the AreRangesAvailable checks. So now we will
                        // confirm (1)...
                        keys.Clear();
                        keys.AddRange(currentGrid.Keys);
                        foreach (int key in keys)
                        {
                            if (_original.ContainsKey(key) &&
                                _original[key] == currentGrid[key])
                            {
                                currentGrid.Remove(key);
                            }
                        }

                        _connectionHelper.MakeConnections(cable, device, currentGrid, isFromEnd, portType, false);

                        // These are no longer part of the originals
                        foreach (int deletedKey in _deleted.Keys)
                        {
                            _original.Remove(deletedKey);
                        }

                        // These are now part of the originals
                        foreach (KeyValuePair <int, int> addedPair in currentGrid)
                        {
                            _original[addedPair.Key] = addedPair.Value;
                        }

                        _deleted.Clear(); // The grid is fresh

                        // Set the existing rows as committed data. Less than count-1 lets us avoid the insert row
                        for (int i = 0; i < grdConnections.Rows.Count - 1; i++)
                        {
                            grdConnections.Rows[i].ReadOnly = true;
                        }

                        btnSave.Enabled = false;
                        btnSave.Tag     = false; // No edits have been made
                        result          = true;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.ToString());
            }

            if (0 < isNotOkString.Length)
            {
                string message = string.Format("{0}\nPlease correct this and try again.", isNotOkString);
                MessageBox.Show(message, "Connection Editor", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return(result);
        }