Exemplo n.º 1
0
        /// <summary>
        /// Splice closure features can have related:
        ///         splice records
        /// </summary>
        /// <param name="spliceFt">Deleted IFeature</param>
        private void CascadeSpliceClosureDelete(ESRI.ArcGIS.Geodatabase.IFeature spliceFt)
        {
            SpliceClosureWrapper splice = new SpliceClosureWrapper(spliceFt);

            // Delete fiber splices
            _spliceHelper.BreakAllSplices(splice, true);
        }
        /// <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);
            }
        }
        /// <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);
            }
        }
Exemplo n.º 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);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Deletes all splices at a splice closure
        /// </summary>
        /// <param name="splice">Splice</param>
        /// <param name="isExistingOperation">Are we already in an edit operation?</param>
        /// <returns>Success</returns>
        public bool BreakAllSplices(SpliceClosureWrapper splice, bool isExistingOperation)
        {
            bool success         = false;
            bool isOperationOpen = false;

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

            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(splice.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}'",
                                                   ConfigUtil.SpliceClosureIpidFieldName,
                                                   splice.IPID);

                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>
        /// 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>
        /// 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>
        /// 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());
            }
        }
Exemplo n.º 12
0
        //public static FiberSpliceConnectionHelper Instance(object hook, ESRI.ArcGIS.Editor.IEditor editor)
        //{
        //    if (_instance != null)
        //    {
        //        return _instance;
        //    }
        //    else
        //    {
        //        _instance = new FiberSpliceConnectionHelper(hook, editor);
        //        return _instance;
        //    }
        //}


        /// <summary>
        /// Gets a list of cable features that are connected to the splice closure in the geometric network
        /// </summary>
        /// <param name="spliceClosure">Splice to check</param>
        /// <returns>List of IFeature</returns>
        public List <ESRI.ArcGIS.Geodatabase.IFeature> GetConnectedCables(SpliceClosureWrapper spliceClosure)
        {
            // At the time of this comment, splicable means they are connected in the
            // geometric network and the splice closure "touches" one of the ends of the cable
            List <ESRI.ArcGIS.Geodatabase.IFeature> result = new List <ESRI.ArcGIS.Geodatabase.IFeature>();

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

            ESRI.ArcGIS.Geometry.IRelationalOperator relOp = spliceClosure.Feature.Shape as ESRI.ArcGIS.Geometry.IRelationalOperator;
            if (relOp == null)
            {
                throw new ArgumentNullException("spliceClosure");
            }

            ESRI.ArcGIS.Geodatabase.ISimpleJunctionFeature junction = spliceClosure.Feature as ESRI.ArcGIS.Geodatabase.ISimpleJunctionFeature;
            if (null != junction)
            {
                for (int i = 0; i < junction.EdgeFeatureCount; i++)
                {
                    ESRI.ArcGIS.Geodatabase.IFeature connectedEdge = junction.get_EdgeFeature(i) as ESRI.ArcGIS.Geodatabase.IFeature;
                    ESRI.ArcGIS.Geodatabase.IDataset dataset       = connectedEdge.Class as ESRI.ArcGIS.Geodatabase.IDataset;
                    string ftClassName = GdbUtils.ParseTableName(dataset);

                    if (0 == string.Compare(ftClassName, ConfigUtil.FiberCableFtClassName, true))
                    {
                        // Test feature edge is coincident with splice closure. Cables are
                        // complex features so splice might lie half way along some cables
                        // but will not be providing any splice connectivity to them.
                        if (relOp.Touches(connectedEdge.Shape)) // only true if point at either end of a line
                        {
                            result.Add(connectedEdge);
                        }
                    }
                }
            }

            return(result);
        }
        /// <summary>
        /// Load the drop down of selected splice closures
        /// </summary>
        /// <param name="helper">SpliceEditorHelper</param>
        private void PopulateSpliceClosures(FiberSpliceHelper helper)
        {
            try
            {
                // Clear anything that is dependent on what we are about to load
                ClearGrid();
                cboCableA.Items.Clear();
                cboCableB.Items.Clear();
                cboSpliceClosure.Items.Clear();
                lblAvailableA.Text = "";
                lblAvailableB.Text = "";

                // Find the layer
                ESRI.ArcGIS.Carto.IFeatureLayer ftLayer = _hookHelper.FindFeatureLayer(ConfigUtil.SpliceClosureFtClassName);
                if (ftLayer == null)
                {
                    ArcMap.Application.StatusBar.set_Message(0, "Telecom Tools error occurred. Check log for details.");
                    _logHelper.addLogEntry(DateTime.Now.ToString(), "ERROR", "Could not find Feature Layer:.", ConfigUtil.SpliceClosureFtClassName);
                    return;
                }
                int displayIdx = ftLayer.FeatureClass.FindField(ftLayer.DisplayField);

                // Get the selection on this layer
                List <ESRI.ArcGIS.Geodatabase.IFeature> selectedSplices = _hookHelper.GetSelectedFeatures(ftLayer);

                for (int i = 0; i < selectedSplices.Count; i++)
                {
                    SpliceClosureWrapper w = new SpliceClosureWrapper(selectedSplices[i], displayIdx);
                    cboSpliceClosure.Items.Add(w);
                }

                if (0 < cboSpliceClosure.Items.Count)
                {
                    cboSpliceClosure.SelectedItem = cboSpliceClosure.Items[0];
                }
            }
            catch (Exception e)
            {
                _logHelper.addLogEntry(DateTime.Now.ToString(), "ERROR", "Splice Connection Window (PopulateSpliceClosures): ", e.Message);
            }
        }
        /// <summary>
        /// Returns true if a SpliceClosure has splice connections associated with it, otherwise returns false.
        /// </summary>
        /// <param name="closure">Closure to check</param>
        /// <returns>Boolean</returns>
        public static bool SpliceClosureHasConnections(SpliceClosureWrapper closure)
        {
            #region Validation
            if (null == closure)
            {
                throw new ArgumentNullException("closure");
            }
            #endregion

            bool result = false;

            ESRI.ArcGIS.Geodatabase.IFeatureClass closureFtClass = closure.Feature.Class as ESRI.ArcGIS.Geodatabase.IFeatureClass;

            // Find the SpliceClosure to Splice Relationship class name
            // and test for the number of related obects
            String spliceClosureToSpliceRelClassName = ConfigUtil.SpliceClosureToSpliceRelClassName;
            int    featureCount = GdbUtils.GetRelatedObjectCount(closure.Feature, spliceClosureToSpliceRelClassName);
            if (featureCount > 0)
            {
                result = true;
            }

            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>
        /// Get the existing splice ranges between two cables at an existing closure
        /// </summary>
        /// <param name="cableA">One cable</param>
        /// <param name="cableB">Other cable</param>
        /// <param name="splice">Splice Closure</param>
        /// <returns>List of FiberSplice</returns>
        /// <remarks>Currently only checks A/B as passed, does not check the reverse B/A combination</remarks>
        public static List <FiberSplice> GetSplicedRanges(FiberCableWrapper cableA, FiberCableWrapper cableB, SpliceClosureWrapper splice)
        {
            List <FiberSplice> result      = new List <FiberSplice>();
            string             spliceWhere = string.Format("{0}='{1}' AND {2}='{3}' AND {4}='{5}'",
                                                           ConfigUtil.ACableIdFieldName,
                                                           cableA.IPID,
                                                           ConfigUtil.BCableIdFieldName,
                                                           cableB.IPID,
                                                           ConfigUtil.SpliceClosureIpidFieldName,
                                                           splice.IPID);

            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(cableA.Feature.Class, ConfigUtil.FiberSpliceTableName);
                ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass();
                releaser.ManageLifetime(filter);

                filter.WhereClause = spliceWhere;
                ((ESRI.ArcGIS.Geodatabase.IQueryFilterDefinition)filter).PostfixClause = string.Format("ORDER BY {0}", ConfigUtil.AFiberNumberFieldName);

                int aUnitIdx = fiberSpliceTable.FindField(ConfigUtil.AFiberNumberFieldName);
                int bUnitIdx = fiberSpliceTable.FindField(ConfigUtil.BFiberNumberFieldName);
                int lossIdx  = fiberSpliceTable.FindField(ConfigUtil.LossFieldName);
                int typeIdx  = fiberSpliceTable.FindField(ConfigUtil.TypeFieldName);
                ESRI.ArcGIS.Geodatabase.IField            typeField  = fiberSpliceTable.Fields.get_Field(typeIdx);
                ESRI.ArcGIS.Geodatabase.ICodedValueDomain typeDomain = typeField.Domain as ESRI.ArcGIS.Geodatabase.ICodedValueDomain;

                ESRI.ArcGIS.Geodatabase.ICursor splices = fiberSpliceTable.Search(filter, true);
                releaser.ManageLifetime(splices);

                ESRI.ArcGIS.Geodatabase.IRow spliceRow = splices.NextRow();

                int    lastAUnit = -1;
                int    lastBUnit = -1;
                double?lastLoss  = null;
                object lastType  = Type.Missing;

                int aLow = -1;
                int bLow = -1;

                while (null != spliceRow)
                {
                    // These are not-null columns
                    int aUnit = (int)spliceRow.get_Value(aUnitIdx);
                    int bUnit = (int)spliceRow.get_Value(bUnitIdx);

                    object lossObj = spliceRow.get_Value(lossIdx);
                    double?loss    = null;
                    if (DBNull.Value != lossObj)
                    {
                        loss = (double)lossObj;
                    }

                    object type = spliceRow.get_Value(typeIdx);

                    if (aUnit != (lastAUnit + 1) ||
                        bUnit != (lastBUnit + 1) ||
                        loss != lastLoss ||
                        !type.Equals(lastType))
                    {
                        if (-1 != lastAUnit)
                        {
                            string typeString = string.Empty;
                            if (null != typeString)
                            {
                                if (null != typeDomain)
                                {
                                    typeString = GdbUtils.GetDomainNameForValue(typeDomain, lastType);
                                }
                                else
                                {
                                    typeString = lastType.ToString(); // DBNull.Value will return string.Empty
                                }
                            }

                            result.Add(new FiberSplice(new Range(aLow, lastAUnit), new Range(bLow, lastBUnit), lastLoss, typeString));
                        }

                        aLow = aUnit;
                        bLow = bUnit;
                    }

                    lastAUnit = aUnit;
                    lastBUnit = bUnit;
                    lastLoss  = loss;
                    lastType  = type;

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

                if (-1 < aLow)
                {
                    string typeString = string.Empty;
                    if (null != typeString)
                    {
                        if (null != typeDomain)
                        {
                            typeString = GdbUtils.GetDomainNameForValue(typeDomain, lastType);
                        }
                        else
                        {
                            typeString = lastType.ToString(); // DBNull.Value will return string.Empty
                        }
                    }

                    result.Add(new FiberSplice(new Range(aLow, lastAUnit), new Range(bLow, lastBUnit), lastLoss, typeString));
                }
            }

            return(result);
        }
        /// <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;
        }
        /// <summary>
        /// Gets all cables that are considered splicable to another cable at a given splice closure. 
        /// </summary>
        /// <param name="cable">Cable to splice with</param>
        /// <param name="spliceClosure">Splice Closure to splice at</param>
        /// <returns>List of SpliceableCableWrapper</returns>
        public List<SpliceableCableWrapper> GetSpliceableCables(FiberCableWrapper cable, SpliceClosureWrapper spliceClosure)
        {
            // At the time of this comment, splicable means they are connected in the geometric network
            List<SpliceableCableWrapper> result = new List<SpliceableCableWrapper>();

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

            int searchOid = cable.Feature.OID;

            ESRI.ArcGIS.Geodatabase.IEdgeFeature cableFt = cable.Feature as ESRI.ArcGIS.Geodatabase.IEdgeFeature;
            ESRI.ArcGIS.Carto.IFeatureLayer ftLayer = _hookHelper.FindFeatureLayer(ConfigUtil.FiberCableFtClassName);
            int displayIdx = ftLayer.FeatureClass.FindField(ftLayer.DisplayField);

            if (null != cableFt)
            {
                // We assume it is simple. Complex junctions are not supported for splicing cables
                ESRI.ArcGIS.Geodatabase.ISimpleJunctionFeature junction = spliceClosure.Feature as ESRI.ArcGIS.Geodatabase.ISimpleJunctionFeature;

                if (null != junction)
                {
                    bool isAFromEnd = false; // would be in the case that junction.EID == cableFt.ToJunctionEID
                    if (junction.EID == cableFt.FromJunctionEID)
                    {
                        isAFromEnd = true;
                    }
                    else if (junction.EID != cableFt.ToJunctionEID)
                    {
                        // It isn't the from or the two? It shouldn't have been passed in as if it was coincident with the cable
                        return result;
            //                        throw new InvalidOperationException("Given splice closure is not the junction for the given cable.");
                    }

                    int edgeCount = junction.EdgeFeatureCount;
                    for (int i = 0; i < edgeCount; i++)
                    {
                        ESRI.ArcGIS.Geodatabase.IEdgeFeature connectedEdge = junction.get_EdgeFeature(i);
                        ESRI.ArcGIS.Geodatabase.IFeature feature = (ESRI.ArcGIS.Geodatabase.IFeature)connectedEdge;
                        ESRI.ArcGIS.Geodatabase.IDataset dataset = feature.Class as ESRI.ArcGIS.Geodatabase.IDataset;
                        string featureClassName = GdbUtils.ParseTableName(dataset);

                        if (0 == string.Compare(featureClassName, ConfigUtil.FiberCableFtClassName)
                            && feature.OID != searchOid)
                        {
                            if (junction.EID == connectedEdge.FromJunctionEID)
                            {
                                result.Add(new SpliceableCableWrapper(feature, true, isAFromEnd, displayIdx));
                            }
                            else if (junction.EID == connectedEdge.ToJunctionEID)
                            {
                                result.Add(new SpliceableCableWrapper(feature, false, isAFromEnd, displayIdx));
                            }
                        }
                    }
                }
            }

            return result;
        }
        //public static FiberSpliceConnectionHelper Instance(object hook, ESRI.ArcGIS.Editor.IEditor editor)
        //{
        //    if (_instance != null)
        //    {
        //        return _instance;
        //    }
        //    else
        //    {
        //        _instance = new FiberSpliceConnectionHelper(hook, editor);
        //        return _instance;
        //    }
        //}
        /// <summary>
        /// Gets a list of cable features that are connected to the splice closure in the geometric network
        /// </summary>
        /// <param name="spliceClosure">Splice to check</param>
        /// <returns>List of IFeature</returns>
        public List<ESRI.ArcGIS.Geodatabase.IFeature> GetConnectedCables(SpliceClosureWrapper spliceClosure)
        {
            // At the time of this comment, splicable means they are connected in the
            // geometric network and the splice closure "touches" one of the ends of the cable
            List<ESRI.ArcGIS.Geodatabase.IFeature> result = new List<ESRI.ArcGIS.Geodatabase.IFeature>();

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

            ESRI.ArcGIS.Geometry.IRelationalOperator relOp = spliceClosure.Feature.Shape as ESRI.ArcGIS.Geometry.IRelationalOperator;
            if (relOp == null)
                throw new ArgumentNullException("spliceClosure");

            ESRI.ArcGIS.Geodatabase.ISimpleJunctionFeature junction = spliceClosure.Feature as ESRI.ArcGIS.Geodatabase.ISimpleJunctionFeature;
            if (null != junction)
            {
                for (int i = 0; i < junction.EdgeFeatureCount; i++)
                {
                    ESRI.ArcGIS.Geodatabase.IFeature connectedEdge = junction.get_EdgeFeature(i) as ESRI.ArcGIS.Geodatabase.IFeature;
                    ESRI.ArcGIS.Geodatabase.IDataset dataset = connectedEdge.Class as ESRI.ArcGIS.Geodatabase.IDataset;
                    string ftClassName = GdbUtils.ParseTableName(dataset);

                    if (0 == string.Compare(ftClassName, ConfigUtil.FiberCableFtClassName, true))
                    {
                        // Test feature edge is coincident with splice closure. Cables are
                        // complex features so splice might lie half way along some cables
                        // but will not be providing any splice connectivity to them.
                        if (relOp.Touches(connectedEdge.Shape)) // only true if point at either end of a line
                            result.Add(connectedEdge);
                    }
                }
            }

            return result;
        }
        /// <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>
        /// Get the existing splice ranges between two cables at an existing closure
        /// </summary>
        /// <param name="cableA">One cable</param>
        /// <param name="cableB">Other cable</param>
        /// <param name="splice">Splice Closure</param>
        /// <returns>List of FiberSplice</returns>
        /// <remarks>Currently only checks A/B as passed, does not check the reverse B/A combination</remarks>
        public static List<FiberSplice> GetSplicedRanges(FiberCableWrapper cableA, FiberCableWrapper cableB, SpliceClosureWrapper splice)
        {
            List<FiberSplice> result = new List<FiberSplice>();
            string spliceWhere = string.Format("{0}='{1}' AND {2}='{3}' AND {4}='{5}'",
                ConfigUtil.ACableIdFieldName,
                cableA.IPID,
                ConfigUtil.BCableIdFieldName,
                cableB.IPID,
                ConfigUtil.SpliceClosureIpidFieldName,
                splice.IPID);

            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(cableA.Feature.Class, ConfigUtil.FiberSpliceTableName);
                ESRI.ArcGIS.Geodatabase.IQueryFilter filter = new ESRI.ArcGIS.Geodatabase.QueryFilterClass();
                releaser.ManageLifetime(filter);

                filter.WhereClause = spliceWhere;
                ((ESRI.ArcGIS.Geodatabase.IQueryFilterDefinition)filter).PostfixClause = string.Format("ORDER BY {0}",ConfigUtil.AFiberNumberFieldName);

                int aUnitIdx = fiberSpliceTable.FindField(ConfigUtil.AFiberNumberFieldName);
                int bUnitIdx = fiberSpliceTable.FindField(ConfigUtil.BFiberNumberFieldName);
                int lossIdx = fiberSpliceTable.FindField(ConfigUtil.LossFieldName);
                int typeIdx = fiberSpliceTable.FindField(ConfigUtil.TypeFieldName);
                ESRI.ArcGIS.Geodatabase.IField typeField = fiberSpliceTable.Fields.get_Field(typeIdx);
                ESRI.ArcGIS.Geodatabase.ICodedValueDomain typeDomain = typeField.Domain as ESRI.ArcGIS.Geodatabase.ICodedValueDomain;

                ESRI.ArcGIS.Geodatabase.ICursor splices = fiberSpliceTable.Search(filter, true);
                releaser.ManageLifetime(splices);

                ESRI.ArcGIS.Geodatabase.IRow spliceRow = splices.NextRow();

                int lastAUnit = -1;
                int lastBUnit = -1;
                double? lastLoss = null;
                object lastType = Type.Missing;

                int aLow = -1;
                int bLow = -1;

                while (null != spliceRow)
                {
                    // These are not-null columns
                    int aUnit = (int)spliceRow.get_Value(aUnitIdx);
                    int bUnit = (int)spliceRow.get_Value(bUnitIdx);

                    object lossObj = spliceRow.get_Value(lossIdx);
                    double? loss = null;
                    if (DBNull.Value != lossObj)
                    {
                        loss = (double)lossObj;
                    }

                    object type = spliceRow.get_Value(typeIdx);

                    if (aUnit != (lastAUnit + 1)
                        || bUnit != (lastBUnit + 1)
                        || loss != lastLoss
                        || !type.Equals(lastType))
                    {
                        if (-1 != lastAUnit)
                        {
                            string typeString = string.Empty;
                            if (null != typeString)
                            {
                                if (null != typeDomain)
                                {
                                    typeString = GdbUtils.GetDomainNameForValue(typeDomain, lastType);
                                }
                                else
                                {
                                    typeString = lastType.ToString(); // DBNull.Value will return string.Empty
                                }
                            }

                            result.Add(new FiberSplice(new Range(aLow, lastAUnit), new Range(bLow, lastBUnit), lastLoss, typeString));
                        }

                        aLow = aUnit;
                        bLow = bUnit;
                    }

                    lastAUnit = aUnit;
                    lastBUnit = bUnit;
                    lastLoss = loss;
                    lastType = type;

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

                if (-1 < aLow)
                {
                    string typeString = string.Empty;
                    if (null != typeString)
                    {
                        if (null != typeDomain)
                        {
                            typeString = GdbUtils.GetDomainNameForValue(typeDomain, lastType);
                        }
                        else
                        {
                            typeString = lastType.ToString(); // DBNull.Value will return string.Empty
                        }
                    }

                    result.Add(new FiberSplice(new Range(aLow, lastAUnit), new Range(bLow, lastBUnit), lastLoss, typeString));
                }
            }

            return result;
        }
        /// <summary>
        /// Load the drop down of selected splice closures
        /// </summary>
        /// <param name="helper">SpliceEditorHelper</param>
        private void PopulateSpliceClosures(FiberSpliceHelper helper)
        {
            try
            {
                // Clear anything that is dependent on what we are about to load
                ClearGrid();
                cboCableA.Items.Clear();
                cboCableB.Items.Clear();
                cboSpliceClosure.Items.Clear();
                lblAvailableA.Text = "";
                lblAvailableB.Text = "";

                // Find the layer
                ESRI.ArcGIS.Carto.IFeatureLayer ftLayer = _hookHelper.FindFeatureLayer(ConfigUtil.SpliceClosureFtClassName);
                if (ftLayer == null)
                {
                    ArcMap.Application.StatusBar.set_Message(0, "Telecom Tools error occurred. Check log for details.");
                    _logHelper.addLogEntry(DateTime.Now.ToString(), "ERROR", "Could not find Feature Layer:.", ConfigUtil.SpliceClosureFtClassName);
                    return;
                }
                int displayIdx = ftLayer.FeatureClass.FindField(ftLayer.DisplayField);

                // Get the selection on this layer
                List<ESRI.ArcGIS.Geodatabase.IFeature> selectedSplices = _hookHelper.GetSelectedFeatures(ftLayer);

                for (int i = 0; i < selectedSplices.Count; i++)
                {
                    SpliceClosureWrapper w = new SpliceClosureWrapper(selectedSplices[i], displayIdx);
                    cboSpliceClosure.Items.Add(w);
                }

                if (0 < cboSpliceClosure.Items.Count)
                {
                    cboSpliceClosure.SelectedItem = cboSpliceClosure.Items[0];
                }
            }
            catch (Exception e)
            {
                _logHelper.addLogEntry(DateTime.Now.ToString(), "ERROR", "Splice Connection Window (PopulateSpliceClosures): ", e.Message);
            }
        }
Exemplo n.º 23
0
        /// <summary>
        /// Gets all cables that are considered splicable to another cable at a given splice closure.
        /// </summary>
        /// <param name="cable">Cable to splice with</param>
        /// <param name="spliceClosure">Splice Closure to splice at</param>
        /// <returns>List of SpliceableCableWrapper</returns>
        public List <SpliceableCableWrapper> GetSpliceableCables(FiberCableWrapper cable, SpliceClosureWrapper spliceClosure)
        {
            // At the time of this comment, splicable means they are connected in the geometric network
            List <SpliceableCableWrapper> result = new List <SpliceableCableWrapper>();

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

            int searchOid = cable.Feature.OID;

            ESRI.ArcGIS.Geodatabase.IEdgeFeature cableFt = cable.Feature as ESRI.ArcGIS.Geodatabase.IEdgeFeature;
            ESRI.ArcGIS.Carto.IFeatureLayer      ftLayer = _hookHelper.FindFeatureLayer(ConfigUtil.FiberCableFtClassName);
            int displayIdx = ftLayer.FeatureClass.FindField(ftLayer.DisplayField);

            if (null != cableFt)
            {
                // We assume it is simple. Complex junctions are not supported for splicing cables
                ESRI.ArcGIS.Geodatabase.ISimpleJunctionFeature junction = spliceClosure.Feature as ESRI.ArcGIS.Geodatabase.ISimpleJunctionFeature;

                if (null != junction)
                {
                    bool isAFromEnd = false; // would be in the case that junction.EID == cableFt.ToJunctionEID
                    if (junction.EID == cableFt.FromJunctionEID)
                    {
                        isAFromEnd = true;
                    }
                    else if (junction.EID != cableFt.ToJunctionEID)
                    {
                        // It isn't the from or the two? It shouldn't have been passed in as if it was coincident with the cable
                        return(result);
//                        throw new InvalidOperationException("Given splice closure is not the junction for the given cable.");
                    }

                    int edgeCount = junction.EdgeFeatureCount;
                    for (int i = 0; i < edgeCount; i++)
                    {
                        ESRI.ArcGIS.Geodatabase.IEdgeFeature connectedEdge = junction.get_EdgeFeature(i);
                        ESRI.ArcGIS.Geodatabase.IFeature     feature       = (ESRI.ArcGIS.Geodatabase.IFeature)connectedEdge;
                        ESRI.ArcGIS.Geodatabase.IDataset     dataset       = feature.Class as ESRI.ArcGIS.Geodatabase.IDataset;
                        string featureClassName = GdbUtils.ParseTableName(dataset);

                        if (0 == string.Compare(featureClassName, ConfigUtil.FiberCableFtClassName) &&
                            feature.OID != searchOid)
                        {
                            if (junction.EID == connectedEdge.FromJunctionEID)
                            {
                                result.Add(new SpliceableCableWrapper(feature, true, isAFromEnd, displayIdx));
                            }
                            else if (junction.EID == connectedEdge.ToJunctionEID)
                            {
                                result.Add(new SpliceableCableWrapper(feature, false, isAFromEnd, displayIdx));
                            }
                        }
                    }
                }
            }

            return(result);
        }
Exemplo n.º 24
0
        /// <summary>
        /// Deletes given splices from one cable to the other, at a given splice closure
        /// </summary>
        /// <param name="cableA">Cable A</param>
        /// <param name="cableB">Cable B</param>
        /// <param name="splice">Splice Closure</param>
        /// <param name="strands">Strands to remove</param>
        /// <param name="isExistingOperation">Flag to control whether we need to wrap this in an edit operation</param>
        /// <returns>Success</returns>
        public bool BreakSplices(FiberCableWrapper cableA, SpliceableCableWrapper cableB, SpliceClosureWrapper splice, Dictionary <int, FiberSplice> strands, bool isExistingOperation)
        {
            bool success         = false;
            bool isOperationOpen = false;

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

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

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

            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(splice.Feature.Class, ConfigUtil.FiberSpliceTableName);

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

                    // A and B is arbitrary, so we check the given combinations going both ways. The structure is:
                    // Where the splice closure IPID is ours and
                    // ((the A Cable/Fiber matches our A cable and B Cable/Fiber matches our B)
                    //  OR (the A Cable/Fiber matches our B cable and B Cable/Fiber matches our A))
                    string format = "{0}='{1}' AND (({2}='{3}' AND {4}={5} AND {6}='{7}' AND {8}={9})" +
                                    " OR ({2}='{7}' AND {4}={9} AND {6}='{3}' AND {8}={5}))";

                    foreach (KeyValuePair <int, FiberSplice> pair in strands)
                    {
                        filter.WhereClause = string.Format(format,
                                                           ConfigUtil.SpliceClosureIpidFieldName,
                                                           splice.IPID,
                                                           ConfigUtil.ACableIdFieldName,
                                                           cableA.IPID,
                                                           ConfigUtil.AFiberNumberFieldName,
                                                           pair.Key,
                                                           ConfigUtil.BCableIdFieldName,
                                                           cableB.IPID,
                                                           ConfigUtil.BFiberNumberFieldName,
                                                           pair.Value.BRange.Low);

                        spliceTable.DeleteSearchedRows(filter);
                    }

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

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

                success = false;
            }

            return(success);
        }
Exemplo n.º 25
0
        /// <summary>
        /// Splices all available strands from one cable to the other, at a given splice closure
        /// </summary>
        /// <param name="cableA">Cable A</param>
        /// <param name="cableB">Cable B</param>
        /// <param name="splice">Splice Closure</param>
        /// <param name="strands">Strands to splice together</param>
        /// <param name="isExistingOperation">Flag to control whether we need to wrap this in an edit operation</param>
        /// <returns>Success</returns>
        public bool CreateSplices(FiberCableWrapper cableA, SpliceableCableWrapper cableB, SpliceClosureWrapper splice, Dictionary <int, FiberSplice> strands, bool isExistingOperation)
        {
            bool success         = false;
            bool isOperationOpen = false;

            #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

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


            if (null == splice)
            {
                splice = GenerateSpliceClosure(cableA, cableB);
            }
            else if (0 == splice.IPID.Length)
            {
                // Populate an IPID; we will need it
                ESRI.ArcGIS.Geodatabase.IFeature spliceFt = splice.Feature;
                Guid g = Guid.NewGuid();

                spliceFt.set_Value(spliceFt.Fields.FindField(ConfigUtil.IpidFieldName), g.ToString("B").ToUpper());
                spliceFt.Store();
            }

            try
            {
                ESRI.ArcGIS.Geodatabase.ITable fiberSpliceTable = _wkspHelper.FindTable(ConfigUtil.FiberSpliceTableName);
//                ESRI.ArcGIS.Geodatabase.ITable fiberSpliceTable = GdbUtils.GetTable(cableA.Feature.Class, ConfigUtil.FiberSpliceTableName);
                int aCableIdx     = fiberSpliceTable.FindField(ConfigUtil.ACableIdFieldName);
                int bCableIdx     = fiberSpliceTable.FindField(ConfigUtil.BCableIdFieldName);
                int aFiberNumIdx  = fiberSpliceTable.FindField(ConfigUtil.AFiberNumberFieldName);
                int bFiberNumIdx  = fiberSpliceTable.FindField(ConfigUtil.BFiberNumberFieldName);
                int spliceIpidIdx = fiberSpliceTable.FindField(ConfigUtil.SpliceClosureIpidFieldName);
                int isAFromIdx    = fiberSpliceTable.FindField(ConfigUtil.IsAFromEndFieldName);
                int isBFromIdx    = fiberSpliceTable.FindField(ConfigUtil.IsBFromEndFieldName);
                int lossIdx       = fiberSpliceTable.FindField(ConfigUtil.LossFieldName);
                int typeIdx       = fiberSpliceTable.FindField(ConfigUtil.TypeFieldName);
                ESRI.ArcGIS.Geodatabase.IField typeField = fiberSpliceTable.Fields.get_Field(typeIdx);

                string aCableId   = cableA.IPID;
                string bCableId   = cableB.IPID;
                string isAFromEnd = cableB.IsOtherFromEnd ? "T" : "F";
                string isBFromEnd = cableB.IsThisFromEnd ? "T" : "F";
                string spliceIpid = splice.IPID;

                using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser())
                {
                    // TODO cant use insert cursor since edit events wont fire.
                    // We need evetns to fire for dynamic values to get populated.
                    // ESRI.ArcGIS.Geodatabase.ICursor insertCursor = fiberSpliceTable.Insert(true);
                    // releaser.ManageLifetime(insertCursor);

                    foreach (KeyValuePair <int, FiberSplice> pair in strands)
                    {
                        IRow row = fiberSpliceTable.CreateRow();

                        releaser.ManageLifetime(row);

                        FiberSplice fiberSplice = pair.Value;

                        row.set_Value(aCableIdx, aCableId);
                        row.set_Value(bCableIdx, bCableId);
                        row.set_Value(aFiberNumIdx, pair.Key);
                        row.set_Value(bFiberNumIdx, fiberSplice.BRange.Low);
                        row.set_Value(spliceIpidIdx, spliceIpid);
                        row.set_Value(isAFromIdx, isAFromEnd);
                        row.set_Value(isBFromIdx, isBFromEnd);

                        if (null == fiberSplice.Loss)
                        {
                            row.set_Value(lossIdx, DBNull.Value);
                        }
                        else
                        {
                            row.set_Value(lossIdx, fiberSplice.Loss);
                        }

                        object typeValue = DBNull.Value;
                        if (null != fiberSplice.Type)
                        {
                            try
                            {
                                typeValue = GdbUtils.CheckForCodedValue(typeField, fiberSplice.Type);
                            }
                            catch
                            {
                                // TODO: Log a warning about why we can't set the default split splice type?
                            }
                        }

                        row.set_Value(typeIdx, typeValue);
                        row.Store();
                    }
                }

                if (isOperationOpen)
                {
                    _editor.StopOperation("Edit Splices");
                }

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

                success = false;
            }

            return(success);
        }
        /// <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>
        /// 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);
            }
        }
        /// <summary>
        /// Deletes all splices at a splice closure
        /// </summary>
        /// <param name="splice">Splice</param>
        /// <param name="isExistingOperation">Are we already in an edit operation?</param>
        /// <returns>Success</returns>
        public bool BreakAllSplices(SpliceClosureWrapper splice, bool isExistingOperation)
        {
            bool success = false;
            bool isOperationOpen = false;

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

            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(splice.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}'",
                    ConfigUtil.SpliceClosureIpidFieldName,
                    splice.IPID);

                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>
        /// Deletes given splices from one cable to the other, at a given splice closure
        /// </summary>
        /// <param name="cableA">Cable A</param>
        /// <param name="cableB">Cable B</param>
        /// <param name="splice">Splice Closure</param>
        /// <param name="strands">Strands to remove</param>
        /// <param name="isExistingOperation">Flag to control whether we need to wrap this in an edit operation</param>
        /// <returns>Success</returns>
        public bool BreakSplices(FiberCableWrapper cableA, SpliceableCableWrapper cableB, SpliceClosureWrapper splice, Dictionary<int,FiberSplice> strands, bool isExistingOperation)
        {
            bool success = false;
            bool isOperationOpen = false;

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

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

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

            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(splice.Feature.Class, ConfigUtil.FiberSpliceTableName);

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

                    // A and B is arbitrary, so we check the given combinations going both ways. The structure is:
                    // Where the splice closure IPID is ours and
                    // ((the A Cable/Fiber matches our A cable and B Cable/Fiber matches our B)
                    //  OR (the A Cable/Fiber matches our B cable and B Cable/Fiber matches our A))
                    string format = "{0}='{1}' AND (({2}='{3}' AND {4}={5} AND {6}='{7}' AND {8}={9})" +
                        " OR ({2}='{7}' AND {4}={9} AND {6}='{3}' AND {8}={5}))";

                    foreach (KeyValuePair<int, FiberSplice> pair in strands)
                    {
                        filter.WhereClause = string.Format(format,
                            ConfigUtil.SpliceClosureIpidFieldName,
                            splice.IPID,
                            ConfigUtil.ACableIdFieldName,
                            cableA.IPID,
                            ConfigUtil.AFiberNumberFieldName,
                            pair.Key,
                            ConfigUtil.BCableIdFieldName,
                            cableB.IPID,
                            ConfigUtil.BFiberNumberFieldName,
                            pair.Value.BRange.Low);

                        spliceTable.DeleteSearchedRows(filter);
                    }

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

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

                success = false;
            }

            return success;
        }
        /// <summary>
        /// Splice closure features can have related:
        ///         splice records
        /// </summary>
        /// <param name="spliceFt">Deleted IFeature</param>
        private void CascadeSpliceClosureDelete(ESRI.ArcGIS.Geodatabase.IFeature spliceFt)
        {
            SpliceClosureWrapper splice = new SpliceClosureWrapper(spliceFt);

            // Delete fiber splices
            _spliceHelper.BreakAllSplices(splice, true);
        }
        /// <summary>
        /// Splices all available strands from one cable to the other, at a given splice closure
        /// </summary>
        /// <param name="cableA">Cable A</param>
        /// <param name="cableB">Cable B</param>
        /// <param name="splice">Splice Closure</param>
        /// <param name="strands">Strands to splice together</param>
        /// <param name="isExistingOperation">Flag to control whether we need to wrap this in an edit operation</param>
        /// <returns>Success</returns>
        public bool CreateSplices(FiberCableWrapper cableA, SpliceableCableWrapper cableB, SpliceClosureWrapper splice, Dictionary<int,FiberSplice> strands, bool isExistingOperation)
        {
            bool success = false;
            bool isOperationOpen = false;

            #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

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

            if (null == splice)
            {
                splice = GenerateSpliceClosure(cableA, cableB);
            }
            else if (0 == splice.IPID.Length)
            {
                // Populate an IPID; we will need it
                ESRI.ArcGIS.Geodatabase.IFeature spliceFt = splice.Feature;
                Guid g = Guid.NewGuid();

                spliceFt.set_Value(spliceFt.Fields.FindField(ConfigUtil.IpidFieldName), g.ToString("B").ToUpper());
                spliceFt.Store();
            }

            try
            {
                ESRI.ArcGIS.Geodatabase.ITable fiberSpliceTable = _wkspHelper.FindTable(ConfigUtil.FiberSpliceTableName);
            //                ESRI.ArcGIS.Geodatabase.ITable fiberSpliceTable = GdbUtils.GetTable(cableA.Feature.Class, ConfigUtil.FiberSpliceTableName);
                int aCableIdx = fiberSpliceTable.FindField(ConfigUtil.ACableIdFieldName);
                int bCableIdx = fiberSpliceTable.FindField(ConfigUtil.BCableIdFieldName);
                int aFiberNumIdx = fiberSpliceTable.FindField(ConfigUtil.AFiberNumberFieldName);
                int bFiberNumIdx = fiberSpliceTable.FindField(ConfigUtil.BFiberNumberFieldName);
                int spliceIpidIdx = fiberSpliceTable.FindField(ConfigUtil.SpliceClosureIpidFieldName);
                int isAFromIdx = fiberSpliceTable.FindField(ConfigUtil.IsAFromEndFieldName);
                int isBFromIdx = fiberSpliceTable.FindField(ConfigUtil.IsBFromEndFieldName);
                int lossIdx = fiberSpliceTable.FindField(ConfigUtil.LossFieldName);
                int typeIdx = fiberSpliceTable.FindField(ConfigUtil.TypeFieldName);
                ESRI.ArcGIS.Geodatabase.IField typeField = fiberSpliceTable.Fields.get_Field(typeIdx);

                string aCableId = cableA.IPID;
                string bCableId = cableB.IPID;
                string isAFromEnd = cableB.IsOtherFromEnd ? "T" : "F";
                string isBFromEnd = cableB.IsThisFromEnd ? "T" : "F";
                string spliceIpid = splice.IPID;

                using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser())
                {
                    // TODO cant use insert cursor since edit events wont fire.
                    // We need evetns to fire for dynamic values to get populated.
                    // ESRI.ArcGIS.Geodatabase.ICursor insertCursor = fiberSpliceTable.Insert(true);
                    // releaser.ManageLifetime(insertCursor);

                    foreach (KeyValuePair<int, FiberSplice> pair in strands)
                    {
                        IRow row = fiberSpliceTable.CreateRow();

                        releaser.ManageLifetime(row);

                        FiberSplice fiberSplice = pair.Value;

                        row.set_Value(aCableIdx, aCableId);
                        row.set_Value(bCableIdx, bCableId);
                        row.set_Value(aFiberNumIdx, pair.Key);
                        row.set_Value(bFiberNumIdx, fiberSplice.BRange.Low);
                        row.set_Value(spliceIpidIdx, spliceIpid);
                        row.set_Value(isAFromIdx, isAFromEnd);
                        row.set_Value(isBFromIdx, isBFromEnd);

                        if (null == fiberSplice.Loss)
                        {
                            row.set_Value(lossIdx, DBNull.Value);
                        }
                        else
                        {
                            row.set_Value(lossIdx, fiberSplice.Loss);
                        }

                        object typeValue = DBNull.Value;
                        if (null != fiberSplice.Type)
                        {
                            try
                            {
                                typeValue = GdbUtils.CheckForCodedValue(typeField, fiberSplice.Type);
                            }
                            catch
                            {
                                // TODO: Log a warning about why we can't set the default split splice type?
                            }
                        }

                        row.set_Value(typeIdx, typeValue);
                        row.Store();
                    }
                }

                if (isOperationOpen)
                {
                    _editor.StopOperation("Edit Splices");
                }

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

                success = false;
            }

            return success;
        }
        /// <summary>
        /// Returns true if a SpliceClosure has splice connections associated with it, otherwise returns false.
        /// </summary>
        /// <param name="closure">Closure to check</param>
        /// <returns>Boolean</returns>
        public static bool SpliceClosureHasConnections(SpliceClosureWrapper closure)
        {
            #region Validation
            if (null == closure)
            {
                throw new ArgumentNullException("closure");
            }
            #endregion

            bool result = false;

            ESRI.ArcGIS.Geodatabase.IFeatureClass closureFtClass = closure.Feature.Class as ESRI.ArcGIS.Geodatabase.IFeatureClass;

            // Find the SpliceClosure to Splice Relationship class name
            // and test for the number of related obects
            String spliceClosureToSpliceRelClassName = ConfigUtil.SpliceClosureToSpliceRelClassName;
            int featureCount = GdbUtils.GetRelatedObjectCount(closure.Feature, spliceClosureToSpliceRelClassName);
            if (featureCount > 0)
            {
                result = true;
            }

            return result;
        }
        /// <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;
        }