public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriSystem.ITrackCancel TrackCancel, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr, ESRI.ArcGIS.Geodatabase.IGPMessages message)
        {
            IFeatureClass osmPointFeatureClass = null;
            IFeatureClass osmLineFeatureClass = null;
            IFeatureClass osmPolygonFeatureClass = null;
            OSMToolHelper osmToolHelper = null;

            try
            {
                DateTime syncTime = DateTime.Now;

                IGPUtilities3 gpUtilities3 = new GPUtilitiesClass();
                osmToolHelper = new OSMToolHelper();

                if (TrackCancel == null)
                {
                    TrackCancel = new CancelTrackerClass();
                }

                IGPParameter osmFileParameter = paramvalues.get_Element(in_osmFileNumber) as IGPParameter;
                IGPValue osmFileLocationString = gpUtilities3.UnpackGPValue(osmFileParameter) as IGPValue;

                // ensure that the specified file does exist
                bool osmFileExists = false;

                try
                {
                    osmFileExists = System.IO.File.Exists(osmFileLocationString.GetAsText());
                }
                catch (Exception ex)
                {
                    message.AddError(120029, String.Format(resourceManager.GetString("GPTools_OSMGPMultiLoader_problemaccessingfile"), ex.Message));
                    return;
                }

                if (osmFileExists == false)
                {
                    message.AddError(120030, String.Format(resourceManager.GetString("GPTools_OSMGPFileReader_osmfiledoesnotexist"), osmFileLocationString.GetAsText()));
                    return;
                }

                long nodeCapacity = 0;
                long wayCapacity = 0;
                long relationCapacity = 0;

                // this assume a clean, tidy XML file - if this is not the case, there will by sync issues later on
                osmToolHelper.countOSMStuffFast(osmFileLocationString.GetAsText(), ref nodeCapacity, ref wayCapacity, ref relationCapacity, ref TrackCancel);

                if (nodeCapacity == 0 && wayCapacity == 0 && relationCapacity == 0)
                {
                    return;
                }

                message.AddMessage(String.Format(resourceManager.GetString("GPTools_OSMGPMultiLoader_countedElements"), nodeCapacity, wayCapacity, relationCapacity));

                // determine the number of threads to be used
                IGPEnvironment parallelProcessingFactorEnvironment = OSMToolHelper.getEnvironment(envMgr, "parallelProcessingFactor");
                IGPString parallelProcessingFactorString = parallelProcessingFactorEnvironment.Value as IGPString;

                // the default value is to use half the cores for additional threads - I am aware that we are comparing apples and oranges but I need a number
                int numberOfThreads = Convert.ToInt32(System.Environment.ProcessorCount / 2);

                if (!(parallelProcessingFactorEnvironment.Value.IsEmpty()))
                {
                    if (!Int32.TryParse(parallelProcessingFactorString.Value, out numberOfThreads))
                    {
                        // this case we have a percent string
                        string resultString = Regex.Match(parallelProcessingFactorString.Value, @"\d+").Value;
                        numberOfThreads = Convert.ToInt32(Int32.Parse(resultString) / 100 * System.Environment.ProcessorCount);
                    }
                }

                // tread the special case of 0
                if (numberOfThreads <= 0)
                    numberOfThreads = 1;

                IGPEnvironment configKeyword = OSMToolHelper.getEnvironment(envMgr, "configKeyword");
                IGPString gpString = configKeyword.Value as IGPString;

                string storageKeyword = String.Empty;

                if (gpString != null)
                {
                    storageKeyword = gpString.Value;
                }

                // determine the temp folder to be use for the intermediate files
                IGPEnvironment scratchWorkspaceEnvironment = OSMToolHelper.getEnvironment(envMgr, "scratchWorkspace");
                IDEWorkspace deWorkspace = scratchWorkspaceEnvironment.Value as IDEWorkspace;
                String scratchWorkspaceFolder = String.Empty;

                if (deWorkspace != null)
                {
                    if (scratchWorkspaceEnvironment.Value.IsEmpty())
                    {
                        scratchWorkspaceFolder = (new System.IO.FileInfo(osmFileLocationString.GetAsText())).DirectoryName;
                    }
                    else
                    {
                        if (deWorkspace.WorkspaceType == esriWorkspaceType.esriRemoteDatabaseWorkspace)
                        {
                            scratchWorkspaceFolder = System.IO.Path.GetTempPath();
                        }
                        else if (deWorkspace.WorkspaceType == esriWorkspaceType.esriFileSystemWorkspace)
                        {
                            scratchWorkspaceFolder = ((IDataElement)deWorkspace).CatalogPath;
                        }
                        else
                        {
                            scratchWorkspaceFolder = (new System.IO.FileInfo(((IDataElement)deWorkspace).CatalogPath)).DirectoryName;
                        }
                    }
                }
                else
                {
                    scratchWorkspaceFolder = (new System.IO.FileInfo(osmFileLocationString.GetAsText())).DirectoryName;
                }

                string metadataAbstract = resourceManager.GetString("GPTools_OSMGPFileReader_metadata_abstract");
                string metadataPurpose = resourceManager.GetString("GPTools_OSMGPFileReader_metadata_purpose");

                IGPParameter osmPointsFeatureClassParameter = paramvalues.get_Element(out_osmPointsNumber) as IGPParameter;
                IGPValue osmPointsFeatureClassGPValue = gpUtilities3.UnpackGPValue(osmPointsFeatureClassParameter) as IGPValue;

                IName workspaceName = gpUtilities3.CreateParentFromCatalogPath(osmPointsFeatureClassGPValue.GetAsText());
                IWorkspace2 pointFeatureWorkspace = workspaceName.Open() as IWorkspace2;

                string[] pointFCNameElements = osmPointsFeatureClassGPValue.GetAsText().Split(System.IO.Path.DirectorySeparatorChar);

                IGPParameter tagPointCollectionParameter = paramvalues.get_Element(in_pointFieldNamesNumber) as IGPParameter;
                IGPMultiValue tagPointCollectionGPValue = gpUtilities3.UnpackGPValue(tagPointCollectionParameter) as IGPMultiValue;

                List<String> pointTagstoExtract = null;

                if (tagPointCollectionGPValue.Count > 0)
                {
                    pointTagstoExtract = new List<string>();

                    for (int valueIndex = 0; valueIndex < tagPointCollectionGPValue.Count; valueIndex++)
                    {
                        string nameOfTag = tagPointCollectionGPValue.get_Value(valueIndex).GetAsText();

                        pointTagstoExtract.Add(nameOfTag);
                    }
                }
                else
                {
                    pointTagstoExtract = OSMToolHelper.OSMSmallFeatureClassFields();
                }

                // points
                try
                {
                    osmPointFeatureClass = osmToolHelper.CreateSmallPointFeatureClass(pointFeatureWorkspace,
                        pointFCNameElements[pointFCNameElements.Length - 1], storageKeyword, metadataAbstract,
                        metadataPurpose, pointTagstoExtract);
                }
                catch (Exception ex)
                {
                    message.AddError(120035, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nullpointfeatureclass"), ex.Message));
                    return;
                }

                if (osmPointFeatureClass == null)
                {
                    return;
                }

                int osmPointIDFieldIndex = osmPointFeatureClass.FindField("OSMID");
                Dictionary<string, int> mainPointAttributeFieldIndices = new Dictionary<string, int>();

                foreach (string fieldName in OSMToolHelper.OSMSmallFeatureClassFields())
                {
                    int currentFieldIndex = osmPointFeatureClass.FindField(fieldName);

                    if (currentFieldIndex != -1)
                    {
                        mainPointAttributeFieldIndices.Add(fieldName, currentFieldIndex);
                    }
                }

                int tagCollectionPointFieldIndex = osmPointFeatureClass.FindField("osmTags");
                int osmSupportingElementPointFieldIndex = osmPointFeatureClass.FindField("osmSupportingElement");

                IGPParameter osmLineFeatureClassParameter = paramvalues.get_Element(out_osmLinesNumber) as IGPParameter;
                IGPValue osmLineFeatureClassGPValue = gpUtilities3.UnpackGPValue(osmLineFeatureClassParameter) as IGPValue;

                IName lineWorkspaceName = gpUtilities3.CreateParentFromCatalogPath(osmLineFeatureClassGPValue.GetAsText());
                IWorkspace2 lineFeatureWorkspace = lineWorkspaceName.Open() as IWorkspace2;

                string[] lineFCNameElements = osmLineFeatureClassGPValue.GetAsText().Split(System.IO.Path.DirectorySeparatorChar);

                IGPParameter tagLineCollectionParameter = paramvalues.get_Element(in_lineFieldNamesNumber) as IGPParameter;
                IGPMultiValue tagLineCollectionGPValue = gpUtilities3.UnpackGPValue(tagLineCollectionParameter) as IGPMultiValue;

                List<String> lineTagstoExtract = null;

                if (tagLineCollectionGPValue.Count > 0)
                {
                    lineTagstoExtract = new List<string>();

                    for (int valueIndex = 0; valueIndex < tagLineCollectionGPValue.Count; valueIndex++)
                    {
                        string nameOfTag = tagLineCollectionGPValue.get_Value(valueIndex).GetAsText();

                        lineTagstoExtract.Add(nameOfTag);
                    }
                }
                else
                {
                    lineTagstoExtract = OSMToolHelper.OSMSmallFeatureClassFields();
                }

                // lines
                try
                {
                    osmLineFeatureClass = osmToolHelper.CreateSmallLineFeatureClass(lineFeatureWorkspace, lineFCNameElements[lineFCNameElements.Length -1],
                        storageKeyword, metadataAbstract, metadataPurpose, lineTagstoExtract);
                }
                catch (Exception ex)
                {
                    message.AddError(120036, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nulllinefeatureclass"), ex.Message));
                    return;
                }

                if (osmLineFeatureClass == null)
                {
                    return;
                }

                int osmLineIDFieldIndex = osmLineFeatureClass.FindField("OSMID");

                Dictionary<string, int> mainLineAttributeFieldIndices = new Dictionary<string, int>();
                foreach (string fieldName in OSMToolHelper.OSMSmallFeatureClassFields())
                {
                    int currentFieldIndex = osmLineFeatureClass.FindField(fieldName);

                    if (currentFieldIndex != -1)
                    {
                        mainLineAttributeFieldIndices.Add(fieldName, currentFieldIndex);
                    }
                }

                int tagCollectionPolylineFieldIndex = osmLineFeatureClass.FindField("osmTags");
                int osmSupportingElementPolylineFieldIndex = osmLineFeatureClass.FindField("osmSupportingElement");

                IGPParameter osmPolygonFeatureClassParameter = paramvalues.get_Element(out_osmPolygonsNumber) as IGPParameter;
                IGPValue osmPolygonFeatureClassGPValue = gpUtilities3.UnpackGPValue(osmPolygonFeatureClassParameter) as IGPValue;

                IName polygonWorkspaceName = gpUtilities3.CreateParentFromCatalogPath(osmPolygonFeatureClassGPValue.GetAsText());
                IWorkspace2 polygonFeatureWorkspace = polygonWorkspaceName.Open() as IWorkspace2;

                string[] polygonFCNameElements = osmPolygonFeatureClassGPValue.GetAsText().Split(System.IO.Path.DirectorySeparatorChar);

                IGPParameter tagPolygonCollectionParameter = paramvalues.get_Element(in_polygonFieldNamesNumber) as IGPParameter;
                IGPMultiValue tagPolygonCollectionGPValue = gpUtilities3.UnpackGPValue(tagPolygonCollectionParameter) as IGPMultiValue;

                List<String> polygonTagstoExtract = null;

                if (tagPolygonCollectionGPValue.Count > 0)
                {
                    polygonTagstoExtract = new List<string>();

                    for (int valueIndex = 0; valueIndex < tagPolygonCollectionGPValue.Count; valueIndex++)
                    {
                        string nameOfTag = tagPolygonCollectionGPValue.get_Value(valueIndex).GetAsText();

                        polygonTagstoExtract.Add(nameOfTag);
                    }
                }
                else
                {
                    polygonTagstoExtract = OSMToolHelper.OSMSmallFeatureClassFields();
                }

                // polygons
                try
                {
                    osmPolygonFeatureClass = osmToolHelper.CreateSmallPolygonFeatureClass(polygonFeatureWorkspace,
                        polygonFCNameElements[polygonFCNameElements.Length -1], storageKeyword, metadataAbstract,
                        metadataPurpose, polygonTagstoExtract);
                }
                catch (Exception ex)
                {
                    message.AddError(120037, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nullpolygonfeatureclass"), ex.Message));
                    return;
                }

                if (osmPolygonFeatureClass == null)
                {
                    return;
                }

                int osmPolygonIDFieldIndex = osmPolygonFeatureClass.FindField("OSMID");

                Dictionary<string, int> mainPolygonAttributeFieldIndices = new Dictionary<string, int>();
                foreach (var fieldName in OSMToolHelper.OSMSmallFeatureClassFields())
                {
                    int currentFieldIndex = osmPolygonFeatureClass.FindField(fieldName);

                    if (currentFieldIndex != -1)
                    {
                        mainPolygonAttributeFieldIndices.Add(fieldName, currentFieldIndex);
                    }
                }

                int tagCollectionPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmTags");
                int osmSupportingElementPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmSupportingElement");

                ComReleaser.ReleaseCOMObject(osmPointFeatureClass);
                osmPointFeatureClass = null;

                ComReleaser.ReleaseCOMObject(osmLineFeatureClass);
                osmLineFeatureClass = null;

                ComReleaser.ReleaseCOMObject(osmPolygonFeatureClass);
                osmPolygonFeatureClass = null;

                List<string> nodeOSMFileNames = new List<string>(numberOfThreads);
                List<string> nodeGDBFileNames = new List<string>(numberOfThreads);

                List<string> wayOSMFileNames = new List<string>(numberOfThreads);
                List<string> wayGDBFileNames = new List<string>(numberOfThreads);

                List<string> relationOSMFileNames = new List<string>(numberOfThreads);
                List<string> relationGDBFileNames = new List<string>(numberOfThreads);

                if (TrackCancel.Continue() == false)
                {
                    return;
                }

                // split the original OSM xml file into smaller pieces for the python processes
                osmToolHelper.splitOSMFile(osmFileLocationString.GetAsText(), scratchWorkspaceFolder, nodeCapacity, wayCapacity, relationCapacity, numberOfThreads,
                    out nodeOSMFileNames, out nodeGDBFileNames, out wayOSMFileNames, out wayGDBFileNames, out relationOSMFileNames, out relationGDBFileNames);

                IGPParameter deleteSourceOSMFileParameter = paramvalues.get_Element(in_deleteOSMSourceFileNumber) as IGPParameter;
                IGPBoolean deleteSourceOSMFileGPValue = gpUtilities3.UnpackGPValue(deleteSourceOSMFileParameter) as IGPBoolean;

                if (deleteSourceOSMFileGPValue.Value)
                {
                    try
                    {
                        System.IO.File.Delete(osmFileLocationString.GetAsText());
                    }
                    catch (Exception ex)
                    {
                        message.AddWarning(ex.Message);
                    }
                }

                if (TrackCancel.Continue() == false)
                {
                    return;
                }

                if (nodeOSMFileNames.Count == 0)
                {
                    nodeOSMFileNames.Add(osmFileLocationString.GetAsText());
                    nodeGDBFileNames.Add(osmPointsFeatureClassGPValue.GetAsText());

                    wayOSMFileNames.Add(osmFileLocationString.GetAsText());
                    wayGDBFileNames.Add(osmLineFeatureClassGPValue.GetAsText());

                    relationOSMFileNames.Add(osmFileLocationString.GetAsText());
                    relationGDBFileNames.Add(osmPolygonFeatureClassGPValue.GetAsText());
                }
                else
                {
                    // for the nodes let's load one of the parts directly into the target file geodatabase
                    nodeGDBFileNames[0] = ((IWorkspace)pointFeatureWorkspace).PathName;
                }

                // define variables helping to invoke core tools for data management
                IGeoProcessorResult2 gpResults2 = null;
                IGeoProcessor2 geoProcessor = new GeoProcessorClass();

                IGPParameter deleteSupportingNodesParameter = paramvalues.get_Element(in_deleteSupportNodesNumber) as IGPParameter;
                IGPBoolean deleteSupportingNodesGPValue = gpUtilities3.UnpackGPValue(deleteSupportingNodesParameter) as IGPBoolean;

                #region load points
                osmToolHelper.loadOSMNodes(nodeOSMFileNames, nodeGDBFileNames, pointFCNameElements[pointFCNameElements.Length - 1], osmPointsFeatureClassGPValue.GetAsText(), pointTagstoExtract, deleteSupportingNodesGPValue.Value, ref message, ref TrackCancel);
                #endregion

                if (TrackCancel.Continue() == false)
                {
                    return;
                }

                #region load ways
                osmToolHelper.loadOSMWays(wayOSMFileNames, osmPointsFeatureClassGPValue.GetAsText(), wayGDBFileNames, lineFCNameElements[lineFCNameElements.Length - 1], polygonFCNameElements[polygonFCNameElements.Length - 1], lineTagstoExtract, polygonTagstoExtract, ref message,  ref TrackCancel);
                #endregion

                #region for local geodatabases enforce spatial integrity

                bool storedOriginalLocal = geoProcessor.AddOutputsToMap;
                geoProcessor.AddOutputsToMap = false;

                try
                {
                    osmLineFeatureClass = ((IFeatureWorkspace)lineFeatureWorkspace).OpenFeatureClass(lineFCNameElements[lineFCNameElements.Length - 1]);

                    if (osmLineFeatureClass != null)
                    {

                        if (((IDataset)osmLineFeatureClass).Workspace.Type == esriWorkspaceType.esriLocalDatabaseWorkspace)
                        {
                            gpUtilities3 = new GPUtilitiesClass() as IGPUtilities3;

                            IGPParameter outLinesParameter = paramvalues.get_Element(out_osmLinesNumber) as IGPParameter;
                            IGPValue lineFeatureClass = gpUtilities3.UnpackGPValue(outLinesParameter);

                            DataManagementTools.RepairGeometry repairlineGeometry = new DataManagementTools.RepairGeometry(osmLineFeatureClass);

                            IVariantArray repairGeometryParameterArray = new VarArrayClass();
                            repairGeometryParameterArray.Add(lineFeatureClass.GetAsText());
                            repairGeometryParameterArray.Add("DELETE_NULL");

                            gpResults2 = geoProcessor.Execute(repairlineGeometry.ToolName, repairGeometryParameterArray, TrackCancel) as IGeoProcessorResult2;
                            message.AddMessages(gpResults2.GetResultMessages());

                            ComReleaser.ReleaseCOMObject(gpUtilities3);
                        }
                    }
                }
                catch { }
                finally
                {
                    ComReleaser.ReleaseCOMObject(osmLineFeatureClass);
                }

                try
                {
                    osmPolygonFeatureClass = ((IFeatureWorkspace)polygonFeatureWorkspace).OpenFeatureClass(polygonFCNameElements[polygonFCNameElements.Length - 1]);

                    if (osmPolygonFeatureClass != null)
                    {
                        if (((IDataset)osmPolygonFeatureClass).Workspace.Type == esriWorkspaceType.esriLocalDatabaseWorkspace)
                        {
                            gpUtilities3 = new GPUtilitiesClass() as IGPUtilities3;

                            IGPParameter outPolygonParameter = paramvalues.get_Element(out_osmPolygonsNumber) as IGPParameter;
                            IGPValue polygonFeatureClass = gpUtilities3.UnpackGPValue(outPolygonParameter);

                            DataManagementTools.RepairGeometry repairpolygonGeometry = new DataManagementTools.RepairGeometry(osmPolygonFeatureClass);

                            IVariantArray repairGeometryParameterArray = new VarArrayClass();
                            repairGeometryParameterArray.Add(polygonFeatureClass.GetAsText());
                            repairGeometryParameterArray.Add("DELETE_NULL");

                            gpResults2 = geoProcessor.Execute(repairpolygonGeometry.ToolName, repairGeometryParameterArray, TrackCancel) as IGeoProcessorResult2;
                            message.AddMessages(gpResults2.GetResultMessages());

                            ComReleaser.ReleaseCOMObject(gpUtilities3);
                        }
                    }
                }
                catch { }
                finally
                {
                    ComReleaser.ReleaseCOMObject(osmPolygonFeatureClass);
                }

                geoProcessor.AddOutputsToMap = storedOriginalLocal;

                #endregion

                if (TrackCancel.Continue() == false)
                {
                    return;
                }

                #region load relations
                osmToolHelper.loadOSMRelations(relationOSMFileNames, osmLineFeatureClassGPValue.GetAsText(), osmPolygonFeatureClassGPValue.GetAsText(), relationGDBFileNames, lineTagstoExtract, polygonTagstoExtract, ref TrackCancel, ref message);
                #endregion

                // check for user interruption
                if (TrackCancel.Continue() == false)
                {
                    return;
                }

                #region for local geodatabases enforce spatial integrity
                //storedOriginalLocal = geoProcessor.AddOutputsToMap;
                //geoProcessor.AddOutputsToMap = false;

                //try
                //{
                //    osmLineFeatureClass = ((IFeatureWorkspace)lineFeatureWorkspace).OpenFeatureClass(lineFCNameElements[lineFCNameElements.Length - 1]);

                //    if (osmLineFeatureClass != null)
                //    {

                //        if (((IDataset)osmLineFeatureClass).Workspace.Type == esriWorkspaceType.esriLocalDatabaseWorkspace)
                //        {
                //            gpUtilities3 = new GPUtilitiesClass() as IGPUtilities3;

                //            IGPParameter outLinesParameter = paramvalues.get_Element(out_osmLinesNumber) as IGPParameter;
                //            IGPValue lineFeatureClass = gpUtilities3.UnpackGPValue(outLinesParameter);

                //            DataManagementTools.RepairGeometry repairlineGeometry = new DataManagementTools.RepairGeometry(osmLineFeatureClass);

                //            IVariantArray repairGeometryParameterArray = new VarArrayClass();
                //            repairGeometryParameterArray.Add(lineFeatureClass.GetAsText());
                //            repairGeometryParameterArray.Add("DELETE_NULL");

                //            gpResults2 = geoProcessor.Execute(repairlineGeometry.ToolName, repairGeometryParameterArray, TrackCancel) as IGeoProcessorResult2;
                //            message.AddMessages(gpResults2.GetResultMessages());

                //            ComReleaser.ReleaseCOMObject(gpUtilities3);
                //        }
                //    }
                //}
                //catch { }
                //finally
                //{
                //    ComReleaser.ReleaseCOMObject(osmLineFeatureClass);
                //}

                //try
                //{
                //    osmPolygonFeatureClass = ((IFeatureWorkspace)polygonFeatureWorkspace).OpenFeatureClass(polygonFCNameElements[polygonFCNameElements.Length - 1]);

                //    if (osmPolygonFeatureClass != null)
                //    {
                //        if (((IDataset)osmPolygonFeatureClass).Workspace.Type == esriWorkspaceType.esriLocalDatabaseWorkspace)
                //        {
                //            gpUtilities3 = new GPUtilitiesClass() as IGPUtilities3;

                //            IGPParameter outPolygonParameter = paramvalues.get_Element(out_osmPolygonsNumber) as IGPParameter;
                //            IGPValue polygonFeatureClass = gpUtilities3.UnpackGPValue(outPolygonParameter);

                //            DataManagementTools.RepairGeometry repairpolygonGeometry = new DataManagementTools.RepairGeometry(osmPolygonFeatureClass);

                //            IVariantArray repairGeometryParameterArray = new VarArrayClass();
                //            repairGeometryParameterArray.Add(polygonFeatureClass.GetAsText());
                //            repairGeometryParameterArray.Add("DELETE_NULL");

                //            gpResults2 = geoProcessor.Execute(repairpolygonGeometry.ToolName, repairGeometryParameterArray, TrackCancel) as IGeoProcessorResult2;
                //            message.AddMessages(gpResults2.GetResultMessages());

                //            ComReleaser.ReleaseCOMObject(gpUtilities3);
                //        }
                //    }
                //}
                //catch { }
                //finally
                //{
                //    ComReleaser.ReleaseCOMObject(osmPolygonFeatureClass);
                //}

                //geoProcessor.AddOutputsToMap = storedOriginalLocal;

                #endregion

                if (TrackCancel.Continue() == false)
                {
                    return;
                }

                if (deleteSupportingNodesGPValue.Value)
                {
                    message.AddMessage(String.Format(resourceManager.GetString("GPTools_OSMGPMultiLoader_remove_supportNodes")));

                    storedOriginalLocal = geoProcessor.AddOutputsToMap;
                    geoProcessor.AddOutputsToMap = false;

                    // create a layer file to select the points that have attributes
                    osmPointFeatureClass = ((IFeatureWorkspace)pointFeatureWorkspace).OpenFeatureClass(pointFCNameElements[pointFCNameElements.Length - 1]);

                    IVariantArray makeFeatureLayerParameterArray = new VarArrayClass();
                    makeFeatureLayerParameterArray.Add(osmPointsFeatureClassGPValue.GetAsText());

                    string tempLayerFile = System.IO.Path.GetTempFileName();
                    makeFeatureLayerParameterArray.Add(tempLayerFile);
                    makeFeatureLayerParameterArray.Add(String.Format("{0} = 'no'", osmPointFeatureClass.SqlIdentifier("osmSupportingElement")));

                    geoProcessor.Execute("MakeFeatureLayer_management", makeFeatureLayerParameterArray, TrackCancel);

                    // copy the features into its own feature class
                    IVariantArray copyFeatureParametersArray = new VarArrayClass();
                    copyFeatureParametersArray.Add(tempLayerFile);

                    string tempFeatureClass = String.Join("\\", new string[] {
                        ((IWorkspace)pointFeatureWorkspace).PathName, "t_" + pointFCNameElements[pointFCNameElements.Length - 1] });
                    copyFeatureParametersArray.Add(tempFeatureClass);

                    geoProcessor.Execute("CopyFeatures_management", copyFeatureParametersArray, TrackCancel);

                    // delete the temp file
                    System.IO.File.Delete(tempLayerFile);

                    // delete the original feature class
                    IVariantArray deleteParameterArray = new VarArrayClass();
                    deleteParameterArray.Add(osmPointsFeatureClassGPValue.GetAsText());

                    geoProcessor.Execute("Delete_management", deleteParameterArray, TrackCancel);

                    // rename the temp feature class back to the original
                    IVariantArray renameParameterArray = new VarArrayClass();
                    renameParameterArray.Add(tempFeatureClass);
                    renameParameterArray.Add(osmPointsFeatureClassGPValue.GetAsText());

                    geoProcessor.Execute("Rename_management", renameParameterArray, TrackCancel);

                    geoProcessor.AddOutputsToMap = storedOriginalLocal;

                    ComReleaser.ReleaseCOMObject(osmPointFeatureClass);
                    ComReleaser.ReleaseCOMObject(geoProcessor);
                }

                gpUtilities3 = new GPUtilitiesClass() as IGPUtilities3;

                // repackage the feature class into their respective gp values
                IGPParameter pointFeatureClassParameter = paramvalues.get_Element(out_osmPointsNumber) as IGPParameter;
                IGPValue pointFeatureClassGPValue = gpUtilities3.UnpackGPValue(pointFeatureClassParameter);
                gpUtilities3.PackGPValue(pointFeatureClassGPValue, pointFeatureClassParameter);

                IGPParameter lineFeatureClassParameter = paramvalues.get_Element(out_osmLinesNumber) as IGPParameter;
                IGPValue line1FeatureClassGPValue = gpUtilities3.UnpackGPValue(lineFeatureClassParameter);
                gpUtilities3.PackGPValue(line1FeatureClassGPValue, lineFeatureClassParameter);

                IGPParameter polygonFeatureClassParameter = paramvalues.get_Element(out_osmPolygonsNumber) as IGPParameter;
                IGPValue polygon1FeatureClassGPValue = gpUtilities3.UnpackGPValue(polygonFeatureClassParameter);
                gpUtilities3.PackGPValue(polygon1FeatureClassGPValue, polygonFeatureClassParameter);

                ComReleaser.ReleaseCOMObject(osmFileLocationString);

                gpUtilities3.ReleaseInternals();
                ComReleaser.ReleaseCOMObject(gpUtilities3);
            }
            catch (Exception ex)
            {
                message.AddError(120055, ex.Message);
                message.AddError(120055, ex.StackTrace);
            }
            finally
            {
                try
                {
                    osmToolHelper = null;

                    System.GC.Collect();
                    System.GC.WaitForPendingFinalizers();
                }
                catch (Exception ex)
                {
                    message.AddError(120056, ex.ToString());
                }
            }
        }
        public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriSystem.ITrackCancel TrackCancel, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr, ESRI.ArcGIS.Geodatabase.IGPMessages message)
        {
            IFeatureClass osmPointFeatureClass = null;
            IFeatureClass osmLineFeatureClass = null;
            IFeatureClass osmPolygonFeatureClass = null;
            OSMToolHelper osmToolHelper = null;

            try
            {
                DateTime syncTime = DateTime.Now;

                IGPUtilities3 gpUtilities3 = new GPUtilitiesClass();
                osmToolHelper = new OSMToolHelper();

                if (TrackCancel == null)
                {
                    TrackCancel = new CancelTrackerClass();
                }

                IGPParameter osmFileParameter = paramvalues.get_Element(in_osmFileNumber) as IGPParameter;
                IGPValue osmFileLocationString = gpUtilities3.UnpackGPValue(osmFileParameter) as IGPValue;

                // ensure that the specified file does exist
                bool osmFileExists = false;

                try
                {
                    osmFileExists = System.IO.File.Exists(osmFileLocationString.GetAsText());
                }
                catch (Exception ex)
                {
                    message.AddError(120029, String.Format(resourceManager.GetString("GPTools_OSMGPFileReader_problemaccessingfile"), ex.Message));
                    return;
                }

                if (osmFileExists == false)
                {
                    message.AddError(120030, String.Format(resourceManager.GetString("GPTools_OSMGPFileReader_osmfiledoesnotexist"), osmFileLocationString.GetAsText()));
                    return;
                }

                IGPParameter conserveMemoryParameter = paramvalues.get_Element(in_conserveMemoryNumber) as IGPParameter;
                IGPBoolean conserveMemoryGPValue = gpUtilities3.UnpackGPValue(conserveMemoryParameter) as IGPBoolean;

                if (conserveMemoryGPValue == null)
                {
                    message.AddError(120031, string.Format(resourceManager.GetString("GPTools_NullPointerParameterType"), conserveMemoryParameter.Name));
                    return;
                }

                message.AddMessage(resourceManager.GetString("GPTools_OSMGPFileReader_countingNodes"));
                long nodeCapacity = 0;
                long wayCapacity = 0;
                long relationCapacity = 0;

                Dictionary<esriGeometryType, List<string>> attributeTags = new Dictionary<esriGeometryType, List<string>>();

                IGPParameter tagCollectionParameter = paramvalues.get_Element(in_attributeSelector) as IGPParameter;
                IGPMultiValue tagCollectionGPValue = gpUtilities3.UnpackGPValue(tagCollectionParameter) as IGPMultiValue;

                List<String> tagstoExtract = null;

                if (tagCollectionGPValue.Count > 0)
                {
                    tagstoExtract = new List<string>();

                    for (int valueIndex = 0; valueIndex < tagCollectionGPValue.Count; valueIndex++)
                    {
                        string nameOfTag = tagCollectionGPValue.get_Value(valueIndex).GetAsText();

                        if (nameOfTag.ToUpper().Equals("ALL"))
                        {
                            tagstoExtract = new List<string>();
                            break;
                        }
                        else
                        {
                            tagstoExtract.Add(nameOfTag);
                        }
                    }
                }

                // if there is an "ALL" keyword then we scan for all tags, otherwise we only add the desired tags to the feature classes and do a 'quick'
                // count scan

                if (tagstoExtract != null)
                {
                    if (tagstoExtract.Count > 0)
                    {
                        // if the number of tags is > 0 then do a simple feature count and take name tags names from the gp value
                        osmToolHelper.countOSMStuff(osmFileLocationString.GetAsText(), ref nodeCapacity, ref wayCapacity, ref relationCapacity, ref TrackCancel);
                        attributeTags.Add(esriGeometryType.esriGeometryPoint, tagstoExtract);
                        attributeTags.Add(esriGeometryType.esriGeometryPolyline, tagstoExtract);
                        attributeTags.Add(esriGeometryType.esriGeometryPolygon, tagstoExtract);
                    }
                    else
                    {
                        // the count should be zero if we encountered the "ALL" keyword 
                        // in this case count the features and create a list of unique tags
                        attributeTags = osmToolHelper.countOSMCapacityAndTags(osmFileLocationString.GetAsText(), ref nodeCapacity, ref wayCapacity, ref relationCapacity, ref TrackCancel);
                    }
                }
                else
                {
                    // no tags we defined, hence we do a simple count and create an empty list indicating that no additional fields
                    // need to be created
                    osmToolHelper.countOSMStuff(osmFileLocationString.GetAsText(), ref nodeCapacity, ref wayCapacity, ref relationCapacity, ref TrackCancel);
                    attributeTags.Add(esriGeometryType.esriGeometryPoint, new List<string>());
                    attributeTags.Add(esriGeometryType.esriGeometryPolyline, new List<string>());
                    attributeTags.Add(esriGeometryType.esriGeometryPolygon, new List<string>());
                }

                if (nodeCapacity == 0 && wayCapacity == 0 && relationCapacity == 0)
                {
                    return;
                }

                if (conserveMemoryGPValue.Value == false)
                {
                    osmNodeDictionary = new Dictionary<string, OSMToolHelper.simplePointRef>(Convert.ToInt32(nodeCapacity));
                }

                message.AddMessage(String.Format(resourceManager.GetString("GPTools_OSMGPFileReader_countedElements"), nodeCapacity, wayCapacity, relationCapacity));

                // prepare the feature dataset and classes
                IGPParameter targetDatasetParameter = paramvalues.get_Element(out_targetDatasetNumber) as IGPParameter;
                IGPValue targetDatasetGPValue = gpUtilities3.UnpackGPValue(targetDatasetParameter);
                IDEDataset2 targetDEDataset2 = targetDatasetGPValue as IDEDataset2;

                if (targetDEDataset2 == null)
                {
                    message.AddError(120048, string.Format(resourceManager.GetString("GPTools_NullPointerParameterType"), targetDatasetParameter.Name));
                    return;
                }

                string targetDatasetName = ((IGPValue)targetDEDataset2).GetAsText();

                IDataElement targetDataElement = targetDEDataset2 as IDataElement;
                IDataset targetDataset = gpUtilities3.OpenDatasetFromLocation(targetDataElement.CatalogPath);

                IName parentName = null;

                try
                {
                    parentName = gpUtilities3.CreateParentFromCatalogPath(targetDataElement.CatalogPath);
                }
                catch 
                {
                    message.AddError(120033, resourceManager.GetString("GPTools_OSMGPFileReader_unable_to_create_fd"));
                    return;
                }


                // test if the feature classes already exists, 
                // if they do and the environments settings are such that an overwrite is not allowed we need to abort at this point
                IGeoProcessorSettings gpSettings = (IGeoProcessorSettings)envMgr;
                if (gpSettings.OverwriteOutput == true)
                {
                }
                else
                {
                    if (gpUtilities3.Exists((IGPValue)targetDEDataset2) == true)
                    {
                        message.AddError(120032, String.Format(resourceManager.GetString("GPTools_OSMGPFileReader_basenamealreadyexists"), targetDataElement.Name));
                        return;
                    }
                }

                // load the descriptions from which to derive the domain values
                OSMDomains availableDomains = null;

                // Reading the XML document requires a FileStream.
                System.Xml.XmlTextReader reader = null;
                string xmlDomainFile = "";
                m_editorConfigurationSettings.TryGetValue("osmdomainsfilepath", out xmlDomainFile);

                if (System.IO.File.Exists(xmlDomainFile))
                {
                    reader = new System.Xml.XmlTextReader(xmlDomainFile);
                }

                if (reader == null)
                {
                    message.AddError(120033, resourceManager.GetString("GPTools_OSMGPDownload_NoDomainConfigFile"));
                    return;
                }

                System.Xml.Serialization.XmlSerializer domainSerializer = null;

                try
                {
                    domainSerializer = new XmlSerializer(typeof(OSMDomains));
                    availableDomains = domainSerializer.Deserialize(reader) as OSMDomains;
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    System.Diagnostics.Debug.WriteLine(ex.StackTrace);
                    message.AddError(120034, ex.Message);
                    return;
                }
                reader.Close();

                message.AddMessage(resourceManager.GetString("GPTools_preparedb"));

                Dictionary<string, IDomain> codedValueDomains = new Dictionary<string, IDomain>();

                foreach (var domain in availableDomains.domain)
                {
                    ICodedValueDomain pointCodedValueDomain = new CodedValueDomainClass();
                    ((IDomain)pointCodedValueDomain).Name = domain.name + "_pt";
                    ((IDomain)pointCodedValueDomain).FieldType = esriFieldType.esriFieldTypeString;

                    ICodedValueDomain lineCodedValueDomain = new CodedValueDomainClass();
                    ((IDomain)lineCodedValueDomain).Name = domain.name + "_ln";
                    ((IDomain)lineCodedValueDomain).FieldType = esriFieldType.esriFieldTypeString;

                    ICodedValueDomain polygonCodedValueDomain = new CodedValueDomainClass();
                    ((IDomain)polygonCodedValueDomain).Name = domain.name + "_ply";
                    ((IDomain)polygonCodedValueDomain).FieldType = esriFieldType.esriFieldTypeString;

                    for (int i = 0; i < domain.domainvalue.Length; i++)
                    {
                        for (int domainGeometryIndex = 0; domainGeometryIndex < domain.domainvalue[i].geometrytype.Length; domainGeometryIndex++)
                        {
                            switch (domain.domainvalue[i].geometrytype[domainGeometryIndex])
                            {
                                case geometrytype.point:
                                    pointCodedValueDomain.AddCode(domain.domainvalue[i].value, domain.domainvalue[i].value);
                                    break;
                                case geometrytype.line:
                                    lineCodedValueDomain.AddCode(domain.domainvalue[i].value, domain.domainvalue[i].value);
                                    break;
                                case geometrytype.polygon:
                                    polygonCodedValueDomain.AddCode(domain.domainvalue[i].value, domain.domainvalue[i].value);
                                    break;
                                default:
                                    break;
                            }
                        }
                    }

                    // add the domain tables to the domains collection
                    codedValueDomains.Add(((IDomain)pointCodedValueDomain).Name, (IDomain)pointCodedValueDomain);
                    codedValueDomains.Add(((IDomain)lineCodedValueDomain).Name, (IDomain)lineCodedValueDomain);
                    codedValueDomains.Add(((IDomain)polygonCodedValueDomain).Name, (IDomain)polygonCodedValueDomain);
                }

                IWorkspaceDomains workspaceDomain = null;
                IFeatureWorkspace featureWorkspace = null;
                // if the target dataset already exists we can go ahead and QI to it directly
                if (targetDataset != null)
                {
                    workspaceDomain = targetDataset.Workspace as IWorkspaceDomains;
                    featureWorkspace = targetDataset.Workspace as IFeatureWorkspace;
                }
                else
                {
                    // in case it doesn't exist yet we will open the parent (the workspace - geodatabase- itself) and 
                    // use it as a reference to create the feature dataset and the feature classes in it.
                    IWorkspace newWorkspace = ((IName)parentName).Open() as IWorkspace;
                    workspaceDomain = newWorkspace as IWorkspaceDomains;
                    featureWorkspace = newWorkspace as IFeatureWorkspace;
                }

                foreach (var domain in codedValueDomains.Values)
                {
                    IDomain testDomain = null;
                    try
                    {
                        testDomain = workspaceDomain.get_DomainByName(domain.Name);
                    }
                    catch { }

                    if (testDomain == null)
                    {
                        workspaceDomain.AddDomain(domain);
                    }
                }

                // this determines the spatial reference as defined from the gp environment settings and the initial wgs84 SR
                ISpatialReferenceFactory spatialReferenceFactory = new SpatialReferenceEnvironmentClass() as ISpatialReferenceFactory;
                ISpatialReference wgs84 = spatialReferenceFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984) as ISpatialReference;

                ISpatialReference downloadSpatialReference = gpUtilities3.GetGPSpRefEnv(envMgr, wgs84, null, 0, 0, 0, 0, null);

                Marshal.ReleaseComObject(wgs84);
                Marshal.ReleaseComObject(spatialReferenceFactory);

                IGPEnvironment configKeyword = OSMGPDownload.getEnvironment(envMgr, "configKeyword");
                IGPString gpString = configKeyword.Value as IGPString;

                string storageKeyword = String.Empty;

                if (gpString != null)
                {
                    storageKeyword = gpString.Value;
                }

                IFeatureDataset targetFeatureDataset = null;
                if (gpUtilities3.Exists((IGPValue)targetDEDataset2))
                {
                    targetFeatureDataset = gpUtilities3.OpenDataset((IGPValue)targetDEDataset2) as IFeatureDataset;
                }
                else
                {
                    targetFeatureDataset = featureWorkspace.CreateFeatureDataset(targetDataElement.Name, downloadSpatialReference);
                }


                downloadSpatialReference = ((IGeoDataset)targetFeatureDataset).SpatialReference;

                string metadataAbstract = resourceManager.GetString("GPTools_OSMGPFileReader_metadata_abstract");
                string metadataPurpose = resourceManager.GetString("GPTools_OSMGPFileReader_metadata_purpose");

                // assign the custom class extension for use with the OSM feature inspector
                UID osmClassUID = new UIDClass();
                osmClassUID.Value = "{65CA4847-8661-45eb-8E1E-B2985CA17C78}";

                // points
                try
                {
                    osmPointFeatureClass = osmToolHelper.CreatePointFeatureClass((IWorkspace2)featureWorkspace, targetFeatureDataset, targetDataElement.Name + "_osm_pt", null, null, null, storageKeyword, availableDomains, metadataAbstract, metadataPurpose, attributeTags[esriGeometryType.esriGeometryPoint]);
                }
                catch (Exception ex)
                {
                    message.AddError(120035, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nullpointfeatureclass"), ex.Message));
                    return;
                }

                if (osmPointFeatureClass == null)
                {
                    return;
                }

                // change the property set of the osm class extension to skip any change detection during the initial data load
                osmPointFeatureClass.RemoveOSMClassExtension();

                int osmPointIDFieldIndex = osmPointFeatureClass.FindField("OSMID");
                Dictionary<string, int> osmPointDomainAttributeFieldIndices = new Dictionary<string, int>();
                foreach (var domains in availableDomains.domain)
                {
                    int currentFieldIndex = osmPointFeatureClass.FindField(domains.name);

                    if (currentFieldIndex != -1)
                    {
                        osmPointDomainAttributeFieldIndices.Add(domains.name, currentFieldIndex);
                    }
                }
                int tagCollectionPointFieldIndex = osmPointFeatureClass.FindField("osmTags");
                int osmUserPointFieldIndex = osmPointFeatureClass.FindField("osmuser");
                int osmUIDPointFieldIndex = osmPointFeatureClass.FindField("osmuid");
                int osmVisiblePointFieldIndex = osmPointFeatureClass.FindField("osmvisible");
                int osmVersionPointFieldIndex = osmPointFeatureClass.FindField("osmversion");
                int osmChangesetPointFieldIndex = osmPointFeatureClass.FindField("osmchangeset");
                int osmTimeStampPointFieldIndex = osmPointFeatureClass.FindField("osmtimestamp");
                int osmMemberOfPointFieldIndex = osmPointFeatureClass.FindField("osmMemberOf");
                int osmSupportingElementPointFieldIndex = osmPointFeatureClass.FindField("osmSupportingElement");
                int osmWayRefCountFieldIndex = osmPointFeatureClass.FindField("wayRefCount");


                // lines
                try
                {
                    osmLineFeatureClass = osmToolHelper.CreateLineFeatureClass((IWorkspace2)featureWorkspace, targetFeatureDataset, targetDataElement.Name + "_osm_ln", null, null, null, storageKeyword, availableDomains, metadataAbstract, metadataPurpose, attributeTags[esriGeometryType.esriGeometryPolyline]);
                }
                catch (Exception ex)
                {
                    message.AddError(120036, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nulllinefeatureclass"), ex.Message));
                    return;
                }

                if (osmLineFeatureClass == null)
                {
                    return;
                }

                // change the property set of the osm class extension to skip any change detection during the initial data load
                osmLineFeatureClass.RemoveOSMClassExtension();

                int osmLineIDFieldIndex = osmLineFeatureClass.FindField("OSMID");
                Dictionary<string, int> osmLineDomainAttributeFieldIndices = new Dictionary<string, int>();
                foreach (var domains in availableDomains.domain)
                {
                    int currentFieldIndex = osmLineFeatureClass.FindField(domains.name);

                    if (currentFieldIndex != -1)
                    {
                        osmLineDomainAttributeFieldIndices.Add(domains.name, currentFieldIndex);
                    }
                }
                int tagCollectionPolylineFieldIndex = osmLineFeatureClass.FindField("osmTags");
                int osmUserPolylineFieldIndex = osmLineFeatureClass.FindField("osmuser");
                int osmUIDPolylineFieldIndex = osmLineFeatureClass.FindField("osmuid");
                int osmVisiblePolylineFieldIndex = osmLineFeatureClass.FindField("osmvisible");
                int osmVersionPolylineFieldIndex = osmLineFeatureClass.FindField("osmversion");
                int osmChangesetPolylineFieldIndex = osmLineFeatureClass.FindField("osmchangeset");
                int osmTimeStampPolylineFieldIndex = osmLineFeatureClass.FindField("osmtimestamp");
                int osmMemberOfPolylineFieldIndex = osmLineFeatureClass.FindField("osmMemberOf");
                int osmMembersPolylineFieldIndex = osmLineFeatureClass.FindField("osmMembers");
                int osmSupportingElementPolylineFieldIndex = osmLineFeatureClass.FindField("osmSupportingElement");


                // polygons
                try
                {
                    osmPolygonFeatureClass = osmToolHelper.CreatePolygonFeatureClass((IWorkspace2)featureWorkspace, targetFeatureDataset, targetDataElement.Name + "_osm_ply", null, null, null, storageKeyword, availableDomains, metadataAbstract, metadataPurpose, attributeTags[esriGeometryType.esriGeometryPolygon]);
                }
                catch (Exception ex)
                {
                    message.AddError(120037, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nullpolygonfeatureclass"), ex.Message));
                    return;
                }

                if (osmPolygonFeatureClass == null)
                {
                    return;
                }

                // change the property set of the osm class extension to skip any change detection during the initial data load
                osmPolygonFeatureClass.RemoveOSMClassExtension();

                int osmPolygonIDFieldIndex = osmPolygonFeatureClass.FindField("OSMID");
                Dictionary<string, int> osmPolygonDomainAttributeFieldIndices = new Dictionary<string, int>();
                foreach (var domains in availableDomains.domain)
                {
                    int currentFieldIndex = osmPolygonFeatureClass.FindField(domains.name);

                    if (currentFieldIndex != -1)
                    {
                        osmPolygonDomainAttributeFieldIndices.Add(domains.name, currentFieldIndex);
                    }
                }
                int tagCollectionPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmTags");
                int osmUserPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmuser");
                int osmUIDPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmuid");
                int osmVisiblePolygonFieldIndex = osmPolygonFeatureClass.FindField("osmvisible");
                int osmVersionPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmversion");
                int osmChangesetPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmchangeset");
                int osmTimeStampPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmtimestamp");
                int osmMemberOfPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmMemberOf");
                int osmMembersPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmMembers");
                int osmSupportingElementPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmSupportingElement");


                // relation table
                ITable relationTable = null;

                try
                {
                    relationTable = osmToolHelper.CreateRelationTable((IWorkspace2)featureWorkspace, targetDataElement.Name + "_osm_relation", null, storageKeyword, metadataAbstract, metadataPurpose);
                }
                catch (Exception ex)
                {
                    message.AddError(120038, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nullrelationtable"), ex.Message));
                    return;
                }

                if (relationTable == null)
                {
                    return;
                }

                int osmRelationIDFieldIndex = relationTable.FindField("OSMID");
                int tagCollectionRelationFieldIndex = relationTable.FindField("osmTags");
                int osmUserRelationFieldIndex = relationTable.FindField("osmuser");
                int osmUIDRelationFieldIndex = relationTable.FindField("osmuid");
                int osmVisibleRelationFieldIndex = relationTable.FindField("osmvisible");
                int osmVersionRelationFieldIndex = relationTable.FindField("osmversion");
                int osmChangesetRelationFieldIndex = relationTable.FindField("osmchangeset");
                int osmTimeStampRelationFieldIndex = relationTable.FindField("osmtimestamp");
                int osmMemberOfRelationFieldIndex = relationTable.FindField("osmMemberOf");
                int osmMembersRelationFieldIndex = relationTable.FindField("osmMembers");
                int osmSupportingElementRelationFieldIndex = relationTable.FindField("osmSupportingElement");

                // revision table 
                ITable revisionTable = null;

                try
                {
                    revisionTable = osmToolHelper.CreateRevisionTable((IWorkspace2)featureWorkspace, targetDataElement.Name + "_osm_revision", null, storageKeyword);
                }
                catch (Exception ex)
                {
                    message.AddError(120039, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nullrevisiontable"), ex.Message));
                    return;
                }

                if (revisionTable == null)
                {
                    return;
                }


                #region clean any existing data from loading targets
                ESRI.ArcGIS.Geoprocessing.IGeoProcessor2 gp = new ESRI.ArcGIS.Geoprocessing.GeoProcessorClass();
                IGeoProcessorResult gpResult = new GeoProcessorResultClass();

                try
                {
                    IVariantArray truncateParameters = new VarArrayClass();
                    truncateParameters.Add(((IWorkspace)featureWorkspace).PathName + "\\" + targetDataElement.Name + "\\" + targetDataElement.Name + "_osm_pt");
                    gpResult = gp.Execute("TruncateTable_management", truncateParameters, TrackCancel);

                    truncateParameters = new VarArrayClass();
                    truncateParameters.Add(((IWorkspace)featureWorkspace).PathName + "\\" + targetDataElement.Name + "\\" + targetDataElement.Name + "_osm_ln");
                    gpResult = gp.Execute("TruncateTable_management", truncateParameters, TrackCancel);

                    truncateParameters = new VarArrayClass();
                    truncateParameters.Add(((IWorkspace)featureWorkspace).PathName + "\\" + targetDataElement.Name + "\\" + targetDataElement.Name + "_osm_ply");
                    gpResult = gp.Execute("TruncateTable_management", truncateParameters, TrackCancel);

                    truncateParameters = new VarArrayClass();
                    truncateParameters.Add(((IWorkspace)featureWorkspace).PathName + "\\" + targetDataElement.Name + "_osm_relation");
                    gpResult = gp.Execute("TruncateTable_management", truncateParameters, TrackCancel);

                    truncateParameters = new VarArrayClass();
                    truncateParameters.Add(((IWorkspace)featureWorkspace).PathName + "\\" + targetDataElement.Name + "_osm_revision");
                    gpResult = gp.Execute("TruncateTable_management", truncateParameters, TrackCancel);
                }
                catch (Exception ex)
                {
                    message.AddWarning(ex.Message);
                }
                #endregion

                bool fastLoad = false;

                //// check for user interruption
                //if (TrackCancel.Continue() == false)
                //{
                //    message.AddAbort(resourceManager.GetString("GPTools_toolabort"));
                //    return;
                //}

                //IFeatureCursor deleteCursor = null;
                //using (ComReleaser comReleaser = new ComReleaser())
                //{
                //    // let's make sure that we clean out any old data that might have existed in the feature classes
                //    deleteCursor = osmPointFeatureClass.Update(null, false);
                //    comReleaser.ManageLifetime(deleteCursor);

                //    for (IFeature feature = deleteCursor.NextFeature(); feature != null; feature = deleteCursor.NextFeature())
                //    {
                //        feature.Delete();

                //        // check for user interruption
                //        if (TrackCancel.Continue() == false)
                //        {
                //            message.AddAbort(resourceManager.GetString("GPTools_toolabort"));
                //            return;
                //        }

                //    }
                //}

                //using (ComReleaser comReleaser = new ComReleaser())
                //{
                //    deleteCursor = osmLineFeatureClass.Update(null, false);
                //    comReleaser.ManageLifetime(deleteCursor);

                //    for (IFeature feature = deleteCursor.NextFeature(); feature != null; feature = deleteCursor.NextFeature())
                //    {
                //        feature.Delete();

                //        // check for user interruption
                //        if (TrackCancel.Continue() == false)
                //        {
                //            message.AddAbort(resourceManager.GetString("GPTools_toolabort"));
                //            return;
                //        }
                //    }
                //}

                //using (ComReleaser comReleaser = new ComReleaser())
                //{
                //    deleteCursor = osmPolygonFeatureClass.Update(null, false);
                //    comReleaser.ManageLifetime(deleteCursor);

                //    for (IFeature feature = deleteCursor.NextFeature(); feature != null; feature = deleteCursor.NextFeature())
                //    {
                //        feature.Delete();

                //        // check for user interruption
                //        if (TrackCancel.Continue() == false)
                //        {
                //            message.AddAbort(resourceManager.GetString("GPTools_toolabort"));
                //            return;
                //        }
                //    }
                //}

                //ICursor tableCursor = null;
                //using (ComReleaser comReleaser = new ComReleaser())
                //{
                //    tableCursor = relationTable.Update(null, false);
                //    comReleaser.ManageLifetime(tableCursor);

                //    for (IRow row = tableCursor.NextRow(); row != null; row = tableCursor.NextRow())
                //    {
                //        row.Delete();

                //        // check for user interruption
                //        if (TrackCancel.Continue() == false)
                //        {
                //            message.AddAbort(resourceManager.GetString("GPTools_toolabort"));
                //            return;
                //        }
                //    }
                //}

                //using (ComReleaser comReleaser = new ComReleaser())
                //{
                //    tableCursor = revisionTable.Update(null, false);
                //    comReleaser.ManageLifetime(tableCursor);

                //    for (IRow row = tableCursor.NextRow(); row != null; row = tableCursor.NextRow())
                //    {
                //        row.Delete();

                //        // check for user interruption
                //        if (TrackCancel.Continue() == false)
                //        {
                //            message.AddAbort(resourceManager.GetString("GPTools_toolabort"));
                //            return;
                //        }
                //    }
                //}

                // define variables helping to invoke core tools for data management
                IGeoProcessorResult2 gpResults2 = null;

                IGeoProcessor2 geoProcessor = new GeoProcessorClass();

                #region load points
                osmToolHelper.loadOSMNodes(osmFileLocationString.GetAsText(), ref TrackCancel, ref message, targetDatasetGPValue, osmPointFeatureClass, conserveMemoryGPValue.Value, fastLoad, Convert.ToInt32(nodeCapacity), ref osmNodeDictionary, featureWorkspace, downloadSpatialReference, availableDomains, false);
                #endregion


                if (TrackCancel.Continue() == false)
                {
                    return;
                }

                #region load ways
                List<string> missingWays = osmToolHelper.loadOSMWays(osmFileLocationString.GetAsText(), ref TrackCancel, ref message, targetDatasetGPValue, osmPointFeatureClass, osmLineFeatureClass, osmPolygonFeatureClass, conserveMemoryGPValue.Value, fastLoad, Convert.ToInt32(wayCapacity), ref osmNodeDictionary, featureWorkspace, downloadSpatialReference, availableDomains, false);
                #endregion

                if (downloadSpatialReference != null)
                    Marshal.ReleaseComObject(downloadSpatialReference);

                #region for local geodatabases enforce spatial integrity

                bool storedOriginalLocal = geoProcessor.AddOutputsToMap;
                geoProcessor.AddOutputsToMap = false;

                if (osmLineFeatureClass != null)
                {
                    if (((IDataset)osmLineFeatureClass).Workspace.Type == esriWorkspaceType.esriLocalDatabaseWorkspace)
                    {
                        gpUtilities3 = new GPUtilitiesClass() as IGPUtilities3;

                        IGPParameter outLinesParameter = paramvalues.get_Element(out_osmLinesNumber) as IGPParameter;
                        IGPValue lineFeatureClass = gpUtilities3.UnpackGPValue(outLinesParameter);

                        DataManagementTools.RepairGeometry repairlineGeometry = new DataManagementTools.RepairGeometry(osmLineFeatureClass);

                        IVariantArray repairGeometryParameterArray = new VarArrayClass();
                        repairGeometryParameterArray.Add(lineFeatureClass.GetAsText());
                        repairGeometryParameterArray.Add("DELETE_NULL");

                        gpResults2 = geoProcessor.Execute(repairlineGeometry.ToolName, repairGeometryParameterArray, TrackCancel) as IGeoProcessorResult2;
                        message.AddMessages(gpResults2.GetResultMessages());

                        ComReleaser.ReleaseCOMObject(gpUtilities3);
                    }
                }

                if (osmPolygonFeatureClass != null)
                {
                    if (((IDataset)osmPolygonFeatureClass).Workspace.Type == esriWorkspaceType.esriLocalDatabaseWorkspace)
                    {
                        gpUtilities3 = new GPUtilitiesClass() as IGPUtilities3;

                        IGPParameter outPolygonParameter = paramvalues.get_Element(out_osmPolygonsNumber) as IGPParameter;
                        IGPValue polygonFeatureClass = gpUtilities3.UnpackGPValue(outPolygonParameter);

                        DataManagementTools.RepairGeometry repairpolygonGeometry = new DataManagementTools.RepairGeometry(osmPolygonFeatureClass);

                        IVariantArray repairGeometryParameterArray = new VarArrayClass();
                        repairGeometryParameterArray.Add(polygonFeatureClass.GetAsText());
                        repairGeometryParameterArray.Add("DELETE_NULL");

                        gpResults2 = geoProcessor.Execute(repairpolygonGeometry.ToolName, repairGeometryParameterArray, TrackCancel) as IGeoProcessorResult2;
                        message.AddMessages(gpResults2.GetResultMessages());

                        ComReleaser.ReleaseCOMObject(gpUtilities3);
                    }
                }

                geoProcessor.AddOutputsToMap = storedOriginalLocal;

                #endregion


                if (TrackCancel.Continue() == false)
                {
                    return;
                }

                #region load relations
                List<string> missingRelations = osmToolHelper.loadOSMRelations(osmFileLocationString.GetAsText(), ref TrackCancel, ref message, targetDatasetGPValue, osmPointFeatureClass, osmLineFeatureClass, osmPolygonFeatureClass, Convert.ToInt32(relationCapacity), relationTable, availableDomains, fastLoad, false);
                #endregion

                // check for user interruption
                if (TrackCancel.Continue() == false)
                {
                    return;
                }

                //storedOriginalLocal = geoProcessor.AddOutputsToMap;
                //try
                //{
                //    geoProcessor.AddOutputsToMap = false;

                //    // add indexes for revisions
                //    //IGPValue revisionTableGPValue = gpUtilities3.MakeGPValueFromObject(revisionTable);
                //    string revisionTableString = targetDatasetGPValue.GetAsText() + System.IO.Path.DirectorySeparatorChar + ((IDataset)revisionTable).BrowseName;
                //    IVariantArray parameterArrary2 = osmToolHelper.CreateAddIndexParameterArray(revisionTableString, "osmoldid;osmnewid", "osmID_IDX", "", "");
                //    gpResults2 = geoProcessor.Execute("AddIndex_management", parameterArrary2, TrackCancel) as IGeoProcessorResult2;

                //    message.AddMessages(gpResults2.GetResultMessages());
                //}
                //catch (Exception ex)
                //{
                //    message.AddWarning(ex.Message);
                //}
                //finally
                //{
                //    geoProcessor.AddOutputsToMap = storedOriginalLocal;
                //}


                #region update the references counts and member lists for nodes

                message.AddMessage(resourceManager.GetString("GPTools_OSMGPFileReader_updatereferences"));
                IFeatureCursor pointUpdateCursor = null;

                IQueryFilter pointQueryFilter = new QueryFilterClass();

                // adjust of number of all other reference counter from 0 to 1
                if (conserveMemoryGPValue.Value == true)
                {
                    pointQueryFilter.WhereClause = osmPointFeatureClass.SqlIdentifier("wayRefCount") + " = 0";
                    pointQueryFilter.SubFields = osmPointFeatureClass.OIDFieldName + ",wayRefCount";
                }

                using (SchemaLockManager ptLockManager = new SchemaLockManager(osmPointFeatureClass as ITable))
                {
                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        int updateCount = 0;
                        if (conserveMemoryGPValue.Value == true)
                        {
                            pointUpdateCursor = osmPointFeatureClass.Update(pointQueryFilter, false);
                            updateCount = ((ITable)osmPointFeatureClass).RowCount(pointQueryFilter);
                        }
                        else
                        {
                            pointUpdateCursor = osmPointFeatureClass.Update(null, false);
                            updateCount = ((ITable)osmPointFeatureClass).RowCount(null);
                        }

                        IStepProgressor stepProgressor = TrackCancel as IStepProgressor;

                        if (stepProgressor != null)
                        {
                            stepProgressor.MinRange = 0;
                            stepProgressor.MaxRange = updateCount;
                            stepProgressor.Position = 0;
                            stepProgressor.Message = resourceManager.GetString("GPTools_OSMGPFileReader_updatepointrefcount");
                            stepProgressor.StepValue = 1;
                            stepProgressor.Show();
                        }

                        comReleaser.ManageLifetime(pointUpdateCursor);

                        IFeature pointFeature = pointUpdateCursor.NextFeature();

                        int positionCounter = 0;
                        while (pointFeature != null)
                        {
                            positionCounter++;
                            string nodeID = Convert.ToString(pointFeature.get_Value(osmPointIDFieldIndex));

                            if (conserveMemoryGPValue.Value == false)
                            {
                                // let get the reference counter from the internal node dictionary
                                if (osmNodeDictionary[nodeID].RefCounter == 0)
                                {
                                    pointFeature.set_Value(osmWayRefCountFieldIndex, 1);
                                }
                                else
                                {
                                    pointFeature.set_Value(osmWayRefCountFieldIndex, osmNodeDictionary[nodeID].RefCounter);
                                }
                            }
                            else
                            {
                                // in the case of memory conservation let's go change the 0s to 1s
                                pointFeature.set_Value(osmWayRefCountFieldIndex, 1);
                            }

                            pointUpdateCursor.UpdateFeature(pointFeature);

                            if (pointFeature != null)
                                Marshal.ReleaseComObject(pointFeature);

                            pointFeature = pointUpdateCursor.NextFeature();

                            if (stepProgressor != null)
                            {
                                stepProgressor.Position = positionCounter;
                            }
                        }

                        if (stepProgressor != null)
                        {
                            stepProgressor.Hide();
                        }

                        Marshal.ReleaseComObject(pointQueryFilter);
                    }
                }

                #endregion

                if (osmNodeDictionary != null)
                {
                    // clear outstanding resources potentially holding points
                    osmNodeDictionary = null;
                    System.GC.Collect(2, GCCollectionMode.Forced);
                }

                if (missingRelations.Count > 0)
                {
                    missingRelations.Clear();
                    missingRelations = null;
                }

                if (missingWays.Count > 0)
                {
                    missingWays.Clear();
                    missingWays = null;
                }

                SyncState.StoreLastSyncTime(targetDatasetName, syncTime);

                gpUtilities3 = new GPUtilitiesClass() as IGPUtilities3;

                // repackage the feature class into their respective gp values
                IGPParameter pointFeatureClassParameter = paramvalues.get_Element(out_osmPointsNumber) as IGPParameter;
                IGPValue pointFeatureClassGPValue = gpUtilities3.UnpackGPValue(pointFeatureClassParameter);
                gpUtilities3.PackGPValue(pointFeatureClassGPValue, pointFeatureClassParameter);

                IGPParameter lineFeatureClassParameter = paramvalues.get_Element(out_osmLinesNumber) as IGPParameter;
                IGPValue line1FeatureClassGPValue = gpUtilities3.UnpackGPValue(lineFeatureClassParameter);
                gpUtilities3.PackGPValue(line1FeatureClassGPValue, lineFeatureClassParameter);

                IGPParameter polygonFeatureClassParameter = paramvalues.get_Element(out_osmPolygonsNumber) as IGPParameter;
                IGPValue polygon1FeatureClassGPValue = gpUtilities3.UnpackGPValue(polygonFeatureClassParameter);
                gpUtilities3.PackGPValue(polygon1FeatureClassGPValue, polygonFeatureClassParameter);

                ComReleaser.ReleaseCOMObject(relationTable);
                ComReleaser.ReleaseCOMObject(revisionTable);

                ComReleaser.ReleaseCOMObject(targetFeatureDataset);
                ComReleaser.ReleaseCOMObject(featureWorkspace);

                ComReleaser.ReleaseCOMObject(osmFileLocationString);
                ComReleaser.ReleaseCOMObject(conserveMemoryGPValue);
                ComReleaser.ReleaseCOMObject(targetDataset);

                gpUtilities3.ReleaseInternals();
                ComReleaser.ReleaseCOMObject(gpUtilities3);
            }
            catch (Exception ex)
            {
                message.AddError(120055, ex.Message);
                message.AddError(120055, ex.StackTrace);
            }
            finally
            {
                try
                {
                    // TE -- 1/7/2015
                    // this is a 'breaking' change as the default loader won't no longer enable the edit extension
                    // the reasoning here is that most users would like the OSM in a 'read-only' fashion, and don't need to track 
                    // changes to be properly transmitted back to the OSM server
                    //if (osmPointFeatureClass != null)
                    //{
                    //    osmPointFeatureClass.ApplyOSMClassExtension();
                    //    ComReleaser.ReleaseCOMObject(osmPointFeatureClass);
                    //}

                    //if (osmLineFeatureClass != null)
                    //{
                    //    osmLineFeatureClass.ApplyOSMClassExtension();
                    //    ComReleaser.ReleaseCOMObject(osmLineFeatureClass);
                    //}

                    //if (osmPolygonFeatureClass != null)
                    //{
                    //    osmPolygonFeatureClass.ApplyOSMClassExtension();
                    //    ComReleaser.ReleaseCOMObject(osmPolygonFeatureClass);
                    //}

                    osmToolHelper = null;

                    System.GC.Collect();
                    System.GC.WaitForPendingFinalizers();
                }
                catch (Exception ex)
                {
                    message.AddError(120056, ex.ToString());
                }
            }
        }