private void CreateAndPopulateTurnFeatureClass(string outputFileGdbPath, string fdsName,
                                                       string ProhibRdmsTableName, string tempStatsTableName,
                                                       IGPMessages messages, ITrackCancel trackcancel)
        {
            // Determine the number of AltID fields we need (one more than the MAX_SEQ_NUMBER value).

            Type factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory");
            var wsf = Activator.CreateInstance(factoryType) as IWorkspaceFactory;
            var fws = wsf.OpenFromFile(outputFileGdbPath, 0) as IFeatureWorkspace;
            ITable tempStatsTable = fws.OpenTable(tempStatsTableName);
            short numAltIDFields = 2;
            if (tempStatsTable.RowCount(null) == 1)
                numAltIDFields = (short)(1 + (double)(tempStatsTable.GetRow(1).get_Value(tempStatsTable.FindField("MAX_SEQ_NUMBER"))));

            // Open the Rdms table and find the fields we need

            ITable rdmsTable = fws.OpenTable(ProhibRdmsTableName);
            int seqNumberField = rdmsTable.FindField("SEQ_NUMBER");
            int linkIDFieldOnRdms = rdmsTable.FindField("LINK_ID");
            int manLinkIDField = rdmsTable.FindField("MAN_LINKID");
            int condIDFieldOnRdms = rdmsTable.FindField("COND_ID");
            int endOfLkFieldOnRdms = rdmsTable.FindField("END_OF_LK");

            // Create a temporary template feature class

            var fcd = new FeatureClassDescriptionClass() as IFeatureClassDescription;
            var ocd = fcd as IObjectClassDescription;
            var fieldsEdit = ocd.RequiredFields as IFieldsEdit;
            IField fieldOnRdmsTable = rdmsTable.Fields.get_Field(linkIDFieldOnRdms);  // use the LINK_ID field as a template for the AltID fields
            for (short i = 1; i <= numAltIDFields; i++)
            {
                IFieldEdit newField = new FieldClass();
                newField.Name_2 = "AltID" + i;
                newField.Precision_2 = fieldOnRdmsTable.Precision;
                newField.Scale_2 = fieldOnRdmsTable.Scale;
                newField.Type_2 = fieldOnRdmsTable.Type;
                fieldsEdit.AddField(newField as IField);
            }
            fieldOnRdmsTable = rdmsTable.Fields.get_Field(condIDFieldOnRdms);
            fieldsEdit.AddField(fieldOnRdmsTable);
            var fieldChk = new FieldCheckerClass() as IFieldChecker;
            IEnumFieldError enumFieldErr = null;
            IFields validatedFields = null;
            fieldChk.ValidateWorkspace = fws as IWorkspace;
            fieldChk.Validate(fieldsEdit as IFields, out enumFieldErr, out validatedFields);
            var tempFC = fws.CreateFeatureClass("TheTemplate", validatedFields, ocd.InstanceCLSID, ocd.ClassExtensionCLSID,
                                                esriFeatureType.esriFTSimple, fcd.ShapeFieldName, "") as IDataset;

            // Create the turn feature class from the template, then delete the template

            Geoprocessor gp = new Geoprocessor();
            CreateTurnFeatureClass createTurnFCTool = new CreateTurnFeatureClass();
            string pathToFds = outputFileGdbPath + "\\" + fdsName;
            createTurnFCTool.out_location = pathToFds;
            createTurnFCTool.out_feature_class_name = TurnFCName;
            createTurnFCTool.maximum_edges = numAltIDFields;
            createTurnFCTool.in_template_feature_class = outputFileGdbPath + "\\TheTemplate";
            gp.Execute(createTurnFCTool, trackcancel);
            tempFC.Delete();

            // Open the new turn feature class and find all the fields on it

            IFeatureClass turnFC = fws.OpenFeatureClass(TurnFCName);
            int[] altIDFields = new int[numAltIDFields];
            int[] edgeFCIDFields = new int[numAltIDFields];
            int[] edgeFIDFields = new int[numAltIDFields];
            int[] edgePosFields = new int[numAltIDFields];
            for (short i = 0; i < numAltIDFields; i++)
            {
                altIDFields[i] = turnFC.FindField("AltID" + (i + 1));
                edgeFCIDFields[i] = turnFC.FindField("Edge" + (i + 1) + "FCID");
                edgeFIDFields[i] = turnFC.FindField("Edge" + (i + 1) + "FID");
                edgePosFields[i] = turnFC.FindField("Edge" + (i + 1) + "Pos");
            }
            int edge1endField = turnFC.FindField("Edge1End");
            int condIDFieldOnTurnFC = turnFC.FindField("COND_ID");

            // Look up the FCID of the Streets feature class

            IFeatureClass streetsFC = fws.OpenFeatureClass(StreetsFCName);
            int streetsFCID = streetsFC.FeatureClassID;

            // Set up queries

            var ts = new TableSortClass() as ITableSort;
            ts.Fields = "COND_ID, SEQ_NUMBER";
            ts.set_Ascending("COND_ID", true);
            ts.set_Ascending("SEQ_NUMBER", true);
            ts.QueryFilter = new QueryFilterClass();
            ts.Table = rdmsTable;
            ts.Sort(null);
            ICursor rdmsCursor = ts.Rows;
            IFeatureCursor turnFCCursor = turnFC.Insert(true);
            IFeatureBuffer turnBuffer = turnFC.CreateFeatureBuffer();

            // Write the field values to the turn feature class accordingly

            int numFeatures = 0;
            IRow rdmsRow = rdmsCursor.NextRow();
            while (rdmsRow != null)
            {
                // Transfer the non-edge identifying field values to the buffer
                turnBuffer.set_Value(condIDFieldOnTurnFC, rdmsRow.get_Value(condIDFieldOnRdms));

                // Write the Edge1End field value to the buffer
                switch ((string)(rdmsRow.get_Value(endOfLkFieldOnRdms)))
                {
                    case "N":
                        turnBuffer.set_Value(edge1endField, "Y");
                        break;
                    case "R":
                        turnBuffer.set_Value(edge1endField, "N");
                        break;
                    default:
                        break;    // not expected
                }

                // Write the AltID values to the buffer
                turnBuffer.set_Value(altIDFields[0], rdmsRow.get_Value(linkIDFieldOnRdms));
                short seq = (short)(rdmsRow.get_Value(seqNumberField));
                short lastEntry;
                do
                {
                    lastEntry = seq;
                    turnBuffer.set_Value(altIDFields[lastEntry], rdmsRow.get_Value(manLinkIDField));
                    rdmsRow = rdmsCursor.NextRow();
                    if (rdmsRow == null) break;
                    seq = (short)(rdmsRow.get_Value(seqNumberField));
                } while (seq != 1);

                // Zero-out the unused fields
                for (int i = lastEntry + 1; i < numAltIDFields; i++)
                    turnBuffer.set_Value(altIDFields[i], 0);

                // Write the FCID and Pos field values to the buffer
                for (short i = 0; i < numAltIDFields; i++)
                {
                    int altID = (int)(turnBuffer.get_Value(altIDFields[i]));
                    if (altID != 0)
                    {
                        turnBuffer.set_Value(edgeFCIDFields[i], streetsFCID);
                        turnBuffer.set_Value(edgeFIDFields[i], 1);
                        turnBuffer.set_Value(edgePosFields[i], 0.5);
                    }
                    else
                    {
                        turnBuffer.set_Value(edgeFCIDFields[i], 0);
                        turnBuffer.set_Value(edgeFIDFields[i], 0);
                        turnBuffer.set_Value(edgePosFields[i], 0);
                    }
                }

                // Create the turn feature
                turnFCCursor.InsertFeature(turnBuffer);
                numFeatures++;

                if ((numFeatures % 100) == 0)
                {
                    // check for user cancel

                    if (trackcancel != null && !trackcancel.Continue())
                        throw (new COMException("Function cancelled."));
                }
            }

            // Flush any outstanding writes to the turn feature class
            turnFCCursor.Flush();

            messages.AddMessage("Updating the EdgeFID values...");

            // Create a temporary network dataset for updating the EdgeFID values

            IDENetworkDataset dends = new DENetworkDatasetClass();
            dends.SupportsTurns = true;
            dends.Buildable = true;
            (dends as IDataElement).Name = StreetsFCName;
            (dends as IDEGeoDataset).SpatialReference = (streetsFC as IGeoDataset).SpatialReference;
            IArray sourceArray = new ArrayClass();
            var efs = new EdgeFeatureSourceClass() as IEdgeFeatureSource;
            (efs as INetworkSource).Name = StreetsFCName;
            efs.UsesSubtypes = false;
            efs.ClassConnectivityGroup = 1;
            efs.ClassConnectivityPolicy = esriNetworkEdgeConnectivityPolicy.esriNECPEndVertex;
            sourceArray.Add(efs);
            var tfs = new TurnFeatureSourceClass() as INetworkSource;
            tfs.Name = TurnFCName;
            sourceArray.Add(tfs);
            dends.Sources = sourceArray;
            var fdxc = fws.OpenFeatureDataset(fdsName) as IFeatureDatasetExtensionContainer;
            var dsCont = fdxc.FindExtension(esriDatasetType.esriDTNetworkDataset) as IDatasetContainer2;
            var tempNDS = dsCont.CreateDataset(dends as IDEDataset) as IDataset;

            // Set the EdgeFID field values by running UpdateByAlternateIDFields

            UpdateByAlternateIDFields updateByAltIDTool = new UpdateByAlternateIDFields();
            updateByAltIDTool.in_network_dataset = pathToFds + "\\" + StreetsFCName;
            updateByAltIDTool.alternate_ID_field_name = "LINK_ID";
            gp.Execute(updateByAltIDTool, trackcancel);

            // Delete the temporary network dataset

            tempNDS.Delete();

            // Write the turn geometries

            TurnGeometryUtilities.WriteTurnGeometry(outputFileGdbPath, StreetsFCName, TurnFCName,
                                                    numAltIDFields, 0.3, messages, trackcancel);

            // Index the turn geometries

            messages.AddMessage("Creating spatial index on the turn feature class...");

            AddSpatialIndex addSpatialIndexTool = new AddSpatialIndex();
            addSpatialIndexTool.in_features = pathToFds + "\\" + TurnFCName;
            gp.Execute(addSpatialIndexTool, trackcancel);

            return;
        }
        private void CreateAndPopulateTurnFeatureClass(string outputFileGdbPath, string fdsName,
                                                       string ProhibMPTableName, string tempStatsTableName,
                                                       IGPMessages messages, ITrackCancel trackcancel)
        {
            // Determine the number of AltID fields we need (the same as the MAX_SEQNR value).

            Type factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory");
            var wsf = Activator.CreateInstance(factoryType) as IWorkspaceFactory;
            var fws = wsf.OpenFromFile(outputFileGdbPath, 0) as IFeatureWorkspace;
            ITable tempStatsTable = fws.OpenTable(tempStatsTableName);
            short numAltIDFields = 2;
            if (tempStatsTable.RowCount(null) == 1)
                numAltIDFields = (short)((double)(tempStatsTable.GetRow(1).get_Value(tempStatsTable.FindField("MAX_SEQNR"))));

            // Open the MP table and find the fields we need

            ITable mpTable = fws.OpenTable(ProhibMPTableName);
            int seqNrField = mpTable.FindField("SEQNR");
            int trpElIDField = mpTable.FindField("TRPELID");
            int idFieldOnMP = mpTable.FindField("ID");
            int mpJnctIDField = mpTable.FindField("JNCTID");

            // Create a temporary template feature class

            var fcd = new FeatureClassDescriptionClass() as IFeatureClassDescription;
            var ocd = fcd as IObjectClassDescription;
            var fieldsEdit = ocd.RequiredFields as IFieldsEdit;
            IField fieldOnMPTable = mpTable.Fields.get_Field(idFieldOnMP);  // use the ID field as a template for the AltID fields
            for (short i = 1; i <= numAltIDFields; i++)
            {
                IFieldEdit newField = new FieldClass();
                newField.Name_2 = "AltID" + i;
                newField.Precision_2 = fieldOnMPTable.Precision;
                newField.Scale_2 = fieldOnMPTable.Scale;
                newField.Type_2 = fieldOnMPTable.Type;
                fieldsEdit.AddField(newField as IField);
            }
            fieldsEdit.AddField(fieldOnMPTable);
            fieldOnMPTable = mpTable.Fields.get_Field(mpJnctIDField);
            fieldsEdit.AddField(fieldOnMPTable);
            var fieldChk = new FieldCheckerClass() as IFieldChecker;
            IEnumFieldError enumFieldErr = null;
            IFields validatedFields = null;
            fieldChk.ValidateWorkspace = fws as IWorkspace;
            fieldChk.Validate(fieldsEdit as IFields, out enumFieldErr, out validatedFields);
            var tempFC = fws.CreateFeatureClass("TheTemplate", validatedFields, ocd.InstanceCLSID, ocd.ClassExtensionCLSID,
                                                esriFeatureType.esriFTSimple, fcd.ShapeFieldName, "") as IDataset;

            // Create the turn feature class from the template, then delete the template

            Geoprocessor gp = new Geoprocessor();
            CreateTurnFeatureClass createTurnFCTool = new CreateTurnFeatureClass();
            string pathToFds = outputFileGdbPath + "\\" + fdsName;
            createTurnFCTool.out_location = pathToFds;
            createTurnFCTool.out_feature_class_name = TurnFCName;
            createTurnFCTool.maximum_edges = numAltIDFields;
            createTurnFCTool.in_template_feature_class = outputFileGdbPath + "\\TheTemplate";
            gp.Execute(createTurnFCTool, trackcancel);
            tempFC.Delete();

            // Open the new turn feature class and find all the fields on it

            IFeatureClass turnFC = fws.OpenFeatureClass(TurnFCName);
            int[] altIDFields = new int[numAltIDFields];
            int[] edgeFCIDFields = new int[numAltIDFields];
            int[] edgeFIDFields = new int[numAltIDFields];
            int[] edgePosFields = new int[numAltIDFields];
            for (short i = 0; i < numAltIDFields; i++)
            {
                altIDFields[i] = turnFC.FindField("AltID" + (i + 1));
                edgeFCIDFields[i] = turnFC.FindField("Edge" + (i + 1) + "FCID");
                edgeFIDFields[i] = turnFC.FindField("Edge" + (i + 1) + "FID");
                edgePosFields[i] = turnFC.FindField("Edge" + (i + 1) + "Pos");
            }
            int edge1endField = turnFC.FindField("Edge1End");
            int idFieldOnTurnFC = turnFC.FindField("ID");
            int turnFCJnctIDField = turnFC.FindField("JNCTID");

            // Look up the FCID of the Streets feature class

            IFeatureClass streetsFC = fws.OpenFeatureClass(StreetsFCName);
            int streetsFCID = streetsFC.FeatureClassID;

            // Set up queries

            var ts = new TableSortClass() as ITableSort;
            ts.Fields = "ID, SEQNR";
            ts.set_Ascending("ID", true);
            ts.set_Ascending("SEQNR", true);
            ts.QueryFilter = new QueryFilterClass();
            ts.Table = mpTable;
            ts.Sort(null);
            ICursor mpCursor = ts.Rows;
            IFeatureCursor turnFCCursor = turnFC.Insert(true);
            IFeatureBuffer turnBuffer = turnFC.CreateFeatureBuffer();

            // Write the field values to the turn feature class accordingly

            turnBuffer.set_Value(edge1endField, "?");  // dummy value; will be updated in a later calculation
            int numFeatures = 0;
            IRow mpRow = mpCursor.NextRow();
            while (mpRow != null)
            {
                // Transfer the non-edge identifying field values to the buffer
                turnBuffer.set_Value(idFieldOnTurnFC, mpRow.get_Value(idFieldOnMP));
                turnBuffer.set_Value(turnFCJnctIDField, mpRow.get_Value(mpJnctIDField));

                // Write the AltID values to the buffer
                int seq = (int)(mpRow.get_Value(seqNrField));
                int lastEntry;
                do
                {
                    lastEntry = seq;
                    turnBuffer.set_Value(altIDFields[lastEntry - 1], mpRow.get_Value(trpElIDField));
                    mpRow = mpCursor.NextRow();
                    if (mpRow == null) break;
                    seq = (int)(mpRow.get_Value(seqNrField));
                } while (seq != 1);

                // Zero-out the unused fields
                for (int i = lastEntry; i < numAltIDFields; i++)
                    turnBuffer.set_Value(altIDFields[i], 0);

                // Write the FCID and Pos field values to the buffer
                for (short i = 0; i < numAltIDFields; i++)
                {
                    double altID = (double)(turnBuffer.get_Value(altIDFields[i]));
                    if (altID != 0)
                    {
                        turnBuffer.set_Value(edgeFCIDFields[i], streetsFCID);
                        turnBuffer.set_Value(edgeFIDFields[i], 1);
                        turnBuffer.set_Value(edgePosFields[i], 0.5);
                    }
                    else
                    {
                        turnBuffer.set_Value(edgeFCIDFields[i], 0);
                        turnBuffer.set_Value(edgeFIDFields[i], 0);
                        turnBuffer.set_Value(edgePosFields[i], 0);
                    }
                }

                // Create the turn feature
                turnFCCursor.InsertFeature(turnBuffer);
                numFeatures++;

                if ((numFeatures % 100) == 0)
                {
                    // check for user cancel

                    if (trackcancel != null && !trackcancel.Continue())
                        throw (new COMException("Function cancelled."));
                }
            }

            // Flush any outstanding writes to the turn feature class
            turnFCCursor.Flush();

            // Update the Edge1End values

            AddMessage("Updating the Edge1End values...", messages, trackcancel);

            MakeFeatureLayer makeFeatureLayerTool = new MakeFeatureLayer();
            makeFeatureLayerTool.in_features = pathToFds + "\\" + TurnFCName;
            makeFeatureLayerTool.out_layer = "Turn_Layer";
            gp.Execute(makeFeatureLayerTool, trackcancel);

            AddJoin addJoinTool = new AddJoin();
            addJoinTool.in_layer_or_view = "Turn_Layer";
            addJoinTool.in_field = "AltID1";
            addJoinTool.join_table = pathToFds + "\\" + StreetsFCName;
            addJoinTool.join_field = "ID";
            gp.Execute(addJoinTool, trackcancel);

            CalculateField calcFieldTool = new CalculateField();
            calcFieldTool.in_table = "Turn_Layer";
            calcFieldTool.field = TurnFCName + ".Edge1End";
            calcFieldTool.expression = "x";
            calcFieldTool.code_block = "Select Case [" + TurnFCName + ".JNCTID]\n  Case [" + StreetsFCName + ".F_JNCTID]: x = \"N\"\n  Case [" + StreetsFCName + ".T_JNCTID]: x = \"Y\"\n  Case Else: x = \"?\"\nEnd Select";
            calcFieldTool.expression_type = "VB";
            gp.Execute(calcFieldTool, trackcancel);

            RemoveJoin removeJoinTool = new RemoveJoin();
            removeJoinTool.in_layer_or_view = "Turn_Layer";
            removeJoinTool.join_name = StreetsFCName;
            gp.Execute(removeJoinTool, trackcancel);

            Delete deleteTool = new Delete();
            deleteTool.in_data = "Turn_Layer";
            gp.Execute(deleteTool, trackcancel);

            AddMessage("Updating the EdgeFID values...", messages, trackcancel);

            // Create a temporary network dataset for updating the EdgeFID values

            IDENetworkDataset dends = new DENetworkDatasetClass();
            dends.SupportsTurns = true;
            dends.Buildable = true;
            (dends as IDataElement).Name = StreetsFCName;
            (dends as IDEGeoDataset).SpatialReference = (streetsFC as IGeoDataset).SpatialReference;
            IArray sourceArray = new ArrayClass();
            var efs = new EdgeFeatureSourceClass() as IEdgeFeatureSource;
            (efs as INetworkSource).Name = StreetsFCName;
            efs.UsesSubtypes = false;
            efs.ClassConnectivityGroup = 1;
            efs.ClassConnectivityPolicy = esriNetworkEdgeConnectivityPolicy.esriNECPEndVertex;
            sourceArray.Add(efs);
            var tfs = new TurnFeatureSourceClass() as INetworkSource;
            tfs.Name = TurnFCName;
            sourceArray.Add(tfs);
            dends.Sources = sourceArray;
            var fdxc = fws.OpenFeatureDataset(fdsName) as IFeatureDatasetExtensionContainer;
            var dsCont = fdxc.FindExtension(esriDatasetType.esriDTNetworkDataset) as IDatasetContainer2;
            var tempNDS = dsCont.CreateDataset(dends as IDEDataset) as IDataset;

            // Set the EdgeFID field values by running UpdateByAlternateIDFields

            UpdateByAlternateIDFields updateByAltIDTool = new UpdateByAlternateIDFields();
            updateByAltIDTool.in_network_dataset = pathToFds + "\\" + StreetsFCName;
            updateByAltIDTool.alternate_ID_field_name = "ID";
            gp.Execute(updateByAltIDTool, trackcancel);

            // Delete the temporary network dataset

            tempNDS.Delete();

            // Write the turn geometries

            TurnGeometryUtilities.WriteTurnGeometry(outputFileGdbPath, StreetsFCName, TurnFCName,
                                                    numAltIDFields, 0.3, messages, trackcancel);

            // Index the turn geometries

            AddMessage("Creating spatial index on the turn feature class...", messages, trackcancel);

            AddSpatialIndex addSpatialIndexTool = new AddSpatialIndex();
            addSpatialIndexTool.in_features = pathToFds + "\\" + TurnFCName;
            gp.Execute(addSpatialIndexTool, trackcancel);

            return;
        }