/// <summary>
        /// Generates a number of buffer tubes and fiber records for a fiber cable, given a configuration. 
        /// </summary>
        /// <param name="feature">IFeature to generate for</param>
        /// <param name="configuration">Specification of buffer and fiber counts</param>
        /// <param name="progressDialog">Progress dialog for user notification</param>
        /// <param name="trackCancel">TrackCancel used in the progress dialog</param>
        /// <returns>Success</returns>
        private bool GenerateUnits(ESRI.ArcGIS.Geodatabase.IFeature feature, FiberCableConfiguration configuration, ESRI.ArcGIS.Framework.IProgressDialog2 progressDialog, ESRI.ArcGIS.esriSystem.ITrackCancel trackCancel)
        {
            bool isComplete = false;
            bool isCancelled = false;
            Guid g;

            ESRI.ArcGIS.esriSystem.IStepProgressor stepProgressor = (ESRI.ArcGIS.esriSystem.IStepProgressor)progressDialog;
            ESRI.ArcGIS.Geodatabase.IObjectClass ftClass = feature.Class;

            using (ESRI.ArcGIS.ADF.ComReleaser releaser = new ESRI.ArcGIS.ADF.ComReleaser())
            {
                ESRI.ArcGIS.Geodatabase.IRelationshipClass cableHasBuffer = GdbUtils.GetRelationshipClass(ftClass, ConfigUtil.FiberCableToBufferRelClassName);
                releaser.ManageLifetime(cableHasBuffer);
                ESRI.ArcGIS.Geodatabase.IRelationshipClass cableHasFiber = GdbUtils.GetRelationshipClass(ftClass, ConfigUtil.FiberCableToFiberRelClassName);
                releaser.ManageLifetime(cableHasFiber);
                ESRI.ArcGIS.Geodatabase.IRelationshipClass bufferHasFiber = GdbUtils.GetRelationshipClass(ftClass, ConfigUtil.BufferToFiberRelClassName);
                releaser.ManageLifetime(bufferHasFiber);

                ESRI.ArcGIS.Geodatabase.ITable bufferTable = cableHasBuffer.DestinationClass as ESRI.ArcGIS.Geodatabase.ITable;
                ESRI.ArcGIS.Geodatabase.ITable fiberTable = cableHasFiber.DestinationClass as ESRI.ArcGIS.Geodatabase.ITable;

                // Fields to populate on buffer
                int bufferIpidIdx = bufferTable.Fields.FindField(ConfigUtil.IpidFieldName);
                int fiberCountIdx = bufferTable.Fields.FindField(ConfigUtil.NumberOfFibersFieldName);
                int bufferToCableIdx = bufferTable.Fields.FindField(cableHasBuffer.OriginForeignKey);
                object bufferToCableValue = feature.get_Value(feature.Fields.FindField(cableHasBuffer.OriginPrimaryKey));

                // Fields to populate on fiber
                int fiberIpidIdx = fiberTable.Fields.FindField(ConfigUtil.IpidFieldName);
                int fiberNumberIdx = fiberTable.Fields.FindField(ConfigUtil.Fiber_NumberFieldName);
                int fiberToCableIdx = fiberTable.Fields.FindField(cableHasFiber.OriginForeignKey);
                object fiberToCableValue = feature.get_Value(feature.Fields.FindField(cableHasFiber.OriginPrimaryKey));
                int fiberToBufferIdx = fiberTable.Fields.FindField(bufferHasFiber.OriginForeignKey);
                int fiberToBufferValueIdx = bufferTable.Fields.FindField(bufferHasFiber.OriginPrimaryKey);

                // Research using InsertCursor for speed.
                int fiberNumber = 0;
                for (int bufferIdx = 1; bufferIdx <= configuration.BufferCount; bufferIdx++)
                {
                    g = Guid.NewGuid();
                    string bufferId = g.ToString("B").ToUpper();

                    ESRI.ArcGIS.Geodatabase.IRow row = bufferTable.CreateRow();
                    releaser.ManageLifetime(row);

                    row.set_Value(bufferIpidIdx, bufferId);
                    row.set_Value(fiberCountIdx, configuration.FibersPerTube);
                    row.set_Value(bufferToCableIdx, bufferToCableValue);

                    row.Store();

                    object fiberToBufferValue = row.get_Value(fiberToBufferValueIdx);

                    // Research using InsertCursor for speed.
                    for (int fiberIdx = 1; fiberIdx <= configuration.FibersPerTube; fiberIdx++)
                    {
                        fiberNumber++;
                        progressDialog.Description = string.Format("Creating fiber {0} of {1}", fiberNumber, configuration.TotalFiberCount);
                        stepProgressor.Step();

                        g = Guid.NewGuid();
                        ESRI.ArcGIS.Geodatabase.IRow fiberRow = fiberTable.CreateRow();
                        releaser.ManageLifetime(fiberRow);

                        fiberRow.set_Value(fiberIpidIdx, g.ToString("B").ToUpper());
                        fiberRow.set_Value(fiberNumberIdx, fiberNumber);
                        fiberRow.set_Value(fiberToBufferIdx, fiberToBufferValue);
                        fiberRow.set_Value(fiberToCableIdx, fiberToCableValue);

                        fiberRow.Store();

                        if (!trackCancel.Continue())
                        {
                            isCancelled = true;
                            break;
                        }
                    }

                    if (!trackCancel.Continue())
                    {
                        isCancelled = true;
                        break;
                    }
                }

                if (!isCancelled)
                {
                    isComplete = true;
                }
            }

            return isComplete;
        }
        /// <summary>
        /// Sets the buffer tube and strand counts based on the given configuration. If IPID and/or CABLEID are null, it also
        /// takes care of them
        /// </summary>
        /// <param name="feature">The FiberCable feature to configure</param>
        /// <param name="configuration">The tube/strand counts</param>
        /// <param name="isExistingOperation">Flag to control whether this method is being called from within an existing 
        /// edit operation</param>
        /// <returns>Success</returns>
        protected bool ConfigureCable(ESRI.ArcGIS.Geodatabase.IFeature feature, FiberCableConfiguration configuration, bool isExistingOperation)
        {
            bool isComplete = false;
            bool isOurOperationOpen = false;

            // The following assignments are defaults for the case where they are not already populated on the feature
            string fiberCableIpid = Guid.NewGuid().ToString("B").ToUpper();

            // The following will be set during Validation
            ESRI.ArcGIS.Geodatabase.IObjectClass ftClass = null;
            ESRI.ArcGIS.Geodatabase.IFields fields = null;
            int ipidIdx = -1;
            int bufferCountIdx = -1;
            int strandCountIdx = -1;

            #region Validation

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

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

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

            ftClass = feature.Class;
            fields = ftClass.Fields;

            string missingFieldFormat = "Field {0} is missing.";

            ipidIdx = fields.FindField(ConfigUtil.IpidFieldName);
            if (-1 == ipidIdx)
            {
                throw new InvalidOperationException(string.Format(missingFieldFormat, ConfigUtil.IpidFieldName));
            }

            bufferCountIdx = fields.FindField(ConfigUtil.NumberOfBuffersFieldName);
            if (-1 == bufferCountIdx)
            {
                throw new InvalidOperationException(string.Format(missingFieldFormat, ConfigUtil.NumberOfBuffersFieldName));
            }

            strandCountIdx = fields.FindField(ConfigUtil.NumberOfFibersFieldName);
            if (-1 == strandCountIdx)
            {
                throw new InvalidOperationException(string.Format(missingFieldFormat, ConfigUtil.NumberOfFibersFieldName));
            }

            #endregion

            ESRI.ArcGIS.esriSystem.ITrackCancel trackCancel = new ESRI.ArcGIS.Display.CancelTrackerClass();
            ESRI.ArcGIS.Framework.IProgressDialog2 progressDialog = _hookHelper.CreateProgressDialog(trackCancel, "Preparing to configure cable...", 1, configuration.TotalFiberCount, 1, "Starting edit operation...", "Fiber Configuration");
            ESRI.ArcGIS.esriSystem.IStepProgressor stepProgressor = (ESRI.ArcGIS.esriSystem.IStepProgressor)progressDialog;

            progressDialog.ShowDialog();
            stepProgressor.Step();

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

            try
            {
                if (DBNull.Value == feature.get_Value(ipidIdx))
                {
                    feature.set_Value(ipidIdx, fiberCableIpid);
                }
                else
                {
                    fiberCableIpid = feature.get_Value(ipidIdx).ToString();
                }

                feature.set_Value(bufferCountIdx, configuration.BufferCount);
                feature.set_Value(strandCountIdx, configuration.TotalFiberCount);

                isComplete = GenerateUnits(feature, configuration, progressDialog, trackCancel);

                progressDialog.Description = "Completing configuration...";
                stepProgressor.Step();

                if (isOurOperationOpen)
                {
                    if (isComplete)
                    {
                        feature.Store();
                        _editor.StopOperation("Configure Fiber");
                    }
                    else
                    {
                        _editor.AbortOperation();
                    }
                }
            }
            catch
            {
                if (isOurOperationOpen)
                {
                    _editor.AbortOperation();
                }
            }

            progressDialog.HideDialog();
            return isComplete;
        }
        void Events5_OnCurrentTemplateChanged(IEditTemplate editTemplate)
        {
            try
            {
                _logHelper.addLogEntry(DateTime.Now.ToString(), "INFO", "Edit template changed.");

                if (editTemplate == null || editTemplate.Layer == null) return;
                if (editTemplate.Layer as IFeatureLayer == null) return;

                IFeatureLayer fLayer = editTemplate.Layer as IFeatureLayer;
                IFeatureClass fc;
                if ((fc = fLayer.FeatureClass) != null)
                {
                    ESRI.ArcGIS.Geodatabase.IDataset dataset = (ESRI.ArcGIS.Geodatabase.IDataset)fc;
                    string tableName = GdbUtils.ParseTableName(dataset);

                    // -------------------------------------------------
                    // Checks for different feature types of interest.
                    // Show the appropriate dialogs for any that need it
                    // -------------------------------------------------

                    // -----------------------------
                    // Fiber
                    // -----------------------------
                    if (0 == string.Compare(ConfigUtil.FiberCableFtClassName, tableName, true))
                    {
                        // Is the current template chosen properly configured with default values...
                        // Needs number of buffer tubes and no of strands of fiber
                        if (editTemplate.get_DefaultValue(ConfigUtil.NumberOfBuffersFieldName) == null ||
                            editTemplate.get_DefaultValue(ConfigUtil.NumberOfFibersFieldName) == null)
                        {
                            IEditor3 editor = ArcMap.Editor as IEditor3;
                            editor.CurrentTemplate = null;
                            MessageBox.Show("Template item has not been configured with # Buffer Tubes or # Strands per Tube. \n\nRight click this item and change these values in the properties.\n\nCreate new template items in the 'Organize Templates' window at the top of this area.");
                        }
                        else
                        {
                            int buffers = (int)editTemplate.get_DefaultValue(ConfigUtil.NumberOfBuffersFieldName);
                            int fibers = (int)editTemplate.get_DefaultValue(ConfigUtil.NumberOfFibersFieldName);

                            FiberCableConfiguration cf = new FiberCableConfiguration(
                                                            buffers,
                                                            fibers,
                                                            "",
                                                            "");

                            _fiberCableHelper.FiberCableConfig = cf;
                        }

                        // Enable the configuration helper
                        //_fiberCableHelper.onStartEditing();
                    }
                    else
                    {
                        //_fiberCableHelper.onStopEditing();
                    }

                    // -----------------------------
                    // Fiber Devices
                    // -----------------------------
                    if (ConfigUtil.IsDeviceClassName(tableName))
                    {
                        // Is the current template chosen properly configured with default values...
                        // Needs number of buffer tubes and no of strands of fiber
                        if (editTemplate.get_DefaultValue(ConfigUtil.InputPortsFieldName) == null ||
                            editTemplate.get_DefaultValue(ConfigUtil.OutputPortsFieldName) == null)
                        {
                            IEditor3 editor = ArcMap.Editor as IEditor3;
                            editor.CurrentTemplate = null;
                            MessageBox.Show("Template item has not been configured with # Input Ports or # Output Ports. \n\nRight click this item and change these values in the properties.\n\nCreate new template items in the 'Organize Templates' window at the top of this area.");
                        }
                        else
                        {
                            int inputPorts = (int)editTemplate.get_DefaultValue(ConfigUtil.InputPortsFieldName);
                            int outputPorts = (int)editTemplate.get_DefaultValue(ConfigUtil.OutputPortsFieldName);

                            _fiberDeviceHelper.InputPorts = inputPorts;
                            _fiberDeviceHelper.OutputPorts = outputPorts;
                        }

                        //_fiberDeviceHelper.onStartEditing();
                    }
                    else
                    {
                        //_fiberDeviceHelper.onStopEditing();
                    }
                }
            }
            catch(Exception ex)
            {
                _logHelper.addLogEntry(DateTime.Now.ToString(), "ERROR", "Error changing edit template.", ex.ToString());
            }
        }