private IEnumerable<OSMTurnInfo> EnumerateOsmTurnRestrictions(IFeatureWorkspace fws)
        {
            OSMUtility osmUtility = new OSMUtility();
            ITable tableRelation = fws.OpenTable(_osmDataset.Name + "_osm_relation");
            try
            {
                TaskManager.StartProgress(tableRelation.RowCount(null));

                using (ComReleaser cr = new ComReleaser())
                {
                    ICursor cursor = tableRelation.Search(null, false);
                    cr.ManageLifetime(cursor);

                    int idxTags = cursor.FindField("osmTags");
                    int idxMembers = cursor.FindField("osmMembers");

                    IRow row = null;
                    while ((row = cursor.NextRow()) != null)
                    {
                        tag[] tags = osmUtility.retrieveOSMTags(row, idxTags, _osmDataset.Workspace);
                        var tagsRestriction = tags.Where(t => t.k.Equals("restriction", StringComparison.CurrentCultureIgnoreCase));

                        foreach (tag tagRestrict in tagsRestriction)
                        {
                            OSMTurnInfo turn = new OSMTurnInfo();

                            turn.TurnType = tagRestrict.v;

                            foreach (member m in osmUtility.retrieveMembers(row, idxMembers))
                            {
                                if (m.role.Equals("from", StringComparison.CurrentCultureIgnoreCase))
                                    turn.From = m;
                                else if (m.role.Equals("to", StringComparison.CurrentCultureIgnoreCase))
                                    turn.To = m;
                                else if (m.role.Equals("via", StringComparison.CurrentCultureIgnoreCase))
                                    turn.Via = m;
                            }

                            if (turn.HasValidMembers())
                            {
                                turn.FromFeature = FindEdgeFeature(turn.From.@ref);
                                turn.ToFeature = FindEdgeFeature(turn.To.@ref);
                                turn.ViaFeature = FindJunctionFeature(turn.Via.@ref);

                                if (turn.HasValidFeatures())
                                    yield return turn;
                            }
                        }

                        TaskManager.StepProgress();
                    }
                }
            }
            finally
            {
                TaskManager.EndProgress();
            }
        }
        internal List<string> loadOSMRelations(string osmFileLocation, ref ITrackCancel TrackCancel, ref IGPMessages message, IGPValue targetGPValue, IFeatureClass osmPointFeatureClass, IFeatureClass osmLineFeatureClass, IFeatureClass osmPolygonFeatureClass, int relationCapacity, ITable relationTable, OSMDomains availableDomains, bool fastLoad, bool checkForExisting)
        {
            List<string> missingRelations = null;
            XmlReader osmFileXmlReader = null;
            XmlSerializer relationSerializer = null;

            try
            {

                missingRelations = new List<string>();

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

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

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

                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");

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

                    if (currentFieldIndex != -1)
                    {
                        osmLineDomainAttributeFieldIndices.Add(domains.name, currentFieldIndex);
                        osmLineDomainAttributeFieldLength.Add(domains.name, osmLineFeatureClass.Fields.get_Field(currentFieldIndex).Length);
                    }
                }
                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");

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

                    if (currentFieldIndex != -1)
                    {
                        osmPolygonDomainAttributeFieldIndices.Add(domains.name, currentFieldIndex);
                        osmPolygonDomainAttributeFieldLength.Add(domains.name, osmPolygonFeatureClass.Fields.get_Field(currentFieldIndex).Length);
                    }
                }
                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");

                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");

                // list for reference count and relation list for lines/polygons/relations
                // set up the progress indicator
                IStepProgressor stepProgressor = TrackCancel as IStepProgressor;

                if (stepProgressor != null)
                {
                    stepProgressor.MinRange = 0;
                    stepProgressor.MaxRange = relationCapacity;
                    stepProgressor.Position = 0;
                    stepProgressor.Message = _resourceManager.GetString("GPTools_OSMGPFileReader_loadingRelations");
                    stepProgressor.StepValue = 1;
                    stepProgressor.Show();
                }

                bool relationIndexRebuildRequired = false;

                if (relationTable != null)
                {
                    osmFileXmlReader = System.Xml.XmlReader.Create(osmFileLocation);
                    relationSerializer = new XmlSerializer(typeof(relation));

                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        using (SchemaLockManager linelock = new SchemaLockManager(osmLineFeatureClass as ITable), polygonLock = new SchemaLockManager(osmPolygonFeatureClass as ITable), relationLock = new SchemaLockManager(relationTable))
                        {
                            ICursor rowCursor = relationTable.Insert(true);
                            comReleaser.ManageLifetime(rowCursor);

                            IRowBuffer rowBuffer = relationTable.CreateRowBuffer();
                            comReleaser.ManageLifetime(rowBuffer);

                            IFeatureCursor lineFeatureInsertCursor = osmLineFeatureClass.Insert(true);
                            comReleaser.ManageLifetime(lineFeatureInsertCursor);

                            IFeatureBuffer lineFeatureBuffer = osmLineFeatureClass.CreateFeatureBuffer();
                            comReleaser.ManageLifetime(lineFeatureBuffer);

                            IFeatureCursor polygonFeatureInsertCursor = osmPolygonFeatureClass.Insert(true);
                            comReleaser.ManageLifetime(polygonFeatureInsertCursor);

                            IFeatureBuffer polygonFeatureBuffer = osmPolygonFeatureClass.CreateFeatureBuffer();
                            comReleaser.ManageLifetime(polygonFeatureBuffer);

                            int relationCount = 1;
                            int relationDebugCount = 1;

                            string lineSQLIdentifier = osmLineFeatureClass.SqlIdentifier("OSMID");
                            string polygonSQLIdentifier = osmPolygonFeatureClass.SqlIdentifier("OSMID");

                            message.AddMessage(_resourceManager.GetString("GPTools_OSMGPFileReader_resolvegeometries"));

                            osmFileXmlReader.MoveToContent();
                            while (osmFileXmlReader.Read())
                            {
                                if (osmFileXmlReader.IsStartElement())
                                {
                                    if (osmFileXmlReader.Name == "relation")
                                    {
                                        relation currentRelation = null;
                                        try
                                        {
                                            // read the full relation node
                                            string currentrelationString = osmFileXmlReader.ReadOuterXml();

                                            using (StringReader relationReader = new System.IO.StringReader(currentrelationString))
                                            {
                                                // de-serialize the xml into to the class instance
                                                currentRelation = relationSerializer.Deserialize(relationReader) as relation;
                                            }

                                            if (currentRelation == null)
                                                continue;

                                            relationDebugCount = relationDebugCount + 1;
                                            esriGeometryType detectedGeometryType = determineRelationGeometryType(osmLineFeatureClass, osmPolygonFeatureClass, relationTable, currentRelation);

                                            if (checkForExisting)
                                            {
                                                switch (detectedGeometryType)
                                                {
                                                    case esriGeometryType.esriGeometryAny:
                                                        if (CheckIfExists(relationTable, currentRelation.id))
                                                            continue;
                                                        break;
                                                    case esriGeometryType.esriGeometryBag:
                                                        if (CheckIfExists(relationTable, currentRelation.id))
                                                            continue;
                                                        break;
                                                    case esriGeometryType.esriGeometryBezier3Curve:
                                                        break;
                                                    case esriGeometryType.esriGeometryCircularArc:
                                                        break;
                                                    case esriGeometryType.esriGeometryEllipticArc:
                                                        break;
                                                    case esriGeometryType.esriGeometryEnvelope:
                                                        break;
                                                    case esriGeometryType.esriGeometryLine:
                                                        if (CheckIfExists(osmLineFeatureClass as ITable, currentRelation.id))
                                                            continue;
                                                        break;
                                                    case esriGeometryType.esriGeometryMultiPatch:
                                                        break;
                                                    case esriGeometryType.esriGeometryMultipoint:
                                                        break;
                                                    case esriGeometryType.esriGeometryNull:
                                                        if (CheckIfExists(relationTable, currentRelation.id))
                                                            continue;
                                                        break;
                                                    case esriGeometryType.esriGeometryPath:
                                                        break;
                                                    case esriGeometryType.esriGeometryPoint:
                                                        break;
                                                    case esriGeometryType.esriGeometryPolygon:
                                                        if (CheckIfExists(osmPolygonFeatureClass as ITable, currentRelation.id))
                                                            continue;
                                                        break;
                                                    case esriGeometryType.esriGeometryPolyline:
                                                        if (CheckIfExists(osmLineFeatureClass as ITable, currentRelation.id))
                                                            continue;
                                                        break;
                                                    case esriGeometryType.esriGeometryRay:
                                                        break;
                                                    case esriGeometryType.esriGeometryRing:
                                                        break;
                                                    case esriGeometryType.esriGeometrySphere:
                                                        break;
                                                    case esriGeometryType.esriGeometryTriangleFan:
                                                        break;
                                                    case esriGeometryType.esriGeometryTriangleStrip:
                                                        break;
                                                    case esriGeometryType.esriGeometryTriangles:
                                                        break;
                                                    default:
                                                        break;
                                                }
                                            }

                                            List<tag> relationTagList = new List<tag>();
                                            List<member> relationMemberList = new List<member>();
                                            Dictionary<string, string> wayList = new Dictionary<string, string>();

                                            // sanity check that the overall relation notation contains at least something
                                            if (currentRelation.Items == null)
                                                continue;

                                            List<OSMNodeFeature> osmPointList = null;
                                            List<OSMLineFeature> osmLineList = null;
                                            List<OSMPolygonFeature> osmPolygonList = null;
                                            List<OSMRelation> osmRelationList = null;

                                            rowBuffer = relationTable.CreateRowBuffer();
                                            comReleaser.ManageLifetime(rowBuffer);

                                            lineFeatureBuffer = osmLineFeatureClass.CreateFeatureBuffer();
                                            comReleaser.ManageLifetime(lineFeatureBuffer);

                                            polygonFeatureBuffer = osmPolygonFeatureClass.CreateFeatureBuffer();
                                            comReleaser.ManageLifetime(polygonFeatureBuffer);

                                            foreach (var item in currentRelation.Items)
                                            {
                                                if (item is member)
                                                {
                                                    member memberItem = item as member;
                                                    relationMemberList.Add(memberItem);

                                                    switch (memberItem.type)
                                                    {
                                                        case memberType.way:

                                                            if (!wayList.ContainsKey(memberItem.@ref))
                                                                wayList.Add(memberItem.@ref, memberItem.role);

                                                            if (IsThisWayALine(memberItem.@ref, osmLineFeatureClass, lineSQLIdentifier, osmPolygonFeatureClass, polygonSQLIdentifier))
                                                            {
                                                                if (osmLineList == null)
                                                                {
                                                                    osmLineList = new List<OSMLineFeature>();
                                                                }

                                                                OSMLineFeature lineFeature = new OSMLineFeature();
                                                                lineFeature.relationList = new List<string>();
                                                                lineFeature.lineID = memberItem.@ref;

                                                                if (detectedGeometryType == esriGeometryType.esriGeometryPolygon)
                                                                {
                                                                    lineFeature.relationList.Add(currentRelation.id + "_ply");
                                                                }
                                                                else if (detectedGeometryType == esriGeometryType.esriGeometryPolyline)
                                                                {
                                                                    lineFeature.relationList.Add(currentRelation.id + "_ln");
                                                                }
                                                                else
                                                                {
                                                                    lineFeature.relationList.Add(currentRelation.id + "_rel");
                                                                }

                                                                osmLineList.Add(lineFeature);
                                                            }
                                                            else
                                                            {
                                                                if (osmPolygonList == null)
                                                                {
                                                                    osmPolygonList = new List<OSMPolygonFeature>();
                                                                }

                                                                OSMPolygonFeature polygonFeature = new OSMPolygonFeature();
                                                                polygonFeature.relationList = new List<string>();
                                                                polygonFeature.polygonID = memberItem.@ref;

                                                                if (detectedGeometryType == esriGeometryType.esriGeometryPolygon)
                                                                {
                                                                    polygonFeature.relationList.Add(currentRelation.id + "_ply");
                                                                }
                                                                else if (detectedGeometryType == esriGeometryType.esriGeometryPolyline)
                                                                {
                                                                    polygonFeature.relationList.Add(currentRelation.id + "_ln");
                                                                }
                                                                else
                                                                {
                                                                    polygonFeature.relationList.Add(currentRelation.id + "_rel");
                                                                }

                                                                osmPolygonList.Add(polygonFeature);
                                                            }

                                                            break;
                                                        case memberType.node:

                                                            if (osmPointList == null)
                                                            {
                                                                osmPointList = new List<OSMNodeFeature>();
                                                            }

                                                            OSMNodeFeature nodeFeature = new OSMNodeFeature();
                                                            nodeFeature.relationList = new List<string>();
                                                            nodeFeature.nodeID = memberItem.@ref;

                                                            nodeFeature.relationList.Add(currentRelation.id + "_rel");

                                                            osmPointList.Add(nodeFeature);

                                                            break;
                                                        case memberType.relation:

                                                            if (osmRelationList == null)
                                                            {
                                                                osmRelationList = new List<OSMRelation>();
                                                            }

                                                            OSMRelation relation = new OSMRelation();
                                                            relation.relationList = new List<string>();
                                                            relation.relationID = memberItem.@ref;
                                                            relation.relationList.Add(currentRelation.id + "_rel");

                                                            break;
                                                        default:
                                                            break;
                                                    }

                                                }
                                                else if (item is tag)
                                                {
                                                    relationTagList.Add((tag)item);
                                                }
                                            }

                                            // if there is a defined geometry type use it to generate a multipart geometry
                                            if (detectedGeometryType == esriGeometryType.esriGeometryPolygon)
                                            {
                                                #region create multipart polygon geometry
                                                //IFeature mpFeature = osmPolygonFeatureClass.CreateFeature();

                                                IPolygon relationMPPolygon = new PolygonClass();
                                                relationMPPolygon.SpatialReference = ((IGeoDataset)osmPolygonFeatureClass).SpatialReference;

                                                ISegmentCollection relationPolygonGeometryCollection = relationMPPolygon as ISegmentCollection;

                                                IQueryFilter osmIDQueryFilter = new QueryFilterClass();
                                                string sqlPolyOSMID = osmPolygonFeatureClass.SqlIdentifier("OSMID");
                                                object missing = Type.Missing;
                                                bool relationComplete = true;

                                                // loop through the list of referenced ways that are listed in a relation
                                                // for each of the items we need to make a decision if they have merit to qualify as stand-alone features
                                                // due to the presence of meaningful attributes (tags)
                                                foreach (KeyValuePair<string, string> wayKey in wayList)
                                                {
                                                    if (relationComplete == false)
                                                        break;

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

                                                    osmIDQueryFilter.WhereClause = sqlPolyOSMID + " = '" + wayKey.Key + "'";

                                                    System.Diagnostics.Debug.WriteLine("Relation (Polygon) #: " + relationDebugCount + " :___: " + currentRelation.id + " :___: " + wayKey.Key);

                                                    using (ComReleaser relationComReleaser = new ComReleaser())
                                                    {
                                                        IFeatureCursor featureCursor = osmPolygonFeatureClass.Search(osmIDQueryFilter, false);
                                                        relationComReleaser.ManageLifetime(featureCursor);

                                                        IFeature partFeature = featureCursor.NextFeature();

                                                        // set the appropriate field attribute to become invisible as a standalone features
                                                        if (partFeature != null)
                                                        {
                                                            IGeometryCollection ringCollection = partFeature.Shape as IGeometryCollection;

                                                            // test for available content in the geometry collection
                                                            if (ringCollection.GeometryCount > 0)
                                                            {
                                                                // test if we dealing with a valid geometry
                                                                if (ringCollection.get_Geometry(0).IsEmpty == false)
                                                                {
                                                                    // add it to the new geometry and mark the added geometry as a supporting element
                                                                    relationPolygonGeometryCollection.AddSegmentCollection((ISegmentCollection)ringCollection.get_Geometry(0));

                                                                    if (osmSupportingElementPolygonFieldIndex > -1)
                                                                    {
                                                                        // if the member of a relation has the role of "inner" and it has tags, then let's keep it
                                                                        // as a standalone feature as well
                                                                        // the geometry is then a hole in the relation but due to the tags it also has merits to be
                                                                        // considered a stand-alone feature
                                                                        if (wayKey.Value.ToLower().Equals("inner"))
                                                                        {
                                                                            if (!_osmUtility.DoesHaveKeys(partFeature, tagCollectionPolygonFieldIndex, null))
                                                                            {
                                                                                partFeature.set_Value(osmSupportingElementPolygonFieldIndex, "yes");
                                                                            }
                                                                        }
                                                                        else
                                                                        {
                                                                            // relation member without an explicit role or the role of "outer" are turned into
                                                                            // supporting features if they don't have relevant attribute
                                                                            if (!_osmUtility.DoesHaveKeys(partFeature, tagCollectionPolylineFieldIndex, null))
                                                                            {
                                                                                partFeature.set_Value(osmSupportingElementPolygonFieldIndex, "yes");
                                                                            }
                                                                        }
                                                                    }

                                                                    partFeature.Store();
                                                                }
                                                            }
                                                        }
                                                        else
                                                        {
                                                            // it still can be a line geometry that will be pieced together into a polygon
                                                            IFeatureCursor lineFeatureCursor = osmLineFeatureClass.Search(osmIDQueryFilter, false);
                                                            relationComReleaser.ManageLifetime(lineFeatureCursor);

                                                            partFeature = lineFeatureCursor.NextFeature();

                                                            if (partFeature != null)
                                                            {
                                                                IGeometryCollection ringCollection = partFeature.Shape as IGeometryCollection;

                                                                // test for available content in the geometry collection
                                                                if (ringCollection.GeometryCount > 0)
                                                                {
                                                                    // test if we dealing with a valid geometry
                                                                    if (ringCollection.get_Geometry(0).IsEmpty == false)
                                                                    {
                                                                        // add it to the new geometry and mark the added geometry as a supporting element
                                                                        relationPolygonGeometryCollection.AddSegmentCollection((ISegmentCollection)ringCollection.get_Geometry(0));

                                                                        if (osmSupportingElementPolylineFieldIndex > -1)
                                                                        {
                                                                            // if the member of a relation has the role of "inner" and it has tags, then let's keep it
                                                                            // as a standalone feature as well
                                                                            // the geometry is then a hole in the relation but due to the tags it also has merits to be
                                                                            // considered a stand-alone feature
                                                                            if (wayKey.Value.ToLower().Equals("inner"))
                                                                            {
                                                                                if (!_osmUtility.DoesHaveKeys(partFeature, tagCollectionPolylineFieldIndex, null))
                                                                                {
                                                                                    partFeature.set_Value(osmSupportingElementPolylineFieldIndex, "yes");
                                                                                }
                                                                            }
                                                                            else
                                                                            {
                                                                                // relation member without an explicit role or the role of "outer" are turned into
                                                                                // supporting features if they don't have relevant attribute
                                                                                if (!_osmUtility.DoesHaveKeys(partFeature, tagCollectionPolylineFieldIndex, null))
                                                                                {
                                                                                    partFeature.set_Value(osmSupportingElementPolylineFieldIndex, "yes");
                                                                                }
                                                                            }
                                                                        }

                                                                        partFeature.Store();
                                                                    }
                                                                }
                                                            }
                                                            else
                                                            {
                                                                relationComplete = false;
                                                                continue;
                                                            }
                                                        }
                                                    }
                                                }

                                                // mark the relation as incomplete
                                                if (relationComplete == false)
                                                {
                                                    missingRelations.Add(currentRelation.id);
                                                    continue;
                                                }

                                                // transform the added collections for geometries into a topological correct geometry representation
                                                ((IPolygon4)relationMPPolygon).SimplifyEx(true, false, true);

                                                polygonFeatureBuffer.Shape = relationMPPolygon;

                                                if (_osmUtility.DoesHaveKeys(currentRelation))
                                                {
                                                }
                                                else
                                                {
                                                    relationTagList = MergeTagsFromOuterPolygonToRelation(currentRelation, osmPolygonFeatureClass);
                                                }

                                                insertTags(osmPolygonDomainAttributeFieldIndices, osmPolygonDomainAttributeFieldLength, tagCollectionPolygonFieldIndex, polygonFeatureBuffer, relationTagList.ToArray());

                                                if (fastLoad == false)
                                                {
                                                    if (osmMembersPolygonFieldIndex > -1)
                                                    {
                                                        _osmUtility.insertMembers(osmMembersPolygonFieldIndex, (IFeature)polygonFeatureBuffer, relationMemberList.ToArray());
                                                    }

                                                    // store the administrative attributes
                                                    // user, uid, version, changeset, timestamp, visible
                                                    if (osmUserPolygonFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.user))
                                                        {
                                                            polygonFeatureBuffer.set_Value(osmUserPolygonFieldIndex, currentRelation.user);
                                                        }
                                                    }

                                                    if (osmUIDPolygonFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.uid))
                                                        {
                                                            polygonFeatureBuffer.set_Value(osmUIDPolygonFieldIndex, Convert.ToInt32(currentRelation.uid));
                                                        }
                                                    }

                                                    if (osmVisiblePolygonFieldIndex != -1)
                                                    {
                                                        if (String.IsNullOrEmpty(currentRelation.visible) == false)
                                                        {
                                                            polygonFeatureBuffer.set_Value(osmVisiblePolygonFieldIndex, currentRelation.visible.ToString());
                                                        }
                                                        else
                                                        {
                                                            polygonFeatureBuffer.set_Value(osmVisiblePolygonFieldIndex, "unknown");
                                                        }
                                                    }

                                                    if (osmVersionPolygonFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.version))
                                                        {
                                                            polygonFeatureBuffer.set_Value(osmVersionPolygonFieldIndex, Convert.ToInt32(currentRelation.version));
                                                        }
                                                    }

                                                    if (osmChangesetPolygonFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.changeset))
                                                        {
                                                            polygonFeatureBuffer.set_Value(osmChangesetPolygonFieldIndex, Convert.ToInt32(currentRelation.changeset));
                                                        }
                                                    }

                                                    if (osmTimeStampPolygonFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.timestamp))
                                                        {
                                                            polygonFeatureBuffer.set_Value(osmTimeStampPolygonFieldIndex, Convert.ToDateTime(currentRelation.timestamp));
                                                        }
                                                    }

                                                    if (osmPolygonIDFieldIndex != -1)
                                                    {
                                                        polygonFeatureBuffer.set_Value(osmPolygonIDFieldIndex, currentRelation.id);
                                                    }

                                                    if (osmSupportingElementPolygonFieldIndex > -1)
                                                    {
                                                        polygonFeatureBuffer.set_Value(osmSupportingElementPolygonFieldIndex, "no");
                                                    }
                                                }

                                                try
                                                {
                                                    //mpFeature.Store();
                                                    polygonFeatureInsertCursor.InsertFeature(polygonFeatureBuffer);
                                                }
                                                catch (Exception ex)
                                                {
                                                    message.AddWarning(ex.Message);
                                                }
                                                #endregion
                                            }
                                            else if (detectedGeometryType == esriGeometryType.esriGeometryPolyline)
                                            {
                                                #region create multipart polyline geometry
                                                //IFeature mpFeature = osmLineFeatureClass.CreateFeature();

                                                IPolyline relationMPPolyline = new PolylineClass();
                                                relationMPPolyline.SpatialReference = ((IGeoDataset)osmLineFeatureClass).SpatialReference;

                                                IGeometryCollection relationPolylineGeometryCollection = relationMPPolyline as IGeometryCollection;

                                                IQueryFilter osmIDQueryFilter = new QueryFilterClass();
                                                object missing = Type.Missing;

                                                // loop through the
                                                foreach (KeyValuePair<string, string> wayKey in wayList)
                                                {
                                                    if (TrackCancel.Continue() == false)
                                                    {
                                                        return missingRelations;
                                                    }

                                                    osmIDQueryFilter.WhereClause = osmLineFeatureClass.WhereClauseByExtensionVersion(wayKey.Key, "OSMID", 2);

                                                    System.Diagnostics.Debug.WriteLine("Relation (Polyline) #: " + relationDebugCount + " :___: " + currentRelation.id + " :___: " + wayKey);

                                                    using (ComReleaser relationComReleaser = new ComReleaser())
                                                    {
                                                        IFeatureCursor featureCursor = osmLineFeatureClass.Search(osmIDQueryFilter, false);
                                                        relationComReleaser.ManageLifetime(featureCursor);

                                                        IFeature partFeature = featureCursor.NextFeature();

                                                        // set the appropriate field attribute to become invisible as a standalone features
                                                        if (partFeature != null)
                                                        {
                                                            if (partFeature.Shape.IsEmpty == false)
                                                            {
                                                                IGeometryCollection pathCollection = partFeature.Shape as IGeometryCollection;
                                                                relationPolylineGeometryCollection.AddGeometry(pathCollection.get_Geometry(0), ref missing, ref missing);

                                                                if (osmSupportingElementPolylineFieldIndex > -1)
                                                                {
                                                                    if (!_osmUtility.DoesHaveKeys(partFeature, tagCollectionPolylineFieldIndex, null))
                                                                    {
                                                                        partFeature.set_Value(osmSupportingElementPolylineFieldIndex, "yes");
                                                                    }
                                                                }

                                                                partFeature.Store();
                                                            }
                                                        }
                                                    }
                                                }

                                                lineFeatureBuffer.Shape = relationMPPolyline;

                                                insertTags(osmLineDomainAttributeFieldIndices, osmLineDomainAttributeFieldLength, tagCollectionPolylineFieldIndex, lineFeatureBuffer, relationTagList.ToArray());

                                                if (fastLoad == false)
                                                {
                                                    if (osmMembersPolylineFieldIndex > -1)
                                                    {
                                                        _osmUtility.insertMembers(osmMembersPolylineFieldIndex, (IFeature)lineFeatureBuffer, relationMemberList.ToArray());
                                                    }

                                                    // store the administrative attributes
                                                    // user, uid, version, changeset, timestamp, visible
                                                    if (osmUserPolylineFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.user))
                                                        {
                                                            lineFeatureBuffer.set_Value(osmUserPolylineFieldIndex, currentRelation.user);
                                                        }
                                                    }

                                                    if (osmUIDPolylineFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.uid))
                                                        {
                                                            lineFeatureBuffer.set_Value(osmUIDPolylineFieldIndex, Convert.ToInt32(currentRelation.uid));
                                                        }
                                                    }

                                                    if (osmVisiblePolylineFieldIndex != -1)
                                                    {
                                                        if (String.IsNullOrEmpty(currentRelation.visible) == false)
                                                        {
                                                            lineFeatureBuffer.set_Value(osmVisiblePolylineFieldIndex, currentRelation.visible.ToString());
                                                        }
                                                        else
                                                        {
                                                            lineFeatureBuffer.set_Value(osmVisiblePolylineFieldIndex, "unknown");
                                                        }
                                                    }

                                                    if (osmVersionPolylineFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.version))
                                                        {
                                                            lineFeatureBuffer.set_Value(osmVersionPolylineFieldIndex, Convert.ToInt32(currentRelation.version));
                                                        }
                                                    }

                                                    if (osmChangesetPolylineFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.changeset))
                                                        {
                                                            lineFeatureBuffer.set_Value(osmChangesetPolylineFieldIndex, Convert.ToInt32(currentRelation.changeset));
                                                        }
                                                    }

                                                    if (osmTimeStampPolylineFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.timestamp))
                                                        {
                                                            lineFeatureBuffer.set_Value(osmTimeStampPolylineFieldIndex, Convert.ToDateTime(currentRelation.timestamp));
                                                        }
                                                    }

                                                    if (osmLineIDFieldIndex != -1)
                                                    {
                                                        lineFeatureBuffer.set_Value(osmLineIDFieldIndex, currentRelation.id);
                                                    }

                                                    if (osmSupportingElementPolylineFieldIndex > -1)
                                                    {
                                                        lineFeatureBuffer.set_Value(osmSupportingElementPolylineFieldIndex, "no");
                                                    }
                                                }

                                                try
                                                {
                                                    lineFeatureInsertCursor.InsertFeature(lineFeatureBuffer);
                                                }
                                                catch (Exception ex)
                                                {
                                                    message.AddWarning(ex.Message);
                                                }
                                                #endregion

                                            }
                                            else if (detectedGeometryType == esriGeometryType.esriGeometryPoint)
                                            {
                                                System.Diagnostics.Debug.WriteLine("Relation #: " + relationDebugCount + " :____: POINT!!!");

                                                if (TrackCancel.Continue() == false)
                                                {
                                                    return missingRelations;
                                                }
                                            }
                                            else
                                            // otherwise it is relation that needs to be dealt with separately
                                            {
                                                if (TrackCancel.Continue() == false)
                                                {
                                                    return missingRelations;
                                                }

                                                System.Diagnostics.Debug.WriteLine("Relation #: " + relationDebugCount + " :____: Kept as relation");

                                                if (tagCollectionRelationFieldIndex != -1)
                                                {
                                                    _osmUtility.insertOSMTags(tagCollectionRelationFieldIndex, rowBuffer, relationTagList.ToArray());
                                                }

                                                if (fastLoad == false)
                                                {
                                                    if (osmMembersRelationFieldIndex != -1)
                                                    {
                                                        _osmUtility.insertMembers(osmMembersRelationFieldIndex, rowBuffer, relationMemberList.ToArray());
                                                    }

                                                    // store the administrative attributes
                                                    // user, uid, version, changeset, timestamp, visible
                                                    if (osmUserRelationFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.user))
                                                        {
                                                            rowBuffer.set_Value(osmUserRelationFieldIndex, currentRelation.user);
                                                        }
                                                    }

                                                    if (osmUIDRelationFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.uid))
                                                        {
                                                            rowBuffer.set_Value(osmUIDRelationFieldIndex, Convert.ToInt64(currentRelation.uid));
                                                        }
                                                    }

                                                    if (osmVisibleRelationFieldIndex != -1)
                                                    {
                                                        if (currentRelation.visible != null)
                                                        {
                                                            rowBuffer.set_Value(osmVisibleRelationFieldIndex, currentRelation.visible.ToString());
                                                        }
                                                    }

                                                    if (osmVersionRelationFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.version))
                                                        {
                                                            rowBuffer.set_Value(osmVersionRelationFieldIndex, Convert.ToInt32(currentRelation.version));
                                                        }
                                                    }

                                                    if (osmChangesetRelationFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.changeset))
                                                        {
                                                            rowBuffer.set_Value(osmChangesetRelationFieldIndex, Convert.ToInt32(currentRelation.changeset));
                                                        }
                                                    }

                                                    if (osmTimeStampRelationFieldIndex != -1)
                                                    {
                                                        if (!String.IsNullOrEmpty(currentRelation.timestamp))
                                                        {
                                                            try
                                                            {
                                                                rowBuffer.set_Value(osmTimeStampRelationFieldIndex, Convert.ToDateTime(currentRelation.timestamp));
                                                            }
                                                            catch (Exception ex)
                                                            {
                                                                message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_invalidTimeFormat"), ex.Message));
                                                            }
                                                        }
                                                    }

                                                    if (osmRelationIDFieldIndex != -1)
                                                    {
                                                        rowBuffer.set_Value(osmRelationIDFieldIndex, currentRelation.id);
                                                    }
                                                }

                                                try
                                                {
                                                    rowCursor.InsertRow(rowBuffer);
                                                    relationCount = relationCount + 1;

                                                    relationIndexRebuildRequired = true;
                                                }
                                                catch (Exception ex)
                                                {
                                                    System.Diagnostics.Debug.WriteLine(ex.Message);
                                                }

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

                                            // update the isMemberOf fields of the attached features
                                            if (osmPointList != null)
                                            {
                                                foreach (OSMNodeFeature nodeFeature in osmPointList)
                                                {
                                                    updateIsMemberOf(osmLineFeatureClass, osmMemberOfPolylineFieldIndex, nodeFeature.nodeID, nodeFeature.relationList);
                                                }
                                            }

                                            if (osmLineList != null)
                                            {
                                                foreach (OSMLineFeature lineFeature in osmLineList)
                                                {
                                                    updateIsMemberOf(osmLineFeatureClass, osmMemberOfPolylineFieldIndex, lineFeature.lineID, lineFeature.relationList);
                                                }
                                            }

                                            if (osmPolygonList != null)
                                            {
                                                foreach (OSMPolygonFeature polygonFeature in osmPolygonList)
                                                {
                                                    updateIsMemberOf(osmLineFeatureClass, osmMemberOfPolylineFieldIndex, polygonFeature.polygonID, polygonFeature.relationList);
                                                }
                                            }

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

                                            if ((relationCount % 50000) == 0)
                                            {
                                                message.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_relationsloaded"), relationCount));
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            message.AddWarning(ex.Message);
                                        }
                                        finally
                                        {
                                            if (rowBuffer != null)
                                            {
                                                Marshal.ReleaseComObject(rowBuffer);

                                                if (rowBuffer != null)
                                                    rowBuffer = null;
                                            }
                                            if (lineFeatureBuffer != null)
                                            {
                                                Marshal.ReleaseComObject(lineFeatureBuffer);

                                                if (lineFeatureBuffer != null)
                                                    lineFeatureBuffer = null;
                                            }

                                            if (polygonFeatureBuffer != null)
                                            {
                                                Marshal.ReleaseComObject(polygonFeatureBuffer);

                                                if (polygonFeatureBuffer != null)
                                                    polygonFeatureBuffer = null;
                                            }

                                            currentRelation = null;
                                        }
                                    }
                                }
                            }

                            // close the OSM file
                            osmFileXmlReader.Close();

                            // flush any remaining entities from the cursor
                            rowCursor.Flush();
                            polygonFeatureInsertCursor.Flush();
                            lineFeatureInsertCursor.Flush();

                            // force a garbage collection
                            System.GC.Collect();

                            // let the user know that we are done dealing with the relations
                            message.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_relationsloaded"), relationCount));
                        }
                    }

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

                    // Addd index for osmid column as well
                    IGeoProcessor2 geoProcessor = new GeoProcessorClass();
                    bool storedOriginalLocal = geoProcessor.AddOutputsToMap;
                    IGPUtilities3 gpUtilities3 = new GPUtilitiesClass();

                    try
                    {
                        geoProcessor.AddOutputsToMap = false;

                        if (relationIndexRebuildRequired)
                        {
                            IIndexes tableIndexes = relationTable.Indexes;
                            int indexPosition = -1;
                            tableIndexes.FindIndex("osmID_IDX", out indexPosition);

                            if (indexPosition == -1)
                            {
                                IGPValue relationTableGPValue = gpUtilities3.MakeGPValueFromObject(relationTable);
                                string sddd = targetGPValue.GetAsText();
                                string tableLocation = GetLocationString(targetGPValue, relationTable);
                                IVariantArray parameterArrary = CreateAddIndexParameterArray(tableLocation, "OSMID", "osmID_IDX", "UNIQUE", "");
                                IGeoProcessorResult2 gpResults2 = geoProcessor.Execute("AddIndex_management", parameterArrary, TrackCancel) as IGeoProcessorResult2;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        message.AddWarning(ex.Message);
                    }
                    finally
                    {
                        geoProcessor.AddOutputsToMap = storedOriginalLocal;

                        Marshal.FinalReleaseComObject(gpUtilities3);
                        Marshal.FinalReleaseComObject(geoProcessor);
                    }
                }
            }
            catch (Exception ex)
            {
            }
            finally
            {
                if (relationSerializer != null)
                    relationSerializer = null;

                if (osmFileXmlReader != null)
                    osmFileXmlReader = null;

                System.GC.Collect();
                System.GC.WaitForPendingFinalizers();
            }

            return missingRelations;
        }
        /// <summary>Use AttributeSelector to create attributes for fields specified in the config XML</summary>
        private void ConvertRequiredTagsToAttributes(bool isEdge)
        {
            string featureClassName = ((isEdge) ? _osmLineName : _osmPointName);
            string featureClassPath = ((isEdge) ? _osmLinePath : _osmPointPath);

            using (ComReleaser cr = new ComReleaser())
            {
                IFeatureClass fc = ((IFeatureWorkspace)_osmDataset.Workspace).OpenFeatureClass(featureClassName);
                cr.ManageLifetime(fc);

                string[] requiredFieldNames = ((isEdge) ? _xml.EdgeFieldNames() : _xml.JunctionFieldNames())
                    .Where(fld => fc.FindField("osm_" + fld) == -1)
                    .ToArray();

                if (requiredFieldNames.Length > 0)
                {
                    IVariantArray paramArray = new VarArrayClass();
                    paramArray.Add(featureClassPath);
                    paramArray.Add(string.Join(";", requiredFieldNames));

                    _taskManager.ExecuteTool("OSMGPAttributeSelector_osmtools", paramArray);
                }
            }
        }
        private IFeature FindEdgeFeature(string osmid)
        {
            List<IFeatureClass> fcEdges = OsmEdgeFeatureClasses;

            foreach (IFeatureClass fcEdge in fcEdges)
            {
                IQueryFilter filter = new QueryFilterClass();
                filter.SubFields = string.Join(",", new string[] { fcEdge.OIDFieldName, fcEdge.ShapeFieldName, "OSMID" });
                filter.WhereClause = fcEdge.WhereClauseByExtensionVersion(osmid, "OSMID", OsmExtVersion);

                using (ComReleaser cr = new ComReleaser())
                {
                    IFeatureCursor cursor = fcEdge.Search(filter, false);
                    cr.ManageLifetime(cursor);

                    IFeature feature = cursor.NextFeature();
                    if (feature != null)
                        return feature;
                }
            }

            return null;
        }
        private void updateSource(ITable sourceTable, string action, long oldOSMFeatureID, long newOSMFeatureID, string userName, int userID, int osmVersion, int changeSetID, Dictionary<long, long> nodeIDLookup, Dictionary<long, long> wayIDLookup, Dictionary<long, long> relationIDLookup, int extensionVersion)
        {
            IOSMClassExtension osmExtension = sourceTable.Extension as IOSMClassExtension;

            try
            {
                if (osmExtension != null)
                {
                    osmExtension.CanBypassChangeDetection = true;
                }

                // let's find all the matching row with the old osm feature ID
                IQueryFilter queryFilter = new QueryFilterClass();
                queryFilter.WhereClause = sourceTable.WhereClauseByExtensionVersion(oldOSMFeatureID, "osmID", extensionVersion);

                using (ComReleaser comReleaser = new ComReleaser())
                {
                    ICursor updateCursor = sourceTable.Update(queryFilter, false);
                    comReleaser.ManageLifetime(updateCursor);

                    IRow updateRow = updateCursor.NextRow();
                    comReleaser.ManageLifetime(updateRow);

                    int osmIDFieldIndex = sourceTable.Fields.FindField("osmID");
                    int osmUserFieldIndex = sourceTable.Fields.FindField("osmuser");
                    int osmUIDFieldIndex = sourceTable.Fields.FindField("osmuid");
                    int osmVersionFieldIndex = sourceTable.Fields.FindField("osmversion");
                    int osmVisibleFieldIndex = sourceTable.Fields.FindField("osmvisible");
                    int osmChangesetIDFieldIndex = sourceTable.Fields.FindField("osmchangeset");
                    int osmTimeStampFieldIndex = sourceTable.Fields.FindField("osmtimestamp");
                    int osmMembersFieldIndex = sourceTable.FindField("osmMembers");
                    int osmisMemberOfFieldIndex = sourceTable.FindField("osmMemberOf");
                    int trackChangesFieldIndex = sourceTable.FindField("osmTrackChanges");

                    if (updateRow != null)
                    {
                        if (osmIDFieldIndex > -1)
                        {
                            if (extensionVersion == 1)
                                updateRow.set_Value(osmIDFieldIndex, Convert.ToInt32(newOSMFeatureID));
                            else if (extensionVersion == 2)
                                updateRow.set_Value(osmIDFieldIndex, Convert.ToString(newOSMFeatureID));
                        }
                        if (osmUserFieldIndex > -1)
                        {
                            updateRow.set_Value(osmUserFieldIndex, userName);
                        }
                        if (osmUIDFieldIndex > -1)
                        {
                            updateRow.set_Value(osmUIDFieldIndex, userID);
                        }
                        if (osmVisibleFieldIndex > -1)
                        {
                            updateRow.set_Value(osmVisibleFieldIndex, "true");
                        }
                        if (osmChangesetIDFieldIndex > -1)
                        {
                            updateRow.set_Value(osmChangesetIDFieldIndex, changeSetID);
                        }
                        if (osmTimeStampFieldIndex > -1)
                        {
                            updateRow.set_Value(osmTimeStampFieldIndex, DateTime.Now.ToUniversalTime());
                        }
                        if (trackChangesFieldIndex > -1)
                        {
                            updateRow.set_Value(trackChangesFieldIndex, 1);
                        }

                        // if we are dealing with a row with a shape field (a feature), then change the IDs of the geometry as well
                        IFeature updateFeature = updateRow as IFeature;
                        if (updateFeature != null)
                        {
                            if (updateFeature.Shape.IsEmpty == false)
                            {
                                switch (updateFeature.Shape.GeometryType)
                                {
                                    case esriGeometryType.esriGeometryAny:
                                        break;
                                    case esriGeometryType.esriGeometryBag:
                                        break;
                                    case esriGeometryType.esriGeometryBezier3Curve:
                                        break;
                                    case esriGeometryType.esriGeometryCircularArc:
                                        break;
                                    case esriGeometryType.esriGeometryEllipticArc:
                                        break;
                                    case esriGeometryType.esriGeometryEnvelope:
                                        break;
                                    case esriGeometryType.esriGeometryLine:
                                        break;
                                    case esriGeometryType.esriGeometryMultiPatch:
                                        break;
                                    case esriGeometryType.esriGeometryMultipoint:
                                        break;
                                    case esriGeometryType.esriGeometryNull:
                                        break;
                                    case esriGeometryType.esriGeometryPath:
                                        break;
                                    case esriGeometryType.esriGeometryPoint:
                                        IPoint featurePoint = updateFeature.Shape as IPoint;
                                        if (extensionVersion == 1)
                                            featurePoint.ID = Convert.ToInt32(newOSMFeatureID);
                                        else if (extensionVersion == 2)
                                            // nothing required as the ObjectID of there referenced feature doesn't change
                                            updateFeature.Shape = featurePoint;
                                        if (featurePoint != null)
                                            ComReleaser.ReleaseCOMObject(featurePoint);
                                        break;
                                    case esriGeometryType.esriGeometryPolygon:
                                        IPointCollection pointCollection = updateFeature.Shape as IPointCollection;
                                        IEnumVertex enumVertex = pointCollection.EnumVertices;
                                        enumVertex.Reset();

                                        IPoint currentPoint = null;
                                        int vertexIndex = -1;
                                        int partIndex = -1;

                                        enumVertex.Next(out currentPoint, out partIndex, out vertexIndex);

                                        while (currentPoint != null)
                                        {
                                            if (extensionVersion == 1)
                                            {
                                                if (nodeIDLookup.ContainsKey(currentPoint.ID))
                                                {
                                                    enumVertex.put_ID(Convert.ToInt32(nodeIDLookup[currentPoint.ID]));
                                                }
                                            }
                                            else if (extensionVersion == 2)
                                            {
                                                // nothing required as the ObjectIDs of referenced features don't change
                                            }
                                            enumVertex.Next(out currentPoint, out partIndex, out vertexIndex);
                                        }
                                        updateFeature.Shape = (IGeometry)pointCollection;

                                        // if we are dealing with a multi-part feature then we will need to referenced members as well

                                        break;
                                    case esriGeometryType.esriGeometryPolyline:
                                        pointCollection = updateFeature.Shape as IPointCollection;
                                        enumVertex = pointCollection.EnumVertices;
                                        enumVertex.Reset();

                                        currentPoint = null;
                                        vertexIndex = -1;
                                        partIndex = -1;

                                        enumVertex.Next(out currentPoint, out partIndex, out vertexIndex);

                                        while (currentPoint != null)
                                        {
                                            if (extensionVersion == 1)
                                            {
                                                if (nodeIDLookup.ContainsKey(currentPoint.ID))
                                                {
                                                    enumVertex.put_ID(Convert.ToInt32(nodeIDLookup[currentPoint.ID]));
                                                }
                                            }
                                            else if (extensionVersion == 2)
                                            {
                                                // nothing required as the ObjectIDs of referenced features don't change
                                            }
                                            enumVertex.Next(out currentPoint, out partIndex, out vertexIndex);
                                        }
                                        updateFeature.Shape = (IGeometry)pointCollection;

                                        // if we are dealing with a multi-part feature then we will need to referenced members as well

                                        break;
                                    case esriGeometryType.esriGeometryRay:
                                        break;
                                    case esriGeometryType.esriGeometryRing:
                                        break;
                                    case esriGeometryType.esriGeometrySphere:
                                        break;
                                    case esriGeometryType.esriGeometryTriangleFan:
                                        break;
                                    case esriGeometryType.esriGeometryTriangleStrip:
                                        break;
                                    case esriGeometryType.esriGeometryTriangles:
                                        break;
                                    default:
                                        break;
                                }
                            }
                        }

                        if (osmisMemberOfFieldIndex > -1)
                        {
                            List<string> isMemberOfList = _osmUtility.retrieveIsMemberOf(updateRow, osmisMemberOfFieldIndex);

                            if (isMemberOfList != null && isMemberOfList.Count > 0)
                            {
                                List<string> newIsMemberOfList = new List<string>();

                                if (((IDataset)sourceTable).Name.Contains("_osm_ln") || ((IDataset)sourceTable).Name.Contains("_osm_ply"))
                                {
                                    // since version 1.1 is only dealing with homogeneous features  - lines/polygons
                                    // or in other words only ways we only go through the way look up at this point
                                    foreach (string parentString in isMemberOfList)
                                    {
                                        long idToCheck = Convert.ToInt64(parentString);
                                        if (wayIDLookup.ContainsKey(idToCheck))
                                        {
                                            newIsMemberOfList.Add(wayIDLookup[idToCheck].ToString());
                                        }
                                        else
                                        {
                                            newIsMemberOfList.Add(parentString);
                                        }
                                    }
                                }
                                else
                                {
                                    // in case we dealing with a relation the entity is assumed to be a hybrid and we need to check against node, way, and relations
                                    foreach (string parentString in isMemberOfList)
                                    {
                                        long idToCheck = Convert.ToInt64(parentString);
                                        if (wayIDLookup.ContainsKey(idToCheck))
                                        {
                                            idToCheck = wayIDLookup[idToCheck];
                                        }

                                        if (nodeIDLookup.ContainsKey(idToCheck))
                                        {
                                            idToCheck = nodeIDLookup[idToCheck];
                                        }

                                        if (relationIDLookup.ContainsKey(idToCheck))
                                        {
                                            idToCheck = relationIDLookup[idToCheck];
                                        }

                                        newIsMemberOfList.Add(idToCheck.ToString());
                                    }
                                }

                                _osmUtility.insertIsMemberOf(osmisMemberOfFieldIndex, newIsMemberOfList, updateRow);
                            }
                        }

                        if (osmMembersFieldIndex > -1)
                        {
                            member[] members = _osmUtility.retrieveMembers(updateRow, osmMembersFieldIndex);

                            if (members != null)
                            {
                                for (int memberIndex = 0; memberIndex < members.Length; memberIndex++)
                                {
                                    switch (members[memberIndex].type)
                                    {
                                        case memberType.way:
                                            long wayID = Convert.ToInt64(members[memberIndex].@ref);
                                            if (wayIDLookup.ContainsKey(wayID))
                                            {
                                                members[memberIndex].@ref = wayIDLookup[wayID].ToString();
                                            }
                                            break;
                                        case memberType.node:
                                            long nodeID = Convert.ToInt64(members[memberIndex].@ref);
                                            if (nodeIDLookup.ContainsKey(nodeID))
                                            {
                                                members[memberIndex].@ref = nodeIDLookup[nodeID].ToString();
                                            }
                                            break;
                                        case memberType.relation:
                                            long relationID = Convert.ToInt64(members[memberIndex].@ref);
                                            if (relationIDLookup.ContainsKey(relationID))
                                            {
                                                members[memberIndex].@ref = relationIDLookup[relationID].ToString();
                                            }
                                            break;
                                        default:
                                            break;
                                    }
                                }

                                _osmUtility.insertMembers(osmMembersFieldIndex, updateRow, members);
                            }
                        }

                        if (osmVersionFieldIndex > -1)
                        {
                            updateRow.set_Value(osmVersionFieldIndex, osmVersion);
                        }

                        updateCursor.UpdateRow(updateRow);
                    }
                }
            }
            catch { }
            finally
            {
                if (osmExtension != null)
                    osmExtension.CanBypassChangeDetection = false;
            }
        }
        private ESRI.ArcGIS.OSM.OSMClassExtension.way CreateWayRepresentation(IFeatureClass featureClass, string action, long osmID, string changeSetID, int osmVersion, Dictionary<long, long> osmIDLookup, IFeatureClass pointFeatureClass, int pointOSMIDFieldIndex, int extensionVersion)
        {
            way wayRepresentation = new way();

            // let's find all the rows that have a different status than 200 - meaning success
            IQueryFilter queryFilter = new QueryFilterClass();
            queryFilter.WhereClause = featureClass.WhereClauseByExtensionVersion(osmID, "OSMID", extensionVersion);

            using (ComReleaser comReleaser = new ComReleaser())
            {
                IFeatureCursor searchCursor = featureClass.Search(queryFilter, false);
                comReleaser.ManageLifetime(searchCursor);

                IFeature wayFeature = searchCursor.NextFeature();

                int osmTagsFieldIndex = featureClass.Fields.FindField("osmTags");
                int osmIDFieldIndex = featureClass.Fields.FindField("osmID");
                int osmUserFieldIndex = featureClass.Fields.FindField("osmuser");
                int osmUIDFieldIndex = featureClass.Fields.FindField("osmuid");
                int osmVisibleFieldIndex = featureClass.Fields.FindField("osmvisible");
                int osmVersionFieldIndex = featureClass.Fields.FindField("osmversion");

                if (wayFeature != null)
                {
                    switch (action)
                    {
                        case "create":
                            // the newly created node needs to carry the changeset info, the coordinate and the tags
                            wayRepresentation.changeset = changeSetID;

                            tag[] tags = null;
                            if (osmTagsFieldIndex > -1)
                            {
                                tags = _osmUtility.retrieveOSMTags((IRow)wayFeature, osmTagsFieldIndex, ((IDataset)featureClass).Workspace);
                            }

                            List<tag> valueOnlyTags = new List<tag>();

                            for (int index = 0; index < tags.Length; index++)
                            {
                                if (!String.IsNullOrEmpty(tags[index].v))
                                {
                                    valueOnlyTags.Add(tags[index]);
                                }
                            }

                            wayRepresentation.tag = valueOnlyTags.ToArray();

                            if (osmIDFieldIndex > -1)
                            {
                                wayRepresentation.id = osmID.ToString();
                            }

                            List<nd> nodeList = new List<nd>();

                            IPointCollection pointCollection = wayFeature.Shape as IPointCollection;
                            IEnumVertex enumVertex = pointCollection.EnumVertices;
                            enumVertex.Reset();

                            IPoint currentPoint = null;
                            int vertexIndex = -1;
                            int partIndex = -1;
                            bool isStoreRequired = false;

                            enumVertex.Next(out currentPoint, out partIndex, out vertexIndex);

                            while (currentPoint != null)
                            {
                                if (osmIDLookup.ContainsKey(currentPoint.ID))
                                {
                                    if (extensionVersion == 1)
                                    {
                                        enumVertex.put_ID(Convert.ToInt32(osmIDLookup[currentPoint.ID]));
                                        isStoreRequired = true;
                                    }
                                    else if (extensionVersion == 2)
                                    {
                                        // the initial established ObjectIDs don't change
                                    }
                                }

                                nd ndElement = new nd();
                                ndElement.@ref = OSMToolHelper.retrieveNodeID(pointFeatureClass, osmIDFieldIndex, extensionVersion, pointCollection.get_Point(vertexIndex));
                                nodeList.Add(ndElement);

                                enumVertex.Next(out currentPoint, out partIndex, out vertexIndex);
                            }

                            // only do a store operation if the vertex IDs have actually changed
                            if (isStoreRequired)
                            {
                                wayFeature.Shape = (IGeometry)pointCollection;
                                wayFeature.Store();
                            }

                            nodeList = CorrectNodeIDs(nodeList);

                            wayRepresentation.nd = nodeList.ToArray();

                            break;
                        case "modify":
                            // for an update the complete (full) way needs to be returned
                            wayRepresentation.changeset = changeSetID;
                            if (osmIDFieldIndex > -1)
                            {
                                wayRepresentation.id = Convert.ToString(wayFeature.get_Value(osmIDFieldIndex), new CultureInfo("en-US"));
                            }

                            if (osmUserFieldIndex > -1)
                            {
                                wayRepresentation.user = Convert.ToString(wayFeature.get_Value(osmUserFieldIndex));
                            }

                            if (osmUIDFieldIndex > -1)
                            {
                                wayRepresentation.uid = Convert.ToString(wayFeature.get_Value(osmUIDFieldIndex), new CultureInfo("en-US"));
                            }

                            if (osmVisibleFieldIndex > -1)
                            {
                                try
                                {
                                    wayRepresentation.visible = (wayVisible)Enum.Parse(typeof(wayVisible), Convert.ToString(wayFeature.get_Value(osmVisibleFieldIndex)));
                                }
                                catch
                                {
                                    wayRepresentation.visible = wayVisible.@true;
                                }
                            }

                            if (osmVersionFieldIndex > -1)
                            {
                                wayRepresentation.version = Convert.ToString(wayFeature.get_Value(osmVersionFieldIndex));
                            }

                            tags = null;
                            if (osmTagsFieldIndex > -1)
                            {
                                tags = _osmUtility.retrieveOSMTags((IRow)wayFeature, osmTagsFieldIndex, ((IDataset)featureClass).Workspace);
                            }

                            valueOnlyTags = new List<tag>();

                            for (int index = 0; index < tags.Length; index++)
                            {
                                if (!String.IsNullOrEmpty(tags[index].v))
                                {
                                    valueOnlyTags.Add(tags[index]);
                                }
                            }

                            pointCollection = wayFeature.Shape as IPointCollection;
                            enumVertex = pointCollection.EnumVertices;
                            enumVertex.Reset();

                            currentPoint = null;
                            vertexIndex = -1;
                            partIndex = -1;

                            // use flag if we need to call store on the update feature
                            // it is somewhat of a costly  operation and we would like to avoid it if possible
                            isStoreRequired = false;

                            nodeList = new List<nd>();

                            enumVertex.Next(out currentPoint, out partIndex, out vertexIndex);

                            while (currentPoint != null)
                            {
                                if (osmIDLookup.ContainsKey(currentPoint.ID))
                                {
                                    if (extensionVersion == 1)
                                    {
                                        enumVertex.put_ID(Convert.ToInt32(osmIDLookup[currentPoint.ID]));
                                        isStoreRequired = true;
                                    }
                                    else if (extensionVersion == 2)
                                    {
                                        // the ObjectIDs of the referenced features don't change
                                    }
                                }

                                nd ndElement = new nd();
                                ndElement.@ref = OSMToolHelper.retrieveNodeID(pointFeatureClass, osmIDFieldIndex, extensionVersion, pointCollection.get_Point(vertexIndex));
                                nodeList.Add(ndElement);

                                enumVertex.Next(out currentPoint, out partIndex, out vertexIndex);
                            }

                            if (isStoreRequired)
                            {
                                wayFeature.Shape = (IGeometry)pointCollection;
                                wayFeature.Store();
                            }

                            nodeList = CorrectNodeIDs(nodeList);

                            wayRepresentation.nd = nodeList.ToArray();

                            wayRepresentation.tag = valueOnlyTags.ToArray();

                            break;
                        case "delete":

                            wayRepresentation.changeset = changeSetID;
                            wayRepresentation.id = Convert.ToString(osmID);
                            wayRepresentation.version = Convert.ToString(osmVersion);

                            break;
                        default:
                            break;
                    }
                }
                else
                {
                    if (action.Equals("delete", StringComparison.InvariantCultureIgnoreCase))
                    {
                        wayRepresentation.changeset = changeSetID;
                        wayRepresentation.id = Convert.ToString(osmID);
                        wayRepresentation.version = Convert.ToString(osmVersion);
                    }
                }
            }

            return wayRepresentation;
        }
        private ESRI.ArcGIS.OSM.OSMClassExtension.node CreateNodeRepresentation(IFeatureClass pointFeatureClass, string action, long osmID, string osmChangeSetID, int osmVersion, IPoint deletePoint, int extensionVersion)
        {
            node nodeRepresentation = new node();

            // let's find all the rows that have a different status than 200 - meaning success
            IQueryFilter queryFilter = new QueryFilterClass();
            queryFilter.WhereClause = pointFeatureClass.WhereClauseByExtensionVersion(osmID, "OSMID", extensionVersion);

            using (ComReleaser comReleaser = new ComReleaser())
            {
                IFeatureCursor searchCursor = pointFeatureClass.Search(queryFilter, false);
                comReleaser.ManageLifetime(searchCursor);

                IFeature pointFeature = searchCursor.NextFeature();

                int osmTagsFieldIndex = pointFeatureClass.Fields.FindField("osmTags");
                int osmIDFieldIndex = pointFeatureClass.Fields.FindField("osmID");
                int osmUserFieldIndex = pointFeatureClass.Fields.FindField("osmuser");
                int osmUIDFieldIndex = pointFeatureClass.Fields.FindField("osmuid");
                int osmVisibleFieldIndex = pointFeatureClass.Fields.FindField("osmvisible");
                int osmVersionFieldIndex = pointFeatureClass.Fields.FindField("osmversion");

                IPoint pointGeometry = null;

                if (pointFeature != null)
                {
                    switch (action)
                    {
                        case "create":
                            // the newly created node needs to carry the changeset info, the coordinate and the tags
                            nodeRepresentation.changeset = osmChangeSetID;

                            pointGeometry = pointFeature.Shape as IPoint;
                            pointGeometry.Project(m_wgs84);

                            nodeRepresentation.lat = Convert.ToString(pointGeometry.Y, new CultureInfo("en-US"));
                            nodeRepresentation.lon = Convert.ToString(pointGeometry.X, new CultureInfo("en-US"));

                            tag[] tags = null;
                            if (osmTagsFieldIndex > -1)
                            {
                                tags = _osmUtility.retrieveOSMTags((IRow)pointFeature, osmTagsFieldIndex, ((IDataset)pointFeatureClass).Workspace);
                            }

                            List<tag> valueOnlyTags = new List<tag>();

                            for (int index = 0; index < tags.Length; index++)
                            {
                                if (!String.IsNullOrEmpty(tags[index].v))
                                {
                                    valueOnlyTags.Add(tags[index]);
                                }
                            }

                            nodeRepresentation.tag = valueOnlyTags.ToArray();

                            if (osmIDFieldIndex > -1)
                            {
                                nodeRepresentation.id = Convert.ToString(pointFeature.get_Value(osmIDFieldIndex), new CultureInfo("en-US"));
                            }

                            break;
                        case "modify":
                            // for an update the complete (full) node needs to be returned
                            nodeRepresentation.changeset = osmChangeSetID;

                            pointGeometry = pointFeature.Shape as IPoint;
                            pointGeometry.Project(m_wgs84);

                            nodeRepresentation.lat = Convert.ToString(pointGeometry.Y, new CultureInfo("en-US"));
                            nodeRepresentation.lon = Convert.ToString(pointGeometry.X, new CultureInfo("en-US"));

                            if (osmIDFieldIndex > -1)
                            {
                                nodeRepresentation.id = Convert.ToString(pointFeature.get_Value(osmIDFieldIndex), new CultureInfo("en-US"));
                            }

                            if (osmUserFieldIndex > -1)
                            {
                                nodeRepresentation.user = Convert.ToString(pointFeature.get_Value(osmUserFieldIndex));
                            }

                            if (osmUIDFieldIndex > -1)
                            {
                                nodeRepresentation.uid = Convert.ToString(pointFeature.get_Value(osmUIDFieldIndex), new CultureInfo("en-US"));
                            }

                            if (osmVisibleFieldIndex > -1)
                            {
                                try
                                {
                                    nodeRepresentation.visible = (nodeVisible)Enum.Parse(typeof(nodeVisible), Convert.ToString(pointFeature.get_Value(osmVisibleFieldIndex)));
                                }
                                catch
                                {
                                    nodeRepresentation.visible = nodeVisible.@true;
                                }
                            }

                            if (osmVersionFieldIndex > -1)
                            {
                                nodeRepresentation.version = Convert.ToString(pointFeature.get_Value(osmVersionFieldIndex));
                            }

                            tags = null;
                            if (osmTagsFieldIndex > -1)
                            {
                                tags = _osmUtility.retrieveOSMTags((IRow)pointFeature, osmTagsFieldIndex, ((IDataset)pointFeatureClass).Workspace);
                            }

                            valueOnlyTags = new List<tag>();

                            for (int index = 0; index < tags.Length; index++)
                            {
                                if (!String.IsNullOrEmpty(tags[index].v))
                                {
                                    valueOnlyTags.Add(tags[index]);
                                }
                            }

                            nodeRepresentation.tag = valueOnlyTags.ToArray();

                            break;
                        case "delete":

                            nodeRepresentation.changeset = osmChangeSetID;
                            nodeRepresentation.id = Convert.ToString(osmID);
                            nodeRepresentation.version = Convert.ToString(osmVersion);

                            pointGeometry = pointFeature.Shape as IPoint;
                            pointGeometry.Project(m_wgs84);

                            nodeRepresentation.lat = Convert.ToString(pointGeometry.Y, new CultureInfo("en-US"));
                            nodeRepresentation.lon = Convert.ToString(pointGeometry.X, new CultureInfo("en-US"));

                            break;
                        default:
                            break;
                    }
                }
                else
                {
                    if (action.Equals("delete", StringComparison.InvariantCultureIgnoreCase))
                    {
                        nodeRepresentation.changeset = osmChangeSetID;
                        nodeRepresentation.id = Convert.ToString(osmID);
                        nodeRepresentation.version = Convert.ToString(osmVersion);

                        if (deletePoint != null)
                        {
                            deletePoint.Project(m_wgs84);

                            nodeRepresentation.lat = Convert.ToString(deletePoint.Y, new CultureInfo("en-US"));
                            nodeRepresentation.lon = Convert.ToString(deletePoint.X, new CultureInfo("en-US"));
                        }
                        else
                        {
                            nodeRepresentation = null;
                        }
                    }
                }
            }

            return nodeRepresentation;
        }
        public void UpdateMessages(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager pEnvMgr, ESRI.ArcGIS.Geodatabase.IGPMessages Messages)
        {
            IGPUtilities3 gpUtilities3 = new GPUtilitiesClass();

            // check for a valid download url
            IGPParameter uploadURLParameter = paramvalues.get_Element(in_uploadURLNumber) as IGPParameter;
            IGPString uploadURLGPString = uploadURLParameter.Value as IGPString;

            if (uploadURLGPString == null)
            {
                Messages.ReplaceError(in_uploadURLNumber, -198, String.Format(resourceManager.GetString("GPTools_NullPointerParameterType"), uploadURLParameter.Value.GetAsText()));
            }
            else
            {
                try
                {
                    if (uploadURLParameter.HasBeenValidated == false)
                    {
                        Uri downloadURI = new Uri(uploadURLGPString.Value);

                        // check base url
                        api osmAPICapabilities = OSMGPDownload.CheckValidServerURL(uploadURLGPString.Value);

                        // if we can construct a valid URI  class then we are accepting the value and store it in the user settings as well
                        if (m_editorConfigurationSettings != null)
                        {
                            if (m_editorConfigurationSettings.ContainsKey("osmbaseurl"))
                            {
                                m_editorConfigurationSettings["osmbaseurl"] = uploadURLGPString.Value;
                            }
                            else
                            {
                                m_editorConfigurationSettings.Add("osmbaseurl", uploadURLGPString.Value);
                            }

                            OSMGPFactory.StoreOSMEditorSettings(m_editorConfigurationSettings);
                        }
                    }
                }
                catch (Exception ex)
                {
                    StringBuilder errorMessage = new StringBuilder();
                    errorMessage.AppendLine(resourceManager.GetString("GPTools_OSMGPUpload_invaliduploadurl"));
                    errorMessage.AppendLine(ex.Message);
                    Messages.ReplaceError(in_uploadURLNumber, -3, errorMessage.ToString());
                }
            }

            IGPParameter revisionTableParameter = paramvalues.get_Element(in_changesTablesNumber) as IGPParameter;
            IGPValue revisionTableGPValue = gpUtilities3.UnpackGPValue(revisionTableParameter);

            if (revisionTableGPValue.IsEmpty())
                return;

            ITable revisionTable = null;
            IQueryFilter revisionTableQueryFilter = null;

            try
            {
                using (ComReleaser comReleaser = new ComReleaser())
                {
                    gpUtilities3.DecodeTableView(revisionTableGPValue, out revisionTable, out revisionTableQueryFilter);
                    comReleaser.ManageLifetime(revisionTable);

                    if (revisionTable is IFeatureClass)
                    {
                        Messages.ReplaceError(in_changesTablesNumber, -4, resourceManager.GetString("GPTools_OSMGPUpload_notarevisiontable"));
                        return;
                    }

                    IDatasetEdit datasetEdit = revisionTable as IDatasetEdit;
                    comReleaser.ManageLifetime(datasetEdit);

                    if (datasetEdit == null)
                    {
                        return;
                    }

                    if (datasetEdit.IsBeingEdited())
                    {
                        Messages.ReplaceError(in_changesTablesNumber, -4, resourceManager.GetString("GPTools_OSMGPUpload_inputnotvalidduringedit"));
                    }
                }

                gpUtilities3.ReleaseInternals();
            }
            catch
            {
                // check if we are dealing with a variable -- if we do then leave this string alone
                string tableName = revisionTableGPValue.GetAsText();
                string tableNameModified = tableName.Replace("%", String.Empty);

                if (((tableName.Length - tableNameModified.Length) % 2) == 0)
                {
                    Messages.Replace(in_changesTablesNumber, new GPMessageClass());
                }
            }
        }
        private void OSMConflictEditorUI_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (errorTreeView == null)
            {
                return;
            }

            if (errorTreeView.Nodes == null)
            {
                return;
            }

            foreach (TreeNode revisionErrorNode in errorTreeView.Nodes)
            {
                ITable revisionTable = m_allRevisionTables[revisionErrorNode.Text];

                int revisionOSMActionFieldIndex = revisionTable.Fields.FindField("osmaction");
                int revisionOSMElementTypeFieldIndex = revisionTable.Fields.FindField("osmelementtype");
                int revisionOSMSourceFCNameFieldIndex = revisionTable.Fields.FindField("sourcefcname");
                int revisionOSMStatusFieldIndex = revisionTable.Fields.FindField("osmstatus");
                int revisionOSMStatusCodeFieldIndex = revisionTable.Fields.FindField("osmstatuscode");
                int revisionOSMErrorMessageFieldIndex = revisionTable.Fields.FindField("osmerrormessage");
                int revisionOSMOldIDFieldIndex = revisionTable.Fields.FindField("osmoldid");
                int revisionOSMVersionFieldIndex = revisionTable.Fields.FindField("osmversion");

                int localVersionFieldIndex = -1;
                int serverVersionFieldIndex = -1;

                int localChangesetFieldIndex = -1;
                int serverChangesetFieldIndex = -1;

                int localOSMTagsFieldIndex = -1;
                int serverOSMTagsFieldIndex = -1;

                IRow localRow = null;
                IRow serverRow = null;
                IRow updateRow = null;

                IFeature localFeature = null;
                IFeature serverFeature = null;

                foreach (TreeNode errorNode in revisionErrorNode.Nodes)
                {
                    conflictTag errorNodeConflictTag = errorNode.Tag as conflictTag;

                    switch (errorNodeConflictTag.DeterminedResolution)
                    {
                        case conflictTag.osmConflictResolution.osmNoResolution:
                            break;
                        case conflictTag.osmConflictResolution.osmUpdateLocalVersionNumber:
                            try
                            {
                                ResolveNodeTag(errorNode, out localRow, out serverRow);

                                if (serverRow == null || localRow == null)
                                {
                                    continue;
                                }

                                if (m_editor != null)
                                {
                                    m_editor.StartOperation();
                                }

                                localVersionFieldIndex = localRow.Fields.FindField("osmversion");
                                serverVersionFieldIndex = serverRow.Fields.FindField("osmversion");

                                localChangesetFieldIndex = localRow.Fields.FindField("osmchangeset");
                                serverChangesetFieldIndex = serverRow.Fields.FindField("osmchangeset");

                                if (localVersionFieldIndex != -1 && serverVersionFieldIndex != -1)
                                {
                                    localRow.set_Value(localVersionFieldIndex, serverRow.get_Value(serverVersionFieldIndex));
                                }

                                if (localChangesetFieldIndex != -1 && serverChangesetFieldIndex != -1)
                                {
                                    localRow.set_Value(localChangesetFieldIndex, serverRow.get_Value(serverChangesetFieldIndex));
                                }

                                localRow.Store();

                                updateRow = revisionTable.GetRow(errorNodeConflictTag.RevisionOID);
                                ClearRevisionErrors(updateRow, revisionOSMStatusFieldIndex, revisionOSMStatusCodeFieldIndex, revisionOSMErrorMessageFieldIndex);

                                if (revisionOSMVersionFieldIndex != -1 && serverVersionFieldIndex != -1)
                                {
                                    updateRow.set_Value(revisionOSMVersionFieldIndex, serverRow.get_Value(serverVersionFieldIndex));
                                }

                                updateRow.Store();

                                if (m_editor != null)
                                {
                                    if (!String.IsNullOrEmpty(errorNode.ToolTipText))
                                    {
                                        m_editor.StopOperation(errorNode.ToolTipText);
                                    }
                                    else
                                    {
                                        m_editor.StopOperation(resourceManager.GetString("OSMEditor_ConflictEditor_genericConflictOpMessage"));
                                    }
                                }
                            }
                            catch
                            {
                                if (m_editor != null)
                                {
                                    m_editor.AbortOperation();
                                }
                            }
                            break;
                        case conflictTag.osmConflictResolution.osmUpdateLocalGeometryServerAttributes:
                            try
                            {
                                ResolveNodeTag(errorNode, out localRow, out serverRow);

                                if (serverRow == null || localRow == null)
                                {
                                    continue;
                                }

                                if (m_editor != null)
                                {
                                    m_editor.StartOperation();
                                }

                                localOSMTagsFieldIndex = localRow.Fields.FindField("osmTags");
                                serverOSMTagsFieldIndex = serverRow.Fields.FindField("osmTags");

                                ESRI.ArcGIS.OSM.OSMClassExtension.tag[] serverTags = null;

                                if (serverOSMTagsFieldIndex != -1)
                                {
                                    serverTags = _osmUtility.retrieveOSMTags(serverRow, serverOSMTagsFieldIndex, null);
                                }

                                if (localOSMTagsFieldIndex != -1)
                                {
                                    _osmUtility.insertOSMTags(localOSMTagsFieldIndex, localRow, serverTags, ((IDataset)revisionTable).Workspace);
                                }

                                localVersionFieldIndex = localRow.Fields.FindField("osmversion");
                                serverVersionFieldIndex = serverRow.Fields.FindField("osmversion");

                                localChangesetFieldIndex = localRow.Fields.FindField("osmchangeset");
                                serverChangesetFieldIndex = serverRow.Fields.FindField("osmchangeset");

                                if (localVersionFieldIndex != -1 && serverVersionFieldIndex != -1)
                                {
                                    localRow.set_Value(localVersionFieldIndex, serverRow.get_Value(serverVersionFieldIndex));
                                }

                                if (localChangesetFieldIndex != -1 && serverChangesetFieldIndex != -1)
                                {
                                    localRow.set_Value(localChangesetFieldIndex, serverRow.get_Value(serverChangesetFieldIndex));
                                }

                                localRow.Store();

                                updateRow = revisionTable.GetRow(errorNodeConflictTag.RevisionOID);
                                ClearRevisionErrors(updateRow, revisionOSMStatusFieldIndex, revisionOSMStatusCodeFieldIndex, revisionOSMErrorMessageFieldIndex);

                                if (revisionOSMVersionFieldIndex != -1 && serverVersionFieldIndex != -1)
                                {
                                    updateRow.set_Value(revisionOSMVersionFieldIndex, serverRow.get_Value(serverVersionFieldIndex));
                                }

                                updateRow.Store();

                                if (m_editor != null)
                                {
                                    if (!String.IsNullOrEmpty(errorNode.ToolTipText))
                                    {
                                        m_editor.StopOperation(errorNode.ToolTipText);
                                    }
                                    else
                                    {
                                        m_editor.StopOperation(resourceManager.GetString("OSMEditor_ConflictEditor_genericConflictOpMessage"));
                                    }
                                }
                            }
                            catch
                            {
                                if (m_editor != null)
                                {
                                    m_editor.AbortOperation();
                                }
                            }
                            break;
                        case conflictTag.osmConflictResolution.osmUpdateServerGeometryLocalAttributes:
                            try
                            {
                                ResolveNodeTag(errorNode, out localRow, out serverRow);

                                if (serverRow == null || localRow == null)
                                {
                                    continue;
                                }

                                if (m_editor != null)
                                {
                                    m_editor.StartOperation();
                                }

                                localFeature = localRow as IFeature;
                                serverFeature = serverRow as IFeature;

                                localFeature.Shape = serverFeature.ShapeCopy;

                                localVersionFieldIndex = localRow.Fields.FindField("osmversion");
                                serverVersionFieldIndex = serverRow.Fields.FindField("osmversion");

                                localChangesetFieldIndex = localRow.Fields.FindField("osmchangeset");
                                serverChangesetFieldIndex = serverRow.Fields.FindField("osmchangeset");

                                if (localVersionFieldIndex != -1 && serverVersionFieldIndex != -1)
                                {
                                    localRow.set_Value(localVersionFieldIndex, serverRow.get_Value(serverVersionFieldIndex));
                                }

                                if (localChangesetFieldIndex != -1 && serverChangesetFieldIndex != -1)
                                {
                                    localRow.set_Value(localChangesetFieldIndex, serverRow.get_Value(serverChangesetFieldIndex));
                                }

                                localRow.Store();

                                updateRow = revisionTable.GetRow(errorNodeConflictTag.RevisionOID);
                                ClearRevisionErrors(updateRow, revisionOSMStatusFieldIndex, revisionOSMStatusCodeFieldIndex, revisionOSMErrorMessageFieldIndex);
                                updateRow.Store();

                                if (m_editor != null)
                                {
                                    if (!String.IsNullOrEmpty(errorNode.ToolTipText))
                                    {
                                        m_editor.StopOperation(errorNode.ToolTipText);
                                    }
                                    else
                                    {
                                        m_editor.StopOperation(resourceManager.GetString("OSMEditor_ConflictEditor_genericConflictOpMessage"));
                                    }
                                }
                            }
                            catch
                            {
                                if (m_editor != null)
                                {
                                    m_editor.AbortOperation();
                                }
                            }
                            break;
                        case conflictTag.osmConflictResolution.osmUpdateServerGeometryServerAttributes:
                            try
                            {
                                ResolveNodeTag(errorNode, out localRow, out serverRow);

                                if (serverRow == null || localRow == null)
                                {
                                    continue;
                                }

                                if (m_editor != null)
                                {
                                    m_editor.StartOperation();
                                }

                                localOSMTagsFieldIndex = localRow.Fields.FindField("osmTags");
                                serverOSMTagsFieldIndex = serverRow.Fields.FindField("osmTags");

                                ESRI.ArcGIS.OSM.OSMClassExtension.tag[] serverTags = null;

                                if (serverOSMTagsFieldIndex != -1)
                                {
                                    serverTags = _osmUtility.retrieveOSMTags(serverRow, serverOSMTagsFieldIndex, null);
                                }

                                if (localOSMTagsFieldIndex != -1)
                                {
                                    _osmUtility.insertOSMTags(localOSMTagsFieldIndex, localRow, serverTags, ((IDataset)revisionTable).Workspace);
                                }

                                localFeature = localRow as IFeature;
                                serverFeature = serverRow as IFeature;

                                localFeature.Shape = serverFeature.ShapeCopy;

                                localVersionFieldIndex = localRow.Fields.FindField("osmversion");
                                serverVersionFieldIndex = serverRow.Fields.FindField("osmversion");

                                localChangesetFieldIndex = localRow.Fields.FindField("osmchangeset");
                                serverChangesetFieldIndex = serverRow.Fields.FindField("osmchangeset");

                                if (localVersionFieldIndex != -1 && serverVersionFieldIndex != -1)
                                {
                                    localRow.set_Value(localVersionFieldIndex, serverRow.get_Value(serverVersionFieldIndex));
                                }

                                if (localChangesetFieldIndex != -1 && serverChangesetFieldIndex != -1)
                                {
                                    localRow.set_Value(localChangesetFieldIndex, serverRow.get_Value(serverChangesetFieldIndex));
                                }

                                localRow.Store();

                                updateRow = revisionTable.GetRow(errorNodeConflictTag.RevisionOID);
                                ClearRevisionErrors(updateRow, revisionOSMStatusFieldIndex, revisionOSMStatusCodeFieldIndex, revisionOSMErrorMessageFieldIndex);

                                if (revisionOSMVersionFieldIndex != -1 && serverVersionFieldIndex != -1)
                                {
                                    updateRow.set_Value(revisionOSMVersionFieldIndex, serverRow.get_Value(serverVersionFieldIndex));
                                }

                                updateRow.Store();

                                if (m_editor != null)
                                {
                                    if (!String.IsNullOrEmpty(errorNode.ToolTipText))
                                    {
                                        m_editor.StopOperation(errorNode.ToolTipText);
                                    }
                                    else
                                    {
                                        m_editor.StopOperation(resourceManager.GetString("OSMEditor_ConflictEditor_genericConflictOpMessage"));
                                    }
                                }
                            }
                            catch
                            {
                                if (m_editor != null)
                                {
                                    m_editor.AbortOperation();
                                }
                            }

                            break;
                        case conflictTag.osmConflictResolution.osmDeleteLocalFeature:
                            try
                            {
                                if (m_editor != null)
                                {
                                    m_editor.StartOperation();
                                }

                                IFeatureWorkspace featureWorkspace = ((IDataset)revisionTable).Workspace as IFeatureWorkspace;
                                IFeatureClass localFeatureClass = featureWorkspace.OpenFeatureClass(errorNodeConflictTag.SourceFeatureClassName);

                                IQueryFilter localQueryFilter = new QueryFilterClass();
                                localQueryFilter.WhereClause = localFeatureClass.WhereClauseByExtensionVersion(errorNodeConflictTag.OSMID, "OSMID", localFeatureClass.OSMExtensionVersion());

                                using (ESRI.ArcGIS.OSM.OSMClassExtension.ComReleaser comReleaser = new ESRI.ArcGIS.OSM.OSMClassExtension.ComReleaser())
                                {
                                    IFeatureCursor localSearchCursor = localFeatureClass.Search(localQueryFilter, false);
                                    comReleaser.ManageLifetime(localSearchCursor);

                                    localFeature = localSearchCursor.NextFeature();

                                    while (localFeature != null)
                                    {
                                        localFeature.Delete();

                                        localFeature = localSearchCursor.NextFeature();
                                    }
                                }

                                updateRow = revisionTable.GetRow(errorNodeConflictTag.RevisionOID);
                                updateRow.Delete();

                                if (m_editor != null)
                                {
                                    if (!String.IsNullOrEmpty(errorNode.ToolTipText))
                                    {
                                        m_editor.StopOperation(errorNode.ToolTipText);
                                    }
                                    else
                                    {
                                        m_editor.StopOperation(resourceManager.GetString("OSMEditor_ConflictEditor_genericConflictOpMessage"));
                                    }
                                }
                            }
                            catch
                            {
                                if (m_editor != null)
                                {
                                    m_editor.AbortOperation();
                                }
                            }

                            break;
                        case conflictTag.osmConflictResolution.osmChangeUpdateToCreate:
                            try
                            {
                                if (m_editor != null)
                                {
                                    m_editor.StartOperation();
                                }

                                updateRow = revisionTable.GetRow(errorNodeConflictTag.RevisionOID);

                                ClearRevisionErrors(updateRow, revisionOSMStatusFieldIndex, revisionOSMStatusCodeFieldIndex, revisionOSMErrorMessageFieldIndex);

                                if (revisionOSMActionFieldIndex != -1)
                                {
                                    updateRow.set_Value(revisionOSMActionFieldIndex, "create");
                                }

                                updateRow.Store();

                                if (m_editor != null)
                                {
                                    if (!String.IsNullOrEmpty(errorNode.ToolTipText))
                                    {
                                        m_editor.StopOperation(errorNode.ToolTipText);
                                    }
                                    else
                                    {
                                        m_editor.StopOperation(resourceManager.GetString("OSMEditor_ConflictEditor_genericConflictOpMessage"));
                                    }
                                }
                            }
                            catch
                            {
                                if (m_editor != null)
                                {
                                    m_editor.AbortOperation();
                                }
                            }
                            break;
                        case conflictTag.osmConflictResolution.osmClearRevisionStatus:
                            try
                            {
                                if (m_editor != null)
                                {
                                    m_editor.StartOperation();
                                }

                                updateRow = revisionTable.GetRow(errorNodeConflictTag.RevisionOID);

                                ClearRevisionErrors(updateRow, revisionOSMStatusFieldIndex, revisionOSMStatusCodeFieldIndex, revisionOSMErrorMessageFieldIndex);

                                updateRow.Store();

                                if (m_editor != null)
                                {
                                    if (!String.IsNullOrEmpty(errorNode.ToolTipText))
                                    {
                                        m_editor.StopOperation(errorNode.ToolTipText);
                                    }
                                    else
                                    {
                                        m_editor.StopOperation(resourceManager.GetString("OSMEditor_ConflictEditor_genericConflictOpMessage"));
                                    }
                                }
                            }
                            catch
                            {
                                if (m_editor != null)
                                {
                                    m_editor.AbortOperation();
                                }
                            }
                            break;
                        case conflictTag.osmConflictResolution.osmRemoveRevisionIncident:
                            try
                            {
                                if (m_editor != null)
                                {
                                    m_editor.StartOperation();
                                }

                                IRow rowToDelete = revisionTable.GetRow(errorNodeConflictTag.RevisionOID);
                                rowToDelete.Delete();

                                if (m_editor != null)
                                {
                                    if (!String.IsNullOrEmpty(errorNode.ToolTipText))
                                    {
                                        m_editor.StopOperation(errorNode.ToolTipText);
                                    }
                                    else
                                    {
                                        m_editor.StopOperation(resourceManager.GetString("OSMEditor_ConflictEditor_genericConflictOpMessage"));
                                    }
                                }
                            }
                            catch
                            {
                                if (m_editor != null)
                                {
                                    m_editor.AbortOperation();
                                }
                            }
                            break;
                        default:
                            break;
                    }
                }
            }

            foreach (KeyValuePair<string, ITable> table in m_allRevisionTables)
            {
                // explicitly release the tables
                if (table.Value != null)
                {
                    Marshal.ReleaseComObject(table.Value);
                }
            }

            //finally clear the table itself
            m_allRevisionTables.Clear();
        }
        private osmRelationGeometryType walkRelationGeometry(IFeatureClass osmLineFeatureClass, IFeatureClass osmPolygonFeatureClass, ITable relationTable, relation currentRelation)
        {
            osmRelationGeometryType testedGeometry = osmRelationGeometryType.osmUnknownGeometry;

            // we use this dictionary to determine if we can fully walk this relation
            // - the assumption is that we can walk the geometry is all node counts are 2
            Dictionary<int, int> nodeCountDictionary = new Dictionary<int, int>();

            try
            {
                if (currentRelation.Items == null)
                    return testedGeometry;

                foreach (var item in currentRelation.Items)
                {
                    if (item is ESRI.ArcGIS.OSM.OSMClassExtension.member)
                    {
                        member memberItem = item as member;
                        IQueryFilter osmIDQueryFilter = new QueryFilterClass();

                        using (ComReleaser comReleaser = new ComReleaser())
                        {
                            if (osmLineFeatureClass != null)
                            {
                                osmIDQueryFilter.WhereClause = osmLineFeatureClass.WhereClauseByExtensionVersion(memberItem.@ref, "OSMID", 2);
                                IFeatureCursor lineFeatureCursor = osmLineFeatureClass.Search(osmIDQueryFilter, false);
                                comReleaser.ManageLifetime(lineFeatureCursor);

                                IFeature foundLineFeature = lineFeatureCursor.NextFeature();

                                if (foundLineFeature != null)
                                {
                                    IPointCollection pointCollection = foundLineFeature.Shape as IPointCollection;

                                    int firstPointID = pointCollection.get_Point(0).ID;
                                    int lastPointID = pointCollection.get_Point(pointCollection.PointCount - 1).ID;

                                    if (nodeCountDictionary.ContainsKey(firstPointID))
                                    {
                                        nodeCountDictionary[firstPointID] = nodeCountDictionary[firstPointID] + 1;
                                    }
                                    else
                                    {
                                        nodeCountDictionary.Add(firstPointID, 1);
                                    }

                                    if (nodeCountDictionary.ContainsKey(lastPointID))
                                    {
                                        nodeCountDictionary[lastPointID] = nodeCountDictionary[lastPointID] + 1;
                                    }
                                    else
                                    {
                                        nodeCountDictionary.Add(lastPointID, 1);
                                    }
                                }

                                osmIDQueryFilter.WhereClause = osmPolygonFeatureClass.WhereClauseByExtensionVersion(memberItem.@ref, "OSMID", 2);
                                IFeatureCursor polygonFeatureCursor = osmPolygonFeatureClass.Search(osmIDQueryFilter, false);
                                comReleaser.ManageLifetime(polygonFeatureCursor);

                                IFeature foundPolygonFeature = polygonFeatureCursor.NextFeature();

                                if (foundPolygonFeature != null)
                                {
                                    IPointCollection pointCollection = foundPolygonFeature.Shape as IPointCollection;

                                    int firstPointID = pointCollection.get_Point(0).ID;

                                    if (nodeCountDictionary.ContainsKey(firstPointID))
                                    {
                                        nodeCountDictionary[firstPointID] = nodeCountDictionary[firstPointID] + 2;
                                    }
                                    else
                                    {
                                        nodeCountDictionary.Add(firstPointID, 2);
                                    }
                                }

                                osmIDQueryFilter.WhereClause = relationTable.WhereClauseByExtensionVersion(memberItem.@ref, "OSMID", 2);
                                ICursor relationCursor = relationTable.Search(osmIDQueryFilter, false);
                                comReleaser.ManageLifetime(relationCursor);

                                IRow foundRelation = relationCursor.NextRow();

                                if (foundRelation != null)
                                {
                                    // in order to be in the relation table is needs to be a either a super-relation or a mixed type entity (hence hybrid)
                                    testedGeometry = osmRelationGeometryType.osmHybridGeometry;
                                    break;
                                }
                            }
                        }
                    }
                }

                // check if there are any nodes counts other than 2, if there are then we cannot fully "walk" the geometry and it will be considered a line
                if (nodeCountDictionary.Values.Any(e => (e != 2)))
                {
                    testedGeometry = osmRelationGeometryType.osmPolyline;
                }
                else
                {
                    testedGeometry = osmRelationGeometryType.osmPolygon;
                }
            }

            catch
            {
                testedGeometry = osmRelationGeometryType.osmHybridGeometry;
            }

            return testedGeometry;
        }
        private void updateIsMemberOf(IFeatureClass osmLineFeatureClass, int osmMemberOfPolylineFieldIndex, string osmID, List<string> parentList)
        {
            using (ComReleaser comReleaserInternal = new ComReleaser())
            {
                IQueryFilter lineQueryFilter = new QueryFilterClass();
                lineQueryFilter.WhereClause = osmLineFeatureClass.WhereClauseByExtensionVersion(osmID, "OSMID", 2);
                IFeatureCursor searchCursor = osmLineFeatureClass.Update(lineQueryFilter, false);
                comReleaserInternal.ManageLifetime(searchCursor);

                IFeature featureToModify = searchCursor.NextFeature();
                if (featureToModify != null)
                {
                    List<string> isMemberOfList = _osmUtility.retrieveIsMemberOf(featureToModify, osmMemberOfPolylineFieldIndex);

                    // create a union of both lists
                    List<string> unionedMemberOfList = new List<string>(isMemberOfList.Union(parentList));

                    isMemberOfList.AddRange(unionedMemberOfList);

                    _osmUtility.insertIsMemberOf(osmMemberOfPolylineFieldIndex, unionedMemberOfList, featureToModify);

                    searchCursor.UpdateFeature(featureToModify);

                    if (featureToModify != null)
                        Marshal.ReleaseComObject(featureToModify);
                }
            }
        }
        private bool IsThisWayALine(string osmID, IFeatureClass lineFeatureClass, string lineQueryIdentifier, IFeatureClass polygonFeatureClass, string polygonQueryIdentifier)
        {
            bool isALine = true;

            using (ComReleaser comReleaser = new ComReleaser())
            {
                IQueryFilter polygonQueryFilter = new QueryFilterClass();
                polygonQueryFilter.WhereClause = polygonQueryIdentifier + " = '" + osmID + "'";
                IFeatureCursor polygonCursor = polygonFeatureClass.Search(polygonQueryFilter, false);
                comReleaser.ManageLifetime(polygonCursor);

                IFeature polyFeature = polygonCursor.NextFeature();

                if (polyFeature != null)
                {
                    isALine = false;
                }
            }

            return isALine;
        }
        private bool CheckIfExists(ITable searchTable, string osmID)
        {
            bool featureAlreadyExists = true;

            try
            {
                string sqlIdentifier = searchTable.SqlIdentifier(osmID);
                using (ComReleaser comReleaser = new ComReleaser())
                {

                IQueryFilter queryFilter = new QueryFilterClass();
                queryFilter.WhereClause = sqlIdentifier + " = '" + osmID + "'";

                    ICursor rowCursor = searchTable.Search(queryFilter, false);
                    comReleaser.ManageLifetime(rowCursor);

                    IRow foundRow = rowCursor.NextRow();

                    if (foundRow == null)
                    {
                        featureAlreadyExists = false;
                    }

                    Marshal.ReleaseComObject(foundRow);
                }
            }
            catch { }

            return featureAlreadyExists;
        }
        internal List<ESRI.ArcGIS.OSM.OSMClassExtension.tag> MergeTagsFromOuterPolygonToRelation(ESRI.ArcGIS.OSM.OSMClassExtension.relation currentRelation, IFeatureClass polygonFeatureClass)
        {
            Dictionary<string, ESRI.ArcGIS.OSM.OSMClassExtension.tag> mergedTagList = new Dictionary<string, ESRI.ArcGIS.OSM.OSMClassExtension.tag>();

            IQueryFilter osmIDQueryFilter = new QueryFilterClass();

            try
            {
                int osmIDPolygonFieldIndex = polygonFeatureClass.FindField("OSMID");
                string sqlPolyOSMID = polygonFeatureClass.SqlIdentifier("OSMID");

                foreach (var relationItem in currentRelation.Items)
                {
                    if (relationItem is ESRI.ArcGIS.OSM.OSMClassExtension.member)
                    {
                        ESRI.ArcGIS.OSM.OSMClassExtension.member currentRelationMember = relationItem as ESRI.ArcGIS.OSM.OSMClassExtension.member;

                        if (currentRelationMember.role.ToLower().Equals("outer"))
                        {
                            using (ComReleaser comReleaser = new ComReleaser())
                            {
                                osmIDQueryFilter.WhereClause = sqlPolyOSMID + " = " + currentRelationMember.@ref;

                                IFeatureCursor featureCursor = polygonFeatureClass.Search(osmIDQueryFilter, false);
                                comReleaser.ManageLifetime(featureCursor);

                                IFeature foundPolygonFeature = featureCursor.NextFeature();

                                if (foundPolygonFeature == null)
                                    continue;

                                tag[] foundTags = _osmUtility.retrieveOSMTags(foundPolygonFeature, osmIDPolygonFieldIndex, ((IDataset)polygonFeatureClass).Workspace);

                                foreach (tag currentWayTag in foundTags)
                                {
                                    // first one in wins
                                    try
                                    {
                                        if (!mergedTagList.ContainsKey(currentWayTag.k))
                                        {
                                            mergedTagList.Add(currentWayTag.k, currentWayTag);
                                        }
                                    }
                                    catch { }
                                }
                            }
                        }
                    }
                    else if (relationItem is tag)
                    {
                        tag relationTag = relationItem as tag;

                        try
                        {
                            if (!mergedTagList.ContainsKey(relationTag.k))
                            {
                                mergedTagList.Add(relationTag.k, relationTag);
                            }
                        }
                        catch { }
                    }
                }
            }
            catch { }

            return mergedTagList.Values.ToList();
        }
        internal List<string> loadOSMWays(string osmFileLocation, ref ITrackCancel TrackCancel, ref IGPMessages message, IGPValue targetGPValue, IFeatureClass osmPointFeatureClass, IFeatureClass osmLineFeatureClass, IFeatureClass osmPolygonFeatureClass, bool conserveMemory, bool fastLoad, int wayCapacity, ref Dictionary<string, simplePointRef> osmNodeDictionary, IFeatureWorkspace featureWorkspace, ISpatialReference downloadSpatialReference, OSMDomains availableDomains, bool checkForExisting)
        {
            if (osmLineFeatureClass == null)
            {
                throw new ArgumentNullException("osmLineFeatureClass");
            }

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

            XmlReader osmFileXmlReader = null;
            XmlSerializer waySerializer = null;
            List<string> missingWays = null;

            try
            {
                missingWays = new List<string>();

                int osmPointIDFieldIndex = osmPointFeatureClass.FindField("OSMID");
                int osmWayRefCountFieldIndex = osmPointFeatureClass.FindField("wayRefCount");

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

                    if (currentFieldIndex != -1)
                    {
                        osmLineDomainAttributeFieldIndices.Add(domains.name, currentFieldIndex);
                        osmLineDomainAttributeFieldLength.Add(domains.name, osmLineFeatureClass.Fields.get_Field(currentFieldIndex).Length);
                    }
                }
                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");

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

                    if (currentFieldIndex != -1)
                    {
                        osmPolygonDomainAttributeFieldIndices.Add(domains.name, currentFieldIndex);
                        osmPolygonDomainAttributeFieldLength.Add(domains.name, osmPolygonFeatureClass.Fields.get_Field(currentFieldIndex).Length);
                    }
                }
                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");

                ISpatialReferenceFactory spatialRef = new SpatialReferenceEnvironmentClass();
                ISpatialReference wgs84 = spatialRef.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984);

                bool shouldProject = !((IClone)wgs84).IsEqual((IClone)downloadSpatialReference);

                // set up the progress indicator
                IStepProgressor stepProgressor = TrackCancel as IStepProgressor;

                if (stepProgressor != null)
                {
                    stepProgressor.MinRange = 0;
                    stepProgressor.MaxRange = wayCapacity;
                    stepProgressor.Position = 0;
                    stepProgressor.Message = _resourceManager.GetString("GPTools_OSMGPFileReader_loadingWays");
                    stepProgressor.StepValue = 1;
                    stepProgressor.Show();
                }

                bool lineIndexRebuildRequired = false;
                bool polygonIndexRebuildRequired = false;

                int wayCount = 0;
                object missingValue = System.Reflection.Missing.Value;

                // enterprise GDB indicator -- supporting load only mode
                IFeatureClassLoad lineFeatureLoad = null;
                IFeatureClassLoad polygonFeatureLoad = null;

                using (SchemaLockManager lineLock = new SchemaLockManager(osmLineFeatureClass as ITable), polygonLock = new SchemaLockManager(osmPolygonFeatureClass as ITable))
                {
                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        IFeatureCursor insertLineCursor = osmLineFeatureClass.Insert(true);
                        comReleaser.ManageLifetime(insertLineCursor);

                        IFeatureBuffer featureLineBuffer = osmLineFeatureClass.CreateFeatureBuffer();
                        comReleaser.ManageLifetime(featureLineBuffer);

                        IFeatureCursor insertPolygonCursor = osmPolygonFeatureClass.Insert(true);
                        comReleaser.ManageLifetime(insertPolygonCursor);

                        IFeatureBuffer featurePolygonBuffer = osmPolygonFeatureClass.CreateFeatureBuffer();
                        comReleaser.ManageLifetime(featurePolygonBuffer);

                        if (((IWorkspace)featureWorkspace).WorkspaceFactory.WorkspaceType == esriWorkspaceType.esriRemoteDatabaseWorkspace)
                        {
                            lineFeatureLoad = osmLineFeatureClass as IFeatureClassLoad;
                            polygonFeatureLoad = osmPolygonFeatureClass as IFeatureClassLoad;
                        }

                        if (lineFeatureLoad != null)
                        {
                            lineFeatureLoad.LoadOnlyMode = true;
                        }

                        if (polygonFeatureLoad != null)
                        {
                            polygonFeatureLoad.LoadOnlyMode = true;
                        }

                        ISpatialReference nativeLineSpatialReference = ((IGeoDataset)osmLineFeatureClass).SpatialReference;
                        ISpatialReference nativePolygonSpatialReference = ((IGeoDataset)osmPolygonFeatureClass).SpatialReference;

                        IQueryFilter osmIDQueryFilter = new QueryFilterClass();
                        string sqlPointOSMID = osmPointFeatureClass.SqlIdentifier("OSMID");
                        IFeatureCursor updatePointCursor = null;

                        osmFileXmlReader = System.Xml.XmlReader.Create(osmFileLocation);
                        waySerializer = new XmlSerializer(typeof(way));

                        // the point query filter for updates will not changes, so let's do that ahead of time
                        try
                        {
                            osmIDQueryFilter.SubFields = osmPointFeatureClass.ShapeFieldName + "," + osmPointFeatureClass.Fields.get_Field(osmPointIDFieldIndex).Name + "," + osmPointFeatureClass.Fields.get_Field(osmWayRefCountFieldIndex).Name;
                        }
                        catch
                        { }

                        osmFileXmlReader.MoveToContent();
                        while (osmFileXmlReader.Read())
                        {
                            if (osmFileXmlReader.IsStartElement())
                            {
                                if (osmFileXmlReader.Name == "way")
                                {
                                    string currentwayString = osmFileXmlReader.ReadOuterXml();

                                    // assuming the way to be a polyline is sort of a safe assumption
                                    // and won't cause any topology problem due to orientation and closeness
                                    bool wayIsLine = true;
                                    bool wayIsComplete = true;

                                    way currentWay = null;

                                    try
                                    {
                                        using (StringReader wayReader = new System.IO.StringReader(currentwayString))
                                        {
                                            currentWay = waySerializer.Deserialize(wayReader) as way;
                                        }

                                        // if the deserialization fails then go ahead and read the next xml element
                                        if (currentWay == null)
                                        {
                                            continue;
                                        }

                                        // and we are expecting at least some nodes on the way itself
                                        if (currentWay.nd == null)
                                        {
                                            continue;
                                        }

                                        featureLineBuffer = osmLineFeatureClass.CreateFeatureBuffer();
                                        featurePolygonBuffer = osmPolygonFeatureClass.CreateFeatureBuffer();

                                        IPointCollection wayPointCollection = null;
                                        wayIsLine = IsThisWayALine(currentWay);

                                        if (wayIsLine)
                                        {

                                            // check if a feature with the same OSMID already exists, because the can only be one
                                            if (checkForExisting == true)
                                            {
                                                if (CheckIfExists(osmLineFeatureClass as ITable, currentWay.id))
                                                {
                                                    continue;
                                                }
                                            }

                                            IPolyline wayPolyline = new PolylineClass();
                                            comReleaser.ManageLifetime(wayPointCollection);

                                            wayPolyline.SpatialReference = downloadSpatialReference;

                                            IPointIDAware polylineIDAware = wayPolyline as IPointIDAware;
                                            polylineIDAware.PointIDAware = true;

                                            wayPointCollection = wayPolyline as IPointCollection;

                                            # region generate line geometry
                                            if (conserveMemory == false)
                                            {
                                                for (int ndIndex = 0; ndIndex < currentWay.nd.Length; ndIndex++)
                                                {
                                                    string ndID = currentWay.nd[ndIndex].@ref;
                                                    if (osmNodeDictionary.ContainsKey(ndID))
                                                    {
                                                        IPoint newPoint = new PointClass();
                                                        newPoint.X = osmNodeDictionary[ndID].Longitude;
                                                        newPoint.Y = osmNodeDictionary[ndID].Latitude;

                                                        newPoint.SpatialReference = wgs84;

                                                        if (shouldProject)
                                                        {
                                                            newPoint.Project(((IGeoDataset)osmLineFeatureClass).SpatialReference);
                                                        }

                                                        IPointIDAware idAware = newPoint as IPointIDAware;
                                                        idAware.PointIDAware = true;

                                                        newPoint.ID = osmNodeDictionary[ndID].pointObjectID;

                                                        wayPointCollection.AddPoint(newPoint, ref missingValue, ref missingValue);

                                                        osmNodeDictionary[ndID].RefCounter = osmNodeDictionary[ndID].RefCounter + 1;
                                                    }
                                                    else
                                                    {
                                                        message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_undeterminedline_node"), currentWay.id, ndID));
                                                        // set the flag that the way is complete due to a missing node
                                                        wayIsComplete = false;
                                                        break;
                                                    }
                                                }

                                            }
                                            else
                                            {
                                                for (int pointIndex = 0; pointIndex < currentWay.nd.Length; pointIndex++)
                                                {
                                                    wayPointCollection.AddPoint(new PointClass());
                                                }

                                                List<string> idRequests = SplitOSMIDRequests(currentWay, 2);

                                                // build a list of node ids we can use to determine the point index in the line geometry
                                                // as well as a dictionary to determine the position in the list in case of duplicates nodes
                                                Dictionary<string, int> nodePositionDictionary = new Dictionary<string, int>(currentWay.nd.Length);
                                                List<string> nodeIDs = new List<string>(currentWay.nd.Length);

                                                foreach (nd wayNode in currentWay.nd)
                                                {
                                                    nodeIDs.Add(wayNode.@ref);

                                                    if (nodePositionDictionary.ContainsKey(wayNode.@ref) == false)
                                                    {
                                                        nodePositionDictionary.Add(wayNode.@ref, 0);
                                                    }
                                                }

                                                try
                                                {
                                                    osmIDQueryFilter.SubFields = osmPointFeatureClass.ShapeFieldName + "," + osmPointFeatureClass.Fields.get_Field(osmPointIDFieldIndex).Name + "," + osmPointFeatureClass.Fields.get_Field(osmWayRefCountFieldIndex).Name;
                                                }
                                                catch
                                                { }

                                                foreach (string request in idRequests)
                                                {
                                                    string idCompareString = request;
                                                    osmIDQueryFilter.WhereClause = sqlPointOSMID + " IN " + request;
                                                    using (ComReleaser innerComReleaser = new ComReleaser())
                                                    {
                                                        updatePointCursor = osmPointFeatureClass.Update(osmIDQueryFilter, true);
                                                        innerComReleaser.ManageLifetime(updatePointCursor);

                                                        IFeature nodeFeature = updatePointCursor.NextFeature();

                                                        while (nodeFeature != null)
                                                        {
                                                            // determine the index of the point in with respect to the node position
                                                            string nodeOSMIDString = Convert.ToString(nodeFeature.get_Value(osmPointIDFieldIndex));

                                                            // remove the ID from the request string
                                                            idCompareString = idCompareString.Replace(nodeOSMIDString, String.Empty);

                                                            int nodePositionIndex = -1;

                                                            while ((nodePositionIndex = nodeIDs.IndexOf(nodeOSMIDString, nodePositionDictionary[nodeOSMIDString])) != -1)
                                                            {
                                                                //// update the new position start search index
                                                                nodePositionDictionary[nodeOSMIDString] = nodePositionIndex + 1;

                                                                wayPointCollection.UpdatePoint(nodePositionIndex, (IPoint)nodeFeature.Shape);

                                                                // increase the reference counter
                                                                if (osmWayRefCountFieldIndex != -1)
                                                                {
                                                                    nodeFeature.set_Value(osmWayRefCountFieldIndex, ((int)nodeFeature.get_Value(osmWayRefCountFieldIndex)) + 1);

                                                                    updatePointCursor.UpdateFeature(nodeFeature);
                                                                }
                                                            }

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

                                                            nodeFeature = updatePointCursor.NextFeature();
                                                        }

                                                        idCompareString = CleanReportedNodes(idCompareString);

                                                        // after removing the commas we should be left with only paranthesis left, meaning a string of length 2
                                                        // if we have more then we have found a missing node, resulting in an incomplete way geometry
                                                        if (idCompareString.Length > 2)
                                                        {
                                                            message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_undeterminedline_node"), currentWay.id, idCompareString));
                                                            wayIsComplete = false;
                                                        }
                                                    }
                                                }
                                            }
                                            #endregion

                                            if (wayIsComplete == false)
                                            {
                                                // if the way geometry is incomplete due to a missing node let's continue to the next way element
                                                missingWays.Add(currentWay.id);
                                                continue;
                                            }

                                            featureLineBuffer.Shape = wayPolyline;
                                            featureLineBuffer.set_Value(osmLineIDFieldIndex, currentWay.id);
                                        }
                                        else
                                        {
                                            // check if a feature with the same OSMID already exists, because the can only be one
                                            if (checkForExisting == true)
                                            {
                                                if (CheckIfExists(osmPolygonFeatureClass as ITable, currentWay.id))
                                                {
                                                    continue;
                                                }
                                            }

                                            IPolygon wayPolygon = new PolygonClass();
                                            comReleaser.ManageLifetime(wayPointCollection);

                                            wayPolygon.SpatialReference = downloadSpatialReference;

                                            IPointIDAware polygonIDAware = wayPolygon as IPointIDAware;
                                            polygonIDAware.PointIDAware = true;

                                            wayPointCollection = wayPolygon as IPointCollection;

                                            #region generate polygon geometry
                                            if (conserveMemory == false)
                                            {
                                                for (int ndIndex = 0; ndIndex < currentWay.nd.Length; ndIndex++)
                                                {
                                                    string ndID = currentWay.nd[ndIndex].@ref;
                                                    if (osmNodeDictionary.ContainsKey(ndID))
                                                    {
                                                        IPoint newPoint = new PointClass();
                                                        newPoint.X = osmNodeDictionary[ndID].Longitude;
                                                        newPoint.Y = osmNodeDictionary[ndID].Latitude;
                                                        newPoint.SpatialReference = wgs84;

                                                        if (shouldProject)
                                                        {
                                                            newPoint.Project(nativePolygonSpatialReference);
                                                        }

                                                        IPointIDAware idAware = newPoint as IPointIDAware;
                                                        idAware.PointIDAware = true;

                                                        newPoint.ID = osmNodeDictionary[ndID].pointObjectID;

                                                        wayPointCollection.AddPoint(newPoint, ref missingValue, ref missingValue);
                                                    }
                                                    else
                                                    {
                                                        message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_undeterminedpolygon_node"), currentWay.id, ndID));
                                                        wayIsComplete = false;
                                                        break;
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                for (int pointIndex = 0; pointIndex < currentWay.nd.Length; pointIndex++)
                                                {
                                                    wayPointCollection.AddPoint(new PointClass());
                                                }

                                                List<string> idRequests = SplitOSMIDRequests(currentWay, 2);

                                                // build a list of node ids we can use to determine the point index in the line geometry
                                                // as well as a dictionary to determine the position in the list in case of duplicates nodes
                                                Dictionary<string, int> nodePositionDictionary = new Dictionary<string, int>(currentWay.nd.Length);
                                                List<string> nodeIDs = new List<string>(currentWay.nd.Length);

                                                foreach (nd wayNode in currentWay.nd)
                                                {
                                                    nodeIDs.Add(wayNode.@ref);

                                                    if (nodePositionDictionary.ContainsKey(wayNode.@ref) == false)
                                                    {
                                                        nodePositionDictionary.Add(wayNode.@ref, 0);
                                                    }
                                                }

                                                try
                                                {
                                                    osmIDQueryFilter.SubFields = osmPointFeatureClass.ShapeFieldName + "," + osmPointFeatureClass.Fields.get_Field(osmPointIDFieldIndex).Name + "," + osmPointFeatureClass.Fields.get_Field(osmWayRefCountFieldIndex).Name;
                                                }
                                                catch
                                                { }

                                                foreach (string osmIDRequest in idRequests)
                                                {
                                                    string idCompareString = osmIDRequest;

                                                    using (ComReleaser innercomReleaser = new ComReleaser())
                                                    {
                                                        osmIDQueryFilter.WhereClause = sqlPointOSMID + " IN " + osmIDRequest;
                                                        updatePointCursor = osmPointFeatureClass.Update(osmIDQueryFilter, false);
                                                        innercomReleaser.ManageLifetime(updatePointCursor);

                                                        IFeature nodeFeature = updatePointCursor.NextFeature();

                                                        while (nodeFeature != null)
                                                        {
                                                            // determine the index of the point in with respect to the node position
                                                            string nodeOSMIDString = Convert.ToString(nodeFeature.get_Value(osmPointIDFieldIndex));

                                                            idCompareString = idCompareString.Replace(nodeOSMIDString, String.Empty);

                                                            int nodePositionIndex = nodeIDs.IndexOf(nodeOSMIDString, nodePositionDictionary[nodeOSMIDString]);

                                                            // update the new position start search index
                                                            nodePositionDictionary[nodeOSMIDString] = nodePositionIndex + 1;

                                                            wayPointCollection.UpdatePoint(nodePositionIndex, (IPoint)nodeFeature.Shape);

                                                            // increase the reference counter
                                                            if (osmWayRefCountFieldIndex != -1)
                                                            {
                                                                nodeFeature.set_Value(osmWayRefCountFieldIndex, ((int)nodeFeature.get_Value(osmWayRefCountFieldIndex)) + 1);

                                                                updatePointCursor.UpdateFeature(nodeFeature);
                                                            }

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

                                                            nodeFeature = updatePointCursor.NextFeature();
                                                        }

                                                        idCompareString = CleanReportedNodes(idCompareString);

                                                        if (idCompareString.Length > 2)
                                                        {
                                                            message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_undeterminedpolygon_node"), currentWay.id, idCompareString));
                                                            wayIsComplete = false;
                                                        }
                                                    }
                                                }
                                            }
                                            #endregion

                                            if (wayIsComplete == false)
                                            {
                                                continue;
                                            }

                                            // remove the last point as OSM considers them to be coincident
                                            wayPointCollection.RemovePoints(wayPointCollection.PointCount - 1, 1);
                                            ((IPolygon)wayPointCollection).Close();

                                            featurePolygonBuffer.Shape = (IPolygon)wayPointCollection;
                                            featurePolygonBuffer.set_Value(osmPolygonIDFieldIndex, currentWay.id);
                                        }

                                        if (wayIsLine)
                                        {
                                            insertTags(osmLineDomainAttributeFieldIndices, osmLineDomainAttributeFieldLength, tagCollectionPolylineFieldIndex, featureLineBuffer, currentWay.tag);
                                        }
                                        else
                                        {
                                            insertTags(osmPolygonDomainAttributeFieldIndices, osmPolygonDomainAttributeFieldLength, tagCollectionPolygonFieldIndex, featurePolygonBuffer, currentWay.tag);
                                        }

                                        // store the administrative attributes
                                        // user, uid, version, changeset, timestamp, visible
                                        if (fastLoad == false)
                                        {
                                            if (!String.IsNullOrEmpty(currentWay.user))
                                            {
                                                if (wayIsLine)
                                                {
                                                    if (osmUserPolylineFieldIndex != -1)
                                                    {
                                                        featureLineBuffer.set_Value(osmUserPolylineFieldIndex, currentWay.user);
                                                    }
                                                }
                                                else
                                                {
                                                    if (osmUserPolygonFieldIndex != -1)
                                                    {
                                                        featurePolygonBuffer.set_Value(osmUserPolygonFieldIndex, currentWay.user);
                                                    }
                                                }
                                            }

                                            if (!String.IsNullOrEmpty(currentWay.uid))
                                            {
                                                if (wayIsLine)
                                                {
                                                    if (osmUIDPolylineFieldIndex != -1)
                                                    {
                                                        featureLineBuffer.set_Value(osmUIDPolylineFieldIndex, Convert.ToInt32(currentWay.uid));
                                                    }
                                                }
                                                else
                                                {
                                                    if (osmUIDPolygonFieldIndex != -1)
                                                    {
                                                        featurePolygonBuffer.set_Value(osmUIDPolygonFieldIndex, Convert.ToInt32(currentWay.uid));
                                                    }
                                                }
                                            }

                                            if (wayIsLine)
                                            {
                                                if (osmVisiblePolylineFieldIndex != -1)
                                                {
                                                    featureLineBuffer.set_Value(osmVisiblePolylineFieldIndex, currentWay.visible.ToString());
                                                }
                                            }
                                            else
                                            {
                                                if (osmVisiblePolygonFieldIndex != -1)
                                                {
                                                    featurePolygonBuffer.set_Value(osmVisiblePolygonFieldIndex, currentWay.visible.ToString());
                                                }
                                            }

                                            if (!String.IsNullOrEmpty(currentWay.version))
                                            {
                                                if (wayIsLine)
                                                {
                                                    if (osmVersionPolylineFieldIndex != -1)
                                                    {
                                                        featureLineBuffer.set_Value(osmVersionPolylineFieldIndex, Convert.ToInt32(currentWay.version));
                                                    }
                                                }
                                                else
                                                {
                                                    if (osmVersionPolygonFieldIndex != -1)
                                                    {
                                                        featurePolygonBuffer.set_Value(osmVersionPolygonFieldIndex, Convert.ToInt32(currentWay.version));
                                                    }
                                                }
                                            }

                                            if (!String.IsNullOrEmpty(currentWay.changeset))
                                            {
                                                if (wayIsLine)
                                                {
                                                    if (osmChangesetPolylineFieldIndex != -1)
                                                    {
                                                        featureLineBuffer.set_Value(osmChangesetPolylineFieldIndex, Convert.ToInt32(currentWay.changeset));
                                                    }
                                                }
                                                else
                                                {
                                                    if (osmChangesetPolygonFieldIndex != -1)
                                                    {
                                                        featurePolygonBuffer.set_Value(osmChangesetPolygonFieldIndex, Convert.ToInt32(currentWay.changeset));
                                                    }
                                                }
                                            }

                                            if (!String.IsNullOrEmpty(currentWay.timestamp))
                                            {
                                                try
                                                {
                                                    if (wayIsLine)
                                                    {
                                                        if (osmTimeStampPolylineFieldIndex != -1)
                                                        {
                                                            featureLineBuffer.set_Value(osmTimeStampPolylineFieldIndex, Convert.ToDateTime(currentWay.timestamp));
                                                        }
                                                    }
                                                    else
                                                    {
                                                        if (osmTimeStampPolygonFieldIndex != -1)
                                                        {
                                                            featurePolygonBuffer.set_Value(osmTimeStampPolygonFieldIndex, Convert.ToDateTime(currentWay.timestamp));
                                                        }
                                                    }
                                                }
                                                catch (Exception ex)
                                                {
                                                    message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_invalidTimeFormat"), ex.Message));
                                                }
                                            }

                                            if (wayIsLine)
                                            {
                                                if (osmSupportingElementPolylineFieldIndex > -1)
                                                {
                                                    if (currentWay.tag == null)
                                                    {
                                                        featureLineBuffer.set_Value(osmSupportingElementPolylineFieldIndex, "yes");
                                                    }
                                                    else
                                                    {
                                                        featureLineBuffer.set_Value(osmSupportingElementPolylineFieldIndex, "no");
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                if (osmSupportingElementPolygonFieldIndex > -1)
                                                {
                                                    if (currentWay.tag == null)
                                                    {
                                                        featurePolygonBuffer.set_Value(osmSupportingElementPolygonFieldIndex, "yes");
                                                    }
                                                    else
                                                    {
                                                        featurePolygonBuffer.set_Value(osmSupportingElementPolygonFieldIndex, "no");
                                                    }
                                                }
                                            }
                                        } // fast load

                                        try
                                        {
                                            if (wayIsLine)
                                            {
                                                insertLineCursor.InsertFeature(featureLineBuffer);
                                                lineIndexRebuildRequired = true;
                                            }
                                            else
                                            {
                                                insertPolygonCursor.InsertFeature(featurePolygonBuffer);
                                                polygonIndexRebuildRequired = true;
                                            }

                                            wayCount = wayCount + 1;

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

                                            if ((wayCount % 50000) == 0)
                                            {
                                                message.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_waysloaded"), wayCount));
                                            }

                                        }
                                        catch (Exception ex)
                                        {
                                            message.AddWarning(ex.Message);
                                            message.AddWarning(currentwayString);
                                        }

                                    }
                                    catch (Exception ex)
                                    {
                                        System.Diagnostics.Debug.WriteLine(ex.Message);
                                        System.Diagnostics.Debug.WriteLine(ex.StackTrace);
                                    }
                                    finally
                                    {
                                        if (featureLineBuffer != null)
                                        {
                                            Marshal.ReleaseComObject(featureLineBuffer);

                                            if (featureLineBuffer != null)
                                                featureLineBuffer = null;
                                        }

                                        if (featurePolygonBuffer != null)
                                        {
                                            Marshal.ReleaseComObject(featurePolygonBuffer);

                                            if (featurePolygonBuffer != null)
                                                featurePolygonBuffer = null;
                                        }

                                        currentWay = null;
                                    }

                                    if (TrackCancel.Continue() == false)
                                    {
                                        insertPolygonCursor.Flush();
                                        if (polygonFeatureLoad != null)
                                        {
                                            polygonFeatureLoad.LoadOnlyMode = false;
                                        }

                                        insertLineCursor.Flush();
                                        if (lineFeatureLoad != null)
                                        {
                                            lineFeatureLoad.LoadOnlyMode = false;
                                        }

                                        return missingWays;
                                    }
                                }
                            }
                        }

                        osmFileXmlReader.Close();

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

                        message.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_waysloaded"), wayCount));

                        insertPolygonCursor.Flush();
                        if (polygonFeatureLoad != null)
                        {
                            polygonFeatureLoad.LoadOnlyMode = false;
                        }

                        insertLineCursor.Flush();
                        if (lineFeatureLoad != null)
                        {
                            lineFeatureLoad.LoadOnlyMode = false;
                        }
                    }
                }

                IGeoProcessor2 geoProcessor = new GeoProcessorClass();
                IGPUtilities3 gpUtilities3 = new GPUtilitiesClass();
                bool storedOriginal = geoProcessor.AddOutputsToMap;
                IVariantArray parameterArrary = null;
                IGeoProcessorResult2 gpResults2 = null;

                try
                {
                    geoProcessor.AddOutputsToMap = false;

                    if (lineIndexRebuildRequired)
                    {
                        IIndexes featureClassIndexes = osmLineFeatureClass.Indexes;
                        int indexPosition = -1;
                        featureClassIndexes.FindIndex("osmID_IDX", out indexPosition);

                        string fcLocation = GetLocationString(targetGPValue, osmLineFeatureClass);

                        if (indexPosition == -1)
                        {
                            message.AddMessage(_resourceManager.GetString("GPTools_buildinglineidx"));

                            // Addd index for osmid column
                            parameterArrary = CreateAddIndexParameterArray(fcLocation, "OSMID", "osmID_IDX", "UNIQUE", "");
                            gpResults2 = geoProcessor.Execute("AddIndex_management", parameterArrary, TrackCancel) as IGeoProcessorResult2;
                        }

                        if (wayCount > 100)
                        {
                            // in this case we are dealing with a file geodatabase
                            if (lineFeatureLoad == null)
                            {
                                UpdateSpatialGridIndex(TrackCancel, message, geoProcessor, fcLocation);
                            }
                        }
                    }

                    if (polygonIndexRebuildRequired)
                    {
                        IIndexes featureClassIndexes = osmPolygonFeatureClass.Indexes;
                        int indexPosition = -1;
                        featureClassIndexes.FindIndex("osmID_IDX", out indexPosition);

                        string fcLocation = GetLocationString(targetGPValue, osmPolygonFeatureClass);

                        if (indexPosition == -1)
                        {
                            message.AddMessage(_resourceManager.GetString("GPTools_buildingpolygonidx"));

                            IGPValue polygonFeatureClassGPValue = gpUtilities3.MakeGPValueFromObject(osmPolygonFeatureClass);

                            if (polygonFeatureClassGPValue != null)
                            {
                                // Addd index for osmid column
                                parameterArrary = CreateAddIndexParameterArray(fcLocation, "OSMID", "osmID_IDX", "UNIQUE", "");
                                gpResults2 = geoProcessor.Execute("AddIndex_management", parameterArrary, TrackCancel) as IGeoProcessorResult2;
                            }
                        }

                        if (wayCount > 100)
                        {
                            if (polygonFeatureLoad == null)
                            {
                                UpdateSpatialGridIndex(TrackCancel, message, geoProcessor, fcLocation);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    message.AddWarning(ex.Message);
                }
                finally
                {
                    geoProcessor.AddOutputsToMap = storedOriginal;

                    Marshal.FinalReleaseComObject(gpUtilities3);
                    Marshal.FinalReleaseComObject(geoProcessor);
                }
            }
            catch (Exception ex)
            {
                message.AddWarning(ex.Message);
            }
            finally
            {
                if (waySerializer != null)
                    waySerializer = null;

                if (osmFileXmlReader != null)
                    osmFileXmlReader = null;

                System.GC.Collect();
                System.GC.WaitForPendingFinalizers();
            }

            return missingWays;
        }
        private List<string> extractAllTags(ITable osmInputTable, IQueryFilter osmQueryFilter, int osmTagCollectionFieldIndex)
        {
            HashSet<string> listOfAllTags = new HashSet<string>();

            if (osmInputTable == null)
            {
                return listOfAllTags.ToList();
            }

            IWorkspace datasetWorkspace = ((IDataset)osmInputTable).Workspace;

            using (ComReleaser comReleaser = new ComReleaser())
            {
                if (osmQueryFilter == null)
                {
                    osmQueryFilter = new QueryFilterClass();
                }

                //osmQueryFilter.SubFields = osmInputTable.Fields.get_Field(osmTagCollectionFieldIndex).Name;

                ICursor osmCursor = osmInputTable.Search(osmQueryFilter, false);
                comReleaser.ManageLifetime(osmCursor);

                IRow osmRow = osmCursor.NextRow();
                comReleaser.ManageLifetime(osmRow);

                while (osmRow != null)
                {
                    ESRI.ArcGIS.OSM.OSMClassExtension.tag[] storedTags = null;

                    try
                    {
                        storedTags = _osmUtility.retrieveOSMTags(osmRow, osmTagCollectionFieldIndex, null);
                    }
                    catch
                    { }

                    if (storedTags != null)
                    {
                        foreach (tag tagItem in storedTags)
                        {
                            listOfAllTags.Add(tagItem.k);
                        }
                    }

                    osmRow = osmCursor.NextRow();
                }
            }

            // sort the tag name alphabetically
            IEnumerable<string> sortedTags = listOfAllTags.OrderBy(nameOfTag => nameOfTag);

            return sortedTags.ToList();
        }
        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());
                }
            }
        }
        private void ResolveNodeTag(TreeNode clickedTreeNode, out IRow localOSMFeature, out IRow serverOSMFeature)
        {
            conflictTag nodeConflictTag = clickedTreeNode.Tag as conflictTag;

            if (nodeConflictTag == null)
            {
                localOSMFeature = null;
                serverOSMFeature = null;
                return;
            }

            ITable currentRevisionTable = m_allRevisionTables[clickedTreeNode.Parent.Text];

            IFeatureWorkspace featureWorkspace = ((IDataset)currentRevisionTable).Workspace as IFeatureWorkspace;
            IFeatureClass localFeatureClass = featureWorkspace.OpenFeatureClass(nodeConflictTag.SourceFeatureClassName);

            IQueryFilter localQueryFilter = new QueryFilterClass();
            localQueryFilter.WhereClause = localFeatureClass.WhereClauseByExtensionVersion(nodeConflictTag.OSMID, "OSMID",localFeatureClass.OSMExtensionVersion());

            using (ESRI.ArcGIS.OSM.OSMClassExtension.ComReleaser comReleaser = new ESRI.ArcGIS.OSM.OSMClassExtension.ComReleaser())
            {

                IFeatureCursor localSearchCursor = localFeatureClass.Search(localQueryFilter, false);
                comReleaser.ManageLifetime(localSearchCursor);

                IFeature localFeature = localSearchCursor.NextFeature();
                localOSMFeature = localFeature as IRow;

            }

            IQueryFilter serverQueryFilter = new QueryFilterClass();
            serverQueryFilter.WhereClause = m_osmPointsFC.WhereClauseByExtensionVersion(nodeConflictTag.OSMID, "OSMID", m_osmPointsFC.OSMExtensionVersion());

            IFeatureCursor serverSearchCursor = null;
            IFeature serverFeature = null;

            using (ESRI.ArcGIS.OSM.OSMClassExtension.ComReleaser comReleaser = new ESRI.ArcGIS.OSM.OSMClassExtension.ComReleaser())
            {
                if (nodeConflictTag.SourceFeatureClassName.Contains("_osm_pt"))
                {
                    serverSearchCursor = m_osmPointsFC.Search(serverQueryFilter, false);
                    comReleaser.ManageLifetime(serverSearchCursor);
                }
                else if (nodeConflictTag.SourceFeatureClassName.Contains("_osm_ln"))
                {
                    serverSearchCursor = m_osmLinesFC.Search(serverQueryFilter, false);
                    comReleaser.ManageLifetime(serverSearchCursor);
                }
                else if (nodeConflictTag.SourceFeatureClassName.Contains("_osm_ply"))
                {
                    serverSearchCursor = m_osmPolygonFC.Search(serverQueryFilter, false);
                    comReleaser.ManageLifetime(serverSearchCursor);
                }
                else if (nodeConflictTag.SourceFeatureClassName.Contains("_osm_relation"))
                {
                }

                if (serverSearchCursor != null)
                {
                    serverFeature = serverSearchCursor.NextFeature();
                }
            }

            serverOSMFeature = serverFeature as IRow;
        }
        public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriSystem.ITrackCancel TrackCancel, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr, ESRI.ArcGIS.Geodatabase.IGPMessages message)
        {
            _message = message;

            // classes to carry out the basic client/server communication
            HttpWebResponse httpResponse = null;
            string changeSetID = "-1";
            IGPString baseURLGPString = new GPStringClass();
            ICursor searchCursor = null;

            IGPUtilities3 gpUtilities3 = new GPUtilitiesClass();

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

            IGPParameter userNameParameter = paramvalues.get_Element(in_userNameNumber) as IGPParameter;
            IGPString userNameGPValue = gpUtilities3.UnpackGPValue(userNameParameter) as IGPString;

            IHttpBasicGPValue userCredentialGPValue = new HttpBasicGPValue();

            if (userNameGPValue != null)
            {
                userCredentialGPValue.UserName = userNameGPValue.Value;
            }
            else
            {
                return;
            }

            IGPParameter passwordParameter = paramvalues.get_Element(in_passwordNumber) as IGPParameter;
            IGPStringHidden passwordGPValue = gpUtilities3.UnpackGPValue(passwordParameter) as IGPStringHidden;

            if (passwordGPValue != null)
            {
                userCredentialGPValue.PassWord = passwordGPValue.Value;
            }
            else
            {
                return;
            }

            ITable revisionTable = null;
            int secondsToTimeout = 10;

            try
            {
                UpdateMessages(paramvalues, envMgr, message);

                if ((message.MaxSeverity == esriGPMessageSeverity.esriGPMessageSeverityAbort) ||
                    (message.MaxSeverity == esriGPMessageSeverity.esriGPMessageSeverityError))
                {
                    message.AddMessages(message);
                    return;
                }

                IGPParameter baseURLParameter = paramvalues.get_Element(in_uploadURLNumber) as IGPParameter;
                baseURLGPString = gpUtilities3.UnpackGPValue(baseURLParameter) as IGPString;

                IGPParameter commentParameter = paramvalues.get_Element(in_uploadCommentNumber) as IGPParameter;
                IGPString uploadCommentGPString = gpUtilities3.UnpackGPValue(commentParameter) as IGPString;

                ISpatialReferenceFactory spatialReferenceFactory = new SpatialReferenceEnvironmentClass() as ISpatialReferenceFactory;
                m_wgs84 = spatialReferenceFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984) as ISpatialReference;

                System.Xml.Serialization.XmlSerializer serializer = null;
                serializer = new XmlSerializer(typeof(osm));

                osm createChangeSetOSM = new osm();
                string user_displayname = "";
                int userID = -1;

                // set the "default" value of the OSM server
                int maxElementsinChangeSet = 50000;

                HttpWebRequest httpClient = HttpWebRequest.Create(baseURLGPString.Value + "/api/capabilities") as HttpWebRequest;
                httpClient = OSMGPDownload.AssignProxyandCredentials(httpClient);
                SetBasicAuthHeader(httpClient, userCredentialGPValue.EncodedUserNamePassWord);
                httpClient.Timeout = secondsToTimeout * 1000;

                createChangeSetOSM.generator = m_Generator;
                createChangeSetOSM.version = "0.6";

                changeset createChangeSet = new changeset();
                createChangeSet.id = "0";
                createChangeSet.open = changesetOpen.@false;

                List<tag> changeSetTags = new List<tag>();

                tag createdByTag = new tag();
                createdByTag.k = "created_by";
                createdByTag.v = "ArcGIS Editor for OpenStreetMap";
                changeSetTags.Add(createdByTag);

                tag commentTag = new tag();
                commentTag.k = "comment";
                commentTag.v = uploadCommentGPString.Value;
                changeSetTags.Add(commentTag);

                createChangeSet.tag = changeSetTags.ToArray();
                createChangeSetOSM.Items = new object[] { createChangeSet };

                api apiCapabilities = null;

                // retrieve some server settings

                try
                {
                    httpResponse = httpClient.GetResponse() as HttpWebResponse;

                    osm osmCapabilities = null;

                    Stream stream = httpResponse.GetResponseStream();

                    XmlTextReader xmlReader = new XmlTextReader(stream);
                    osmCapabilities = serializer.Deserialize(xmlReader) as osm;
                    xmlReader.Close();

                    apiCapabilities = osmCapabilities.Items[0] as api;
                    httpResponse.Close();
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    message.AddWarning(ex.Message);
                }

                if (apiCapabilities != null)
                {
                    // read the timeout parameter
                    secondsToTimeout = Convert.ToInt32(apiCapabilities.timeout.seconds);
                    httpClient.Timeout = secondsToTimeout * 1000;

                    // update the setting of allowed features per changeset from the actual capabilities response
                    maxElementsinChangeSet = Convert.ToInt32(apiCapabilities.changesets.maximum_elements);
                }

                // retrieve some information about the user
                try
                {
                    httpClient = null;
                    httpClient = HttpWebRequest.Create(baseURLGPString.Value + "/api/0.6/user/details") as HttpWebRequest;
                    httpClient = OSMGPDownload.AssignProxyandCredentials(httpClient);
                    SetBasicAuthHeader(httpClient, userCredentialGPValue.EncodedUserNamePassWord);

                    httpResponse = httpClient.GetResponse() as HttpWebResponse;

                    osm osmCapabilities = null;

                    Stream stream = httpResponse.GetResponseStream();

                    XmlTextReader xmlReader = new XmlTextReader(stream);
                    osmCapabilities = serializer.Deserialize(xmlReader) as osm;
                    xmlReader.Close();
                    user userInformation = osmCapabilities.Items[0] as user;

                    if (userInformation != null)
                    {
                        user_displayname = userInformation.display_name;
                        userID = Convert.ToInt32(userInformation.id);
                    }
                }

                catch (ArgumentOutOfRangeException ex)
                {
                    message.AddError(120044, ex.Message);
                    return;
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    message.AddWarning(ex.Message);
                }

                IGPParameter revisionTableParameter = paramvalues.get_Element(in_changesTablesNumber) as IGPParameter;
                int featureUpdateCounter = 0;

                IQueryFilter revisionTableQueryFilter = null;

                try
                {
                    gpUtilities3.DecodeTableView(gpUtilities3.UnpackGPValue(revisionTableParameter), out revisionTable, out revisionTableQueryFilter);
                }
                catch
                {
                    message.AddError(120045,resourceManager.GetString("GPTools_OSMGPUpload_missingRevisionTable"));
                    return;
                }

                int revChangeSetIDFieldIndex = revisionTable.Fields.FindField("osmchangeset");
                int revActionFieldIndex = revisionTable.Fields.FindField("osmaction");
                int revElementTypeFieldIndex = revisionTable.Fields.FindField("osmelementtype");
                int revVersionFieldIndex = revisionTable.Fields.FindField("osmversion");
                int revFCNameFieldIndex = revisionTable.Fields.FindField("sourcefcname");
                int revOldIDFieldIndex = revisionTable.Fields.FindField("osmoldid");
                int revNewIDFieldIndex = revisionTable.Fields.FindField("osmnewid");
                int revStatusFieldIndex = revisionTable.Fields.FindField("osmstatus");
                int revStatusCodeFieldIndex = revisionTable.Fields.FindField("osmstatuscode");
                int revErrorMessageFieldIndex = revisionTable.Fields.FindField("osmerrormessage");
                int revLongitudeFieldIndex = revisionTable.Fields.FindField("osmlon");
                int revLatitudeFieldIndex = revisionTable.Fields.FindField("osmlat");

                // let's find all the rows that have a different status than OK - meaning success
                IQueryFilter queryFilter = new QueryFilterClass();

                searchCursor = revisionTable.Search(queryFilter, false);
                IRow searchRowToUpdate = null;

                // lookup table to adjust all osm ID references if there are know entities
                Dictionary<long, long> nodeosmIDLookup = new Dictionary<long, long>();
                Dictionary<long, long> wayosmIDLookup = new Dictionary<long, long>();
                Dictionary<long, long> relationosmIDLookup = new Dictionary<long, long>();

                // let's pre-populate the lookup IDs with already know entities
                // it is necessary if the revision table is used more than once and in different sessions
                queryFilter.WhereClause = "NOT " + revisionTable.SqlIdentifier("osmnewid") + " IS NULL";

                using (ComReleaser comReleaser = new ComReleaser())
                {
                    ICursor searchIDCursor = revisionTable.Search(queryFilter, false);
                    comReleaser.ManageLifetime(searchIDCursor);

                    IRow searchRow = searchIDCursor.NextRow();
                    comReleaser.ManageLifetime(searchRow);

                    while (searchRow != null)
                    {
                        if (revOldIDFieldIndex > -1 && revNewIDFieldIndex > -1)
                        {
                            string elementType = Convert.ToString(searchRow.get_Value(revElementTypeFieldIndex));

                            switch (elementType)
                            {
                                case "node":
                                    if (nodeosmIDLookup.ContainsKey(Convert.ToInt64(searchRow.get_Value(revOldIDFieldIndex))) == false)
                                    {
                                        nodeosmIDLookup.Add(Convert.ToInt64(searchRow.get_Value(revOldIDFieldIndex)), Convert.ToInt64(searchRow.get_Value(revNewIDFieldIndex)));
                                    }
                                    break;
                                case "way":
                                    if (wayosmIDLookup.ContainsKey(Convert.ToInt64(searchRow.get_Value(revOldIDFieldIndex))) == false)
                                    {
                                        wayosmIDLookup.Add(Convert.ToInt64(searchRow.get_Value(revOldIDFieldIndex)), Convert.ToInt64(searchRow.get_Value(revNewIDFieldIndex)));
                                    }
                                    break;
                                case "relation":
                                    if (relationosmIDLookup.ContainsKey(Convert.ToInt64(searchRow.get_Value(revOldIDFieldIndex))) == false)
                                    {
                                        relationosmIDLookup.Add(Convert.ToInt64(searchRow.get_Value(revOldIDFieldIndex)), Convert.ToInt64(searchRow.get_Value(revNewIDFieldIndex)));
                                    }
                                    break;
                                default:
                                    break;
                            }
                        }
                        searchRow = searchIDCursor.NextRow();
                    }
                }

                IFeatureClass pointFeatureClass = null;
                int pointOSMIDFieldIndex = -1;
                IFeatureClass lineFeatureClass = null;
                IFeatureClass polygonFeatureClass = null;
                ITable relationTable = null;

                int osmDelimiterPosition = ((IDataset)revisionTable).Name.IndexOf("_osm_");
                string osmBaseName = ((IDataset)revisionTable).Name.Substring(0, osmDelimiterPosition);

                IFeatureWorkspace osmFeatureWorkspace = ((IDataset)revisionTable).Workspace as IFeatureWorkspace;

                if (osmFeatureWorkspace != null)
                {
                    pointFeatureClass = osmFeatureWorkspace.OpenFeatureClass(osmBaseName + "_osm_pt");
                    pointOSMIDFieldIndex = pointFeatureClass.FindField("OSMID");
                    lineFeatureClass = osmFeatureWorkspace.OpenFeatureClass(osmBaseName + "_osm_ln");
                    polygonFeatureClass = osmFeatureWorkspace.OpenFeatureClass(osmBaseName + "_osm_ply");
                    relationTable = osmFeatureWorkspace.OpenTable(osmBaseName + "_osm_relation");
                }

                // determine version of extension
                int internalExtensionVersion = pointFeatureClass.OSMExtensionVersion();

                string sData = OsmRest.SerializeUtils.CreateXmlSerializable(createChangeSetOSM, serializer, Encoding.ASCII, "text/xml");
                HttpWebRequest httpClient2 = HttpWebRequest.Create(baseURLGPString.Value + "/api/0.6/changeset/create") as HttpWebRequest;
                httpClient2.Method = "PUT";
                httpClient2 = OSMGPDownload.AssignProxyandCredentials(httpClient2);
                SetBasicAuthHeader(httpClient2, userCredentialGPValue.EncodedUserNamePassWord);
                httpClient2.Timeout = secondsToTimeout * 1000;

                try
                {
                    Stream requestStream = httpClient2.GetRequestStream();
                    StreamWriter mywriter = new StreamWriter(requestStream);

                    mywriter.Write(sData);
                    mywriter.Close();

                    WebResponse clientResponse = httpClient2.GetResponse();
                    Stream readStream = clientResponse.GetResponseStream();
                    StreamReader streamReader = new StreamReader(readStream);
                    changeSetID = streamReader.ReadToEnd();
                    streamReader.Close();

                    message.AddMessage(String.Format(resourceManager.GetString("GPTools_OSMGPUpload_openChangeSet"), changeSetID));

                }
                catch (Exception ex)
                {
                    if (httpResponse != null)
                    {
                        if (httpResponse.StatusCode != System.Net.HttpStatusCode.OK)
                        {
                            foreach (var errorItem in httpResponse.Headers.GetValues("Error"))
                            {
                                message.AddError(120009, errorItem);
                            }

                            message.AddError(120009, httpResponse.StatusCode.ToString());
                            message.AddError(120009, ex.Message);
                        }
                    }
                    else
                    {
                        message.AddError(120047, ex.Message);
                    }

                    return;
                }

                IGPParameter uploadFormatParameter = paramvalues.get_Element(in_uploadFormatNumber) as IGPParameter;
                IGPBoolean useOSMChangeFormatGPValue = gpUtilities3.UnpackGPValue(uploadFormatParameter) as IGPBoolean;

                // Al Hack
                if (useOSMChangeFormatGPValue == null)
                {
                    useOSMChangeFormatGPValue = new GPBoolean();
                    useOSMChangeFormatGPValue.Value = false;
                }

                SQLFormatter sqlFormatter = new SQLFormatter(revisionTable);

                if (useOSMChangeFormatGPValue.Value == true)
                {
                    #region osmchange upload format

                    osmChange osmChangeDocument = new osmChange();
                    osmChangeDocument.generator = m_Generator;
                    osmChangeDocument.version = "0.6";

                    // xml elements to describe the changeset
                    create uploadCreates = null;
                    modify uploadModify = null;
                    delete uploadDelete = null;

                    // helper classes to keep track of elements entered into a changeset
                    List<object> listOfCreates = null;
                    List<object> listOfModifies = null;
                    List<object> listOfDeletes = null;

                    List<object> changeSetItems = new List<object>();

                    #region upload create actions
                    // loop through creates
                    queryFilter.WhereClause = "(" + sqlFormatter.SqlIdentifier("osmstatuscode") + " <> 200 OR "
                        + sqlFormatter.SqlIdentifier("osmstatus") + " IS NULL) AND "
                        + sqlFormatter.SqlIdentifier("osmaction") + " = 'create'";

                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        searchCursor = revisionTable.Search(queryFilter, false);
                        comReleaser.ManageLifetime(searchCursor);

                        searchRowToUpdate = searchCursor.NextRow();
                        comReleaser.ManageLifetime(searchRowToUpdate);

                        // if we have at least one entry with a create action, then add the 'create' element to the changeset representation
                        if (searchRowToUpdate != null)
                        {
                            uploadCreates = new create();
                            listOfCreates = new List<object>();
                        }

                        while (searchRowToUpdate != null)
                        {
                            try
                            {
                                if (TrackCancel.Continue() == false)
                                {
                                    closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                                    return;
                                }

                                string action = String.Empty;
                                if (revActionFieldIndex != -1)
                                {
                                    action = searchRowToUpdate.get_Value(revActionFieldIndex) as string;
                                }
                                string elementType = String.Empty;
                                if (revElementTypeFieldIndex != -1)
                                {
                                    elementType = searchRowToUpdate.get_Value(revElementTypeFieldIndex) as string;
                                }

                                string sourceFCName = String.Empty;
                                if (revFCNameFieldIndex != -1)
                                {
                                    sourceFCName = searchRowToUpdate.get_Value(revFCNameFieldIndex) as string;
                                }

                                long osmOldID = -1;
                                if (revOldIDFieldIndex != -1)
                                {
                                    osmOldID = Convert.ToInt64(searchRowToUpdate.get_Value(revOldIDFieldIndex));
                                }

                                // if the overall number of uploaded elements is too big for a single changeset we do need to split it up
                                // into multiple sets
                                if (featureUpdateCounter > 0 & (featureUpdateCounter % maxElementsinChangeSet) == 0)
                                {
                                    // add any outstanding creations to the changeset items
                                    if (listOfCreates != null && uploadCreates != null)
                                    {
                                        uploadCreates.Items = listOfCreates.ToArray();
                                        // in case there are any creates let's add them to the changeset document
                                        changeSetItems.Add(uploadCreates);
                                    }

                                    // add all the changeset items to the changeset document
                                    osmChangeDocument.Items = changeSetItems.ToArray();

                                    // submit changeset
                                    try
                                    {
                                        httpClient = HttpWebRequest.Create(baseURLGPString.Value + "/api/0.6/changeset/" + changeSetID + "/upload") as HttpWebRequest;
                                        httpClient = OSMGPDownload.AssignProxyandCredentials(httpClient);
                                        httpClient.Method = "POST";
                                        SetBasicAuthHeader(httpClient, userCredentialGPValue.EncodedUserNamePassWord);
                                        httpClient.Timeout = secondsToTimeout * 1000;

                                        string sContent = OsmRest.SerializeUtils.CreateXmlSerializable(osmChangeDocument, null, Encoding.UTF8, "text/xml");

                                        message.AddMessage(String.Format(resourceManager.GetString("GPTools_OSMGPUpload_featureSubmit"), featureUpdateCounter));

                                        OsmRest.HttpUtils.Post(httpClient, sContent);

                                        httpResponse = httpClient.GetResponse() as HttpWebResponse;
                                        diffResult diffResultResonse = OsmRest.HttpUtils.GetResponse(httpResponse);

                                        // parse changes locally and update local data sources
                                        if (diffResultResonse != null)
                                        {
                                            ParseResultDiff(diffResultResonse, revisionTable, pointFeatureClass, lineFeatureClass, polygonFeatureClass, relationTable, user_displayname, userID, changeSetID, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                        }

                                    }
                                    catch (Exception ex)
                                    {
                                        closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                                        message.AddError(120009, ex.Message);

                                        if (ex is WebException)
                                        {
                                            WebException webException = ex as WebException;
                                            string serverErrorMessage = webException.Response.Headers["Error"];
                                            if (!String.IsNullOrEmpty(serverErrorMessage))
                                            {
                                                message.AddError(120009, serverErrorMessage);
                                            }
                                        }

                                        if (httpResponse != null)
                                        {
                                            httpResponse.Close();
                                        }
                                        return;
                                    }
                                    finally
                                    {
                                        // reset the list and containers of modifications for the next batch
                                        listOfCreates.Clear();
                                        changeSetItems.Clear();

                                        if (httpResponse != null)
                                        {
                                            httpResponse.Close();
                                        }
                                    }

                                    if (TrackCancel.Continue() == false)
                                    {
                                        closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                                        return;
                                    }

                                    CreateNextChangeSet(message, createChangeSetOSM, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, ref changeSetID, baseURLGPString, ref featureUpdateCounter);
                                }

                                switch (elementType)
                                {
                                    case "node":
                                        node createNode = CreateNodeRepresentation(pointFeatureClass, action, osmOldID, changeSetID, 1, null, internalExtensionVersion);
                                        listOfCreates.Add(createNode);
                                        break;
                                    case "way":
                                        way createWay = null;
                                        if (sourceFCName.Contains("_osm_ln"))
                                        {
                                            createWay = CreateWayRepresentation(lineFeatureClass, action, osmOldID, changeSetID, 1, nodeosmIDLookup, pointFeatureClass, pointOSMIDFieldIndex, internalExtensionVersion);
                                        }
                                        else if (sourceFCName.Contains("_osm_ply"))
                                        {
                                            createWay = CreateWayRepresentation(polygonFeatureClass, action, osmOldID, changeSetID, 1, nodeosmIDLookup, pointFeatureClass, pointOSMIDFieldIndex, internalExtensionVersion);
                                        }
                                        listOfCreates.Add(createWay);
                                        break;
                                    case "relation":
                                        relation createRelation = null;
                                        if (sourceFCName.Contains("_osm_ln"))
                                        {
                                            createRelation = CreateRelationRepresentation((ITable)lineFeatureClass, action, osmOldID, changeSetID, 1, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                        }
                                        else if (sourceFCName.Contains("_osm_ply"))
                                        {
                                            createRelation = CreateRelationRepresentation((ITable)polygonFeatureClass, action, osmOldID, changeSetID, 1, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                        }
                                        else if (sourceFCName.Contains("_osm_relation"))
                                        {
                                            createRelation = CreateRelationRepresentation(relationTable, action, osmOldID, changeSetID, 1, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                        }
                                        listOfCreates.Add(createRelation);
                                        break;
                                    default:
                                        break;
                                }
                                // increment the counter keeping track of the submitted changes
                                featureUpdateCounter = featureUpdateCounter + 1;
                            }
                            catch
                            {
                            }
                            searchRowToUpdate = searchCursor.NextRow();
                        }

                        if (listOfCreates != null && uploadCreates != null)
                        {
                            // sort the list of created elements in the order of nodes, ways, relations
                            listOfCreates.Sort(new OSMElementComparer());

                            uploadCreates.Items = listOfCreates.ToArray();
                            // in case there are any creates let's add them to the changeset document
                            changeSetItems.Add(uploadCreates);
                        }
                    }
                    #endregion

                    #region upload modify actions
                    // loop through modifies
                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        queryFilter.WhereClause = "(" +
                            sqlFormatter.SqlIdentifier("osmstatuscode") + " <> 200 OR "
                            + sqlFormatter.SqlIdentifier("osmstatus") + " IS NULL) AND "
                            + sqlFormatter.SqlIdentifier("osmaction") + " = 'modify'";

                        searchCursor = revisionTable.Search(queryFilter, false);
                        comReleaser.ManageLifetime(searchCursor);

                        searchRowToUpdate = searchCursor.NextRow();

                        if (searchRowToUpdate != null)
                        {
                            uploadModify = new modify();
                            listOfModifies = new List<object>();
                        }

                        while (searchRowToUpdate != null)
                        {
                            if (TrackCancel.Continue() == false)
                            {
                                closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                                return;
                            }

                            try
                            {
                                string action = String.Empty;
                                if (revActionFieldIndex != -1)
                                {
                                    action = searchRowToUpdate.get_Value(revActionFieldIndex) as string;
                                }

                                string elementType = String.Empty;
                                if (revElementTypeFieldIndex != -1)
                                {
                                    elementType = searchRowToUpdate.get_Value(revElementTypeFieldIndex) as string;
                                }

                                string sourceFCName = String.Empty;
                                if (revFCNameFieldIndex != -1)
                                {
                                    sourceFCName = searchRowToUpdate.get_Value(revFCNameFieldIndex) as string;
                                }

                                long osmOldID = -1;
                                if (revOldIDFieldIndex != -1)
                                {
                                    osmOldID = Convert.ToInt64(searchRowToUpdate.get_Value(revOldIDFieldIndex));
                                }

                                // if the overall number of uploaded elements is too big for a single changeset we do need to split it up
                                long modifyID = -1;
                                if (revNewIDFieldIndex != -1)
                                {
                                    object osmIDValue = searchRowToUpdate.get_Value(revNewIDFieldIndex);

                                    if (osmIDValue == DBNull.Value)
                                    {
                                        osmIDValue = osmOldID;
                                    }

                                    try
                                    {
                                        modifyID = Convert.ToInt64(osmIDValue);
                                    }
                                    catch { }

                                    // modifies should only happen to osm IDs > 0
                                    // if that condition is not met let's skip this feature as something is not right
                                    if (modifyID < 0)
                                    {
                                        searchRowToUpdate = searchCursor.NextRow();
                                        continue;
                                    }
                                }

                                int osmVersion = -1;
                                if (revVersionFieldIndex != -1)
                                {
                                    osmVersion = Convert.ToInt32(searchRowToUpdate.get_Value(revVersionFieldIndex));
                                }

                                // into multiple sets
                                if ((featureUpdateCounter % maxElementsinChangeSet) == 0)
                                {
                                    // add any outstanding modifications to the changeset items
                                    if (listOfModifies != null && uploadModify != null)
                                    {
                                        uploadModify.Items = listOfModifies.ToArray();
                                        // in case there are any creates let's add them to the changeset document
                                        changeSetItems.Add(uploadModify);
                                    }

                                    // add all the changeset items to the changeset document
                                    osmChangeDocument.Items = changeSetItems.ToArray();

                                    // submit changeset
                                    try
                                    {
                                        httpClient = HttpWebRequest.Create(baseURLGPString.Value + "/api/0.6/changeset/" + changeSetID + "/upload") as HttpWebRequest;
                                        httpClient = OSMGPDownload.AssignProxyandCredentials(httpClient);
                                        httpClient.Method = "POST";
                                        SetBasicAuthHeader(httpClient, userCredentialGPValue.EncodedUserNamePassWord);
                                        httpClient.Timeout = secondsToTimeout * 1000;

                                        string sContent = OsmRest.SerializeUtils.CreateXmlSerializable(osmChangeDocument, null, Encoding.UTF8, "text/xml");
                                        OsmRest.HttpUtils.Post(httpClient, sContent);

                                        httpResponse = httpClient.GetResponse() as HttpWebResponse;
                                        diffResult diffResultResonse = OsmRest.HttpUtils.GetResponse(httpResponse);

                                        // parse changes locally and update local data sources
                                        if (diffResultResonse != null)
                                        {
                                            ParseResultDiff(diffResultResonse, revisionTable, pointFeatureClass, lineFeatureClass, polygonFeatureClass, relationTable, user_displayname, userID, changeSetID, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                        }

                                    }
                                    catch (Exception ex)
                                    {
                                        closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                                        message.AddError(120009, ex.Message);

                                        if (ex is WebException)
                                        {
                                            WebException webException = ex as WebException;
                                            string serverErrorMessage = webException.Response.Headers["Error"];
                                            if (!String.IsNullOrEmpty(serverErrorMessage))
                                            {
                                                message.AddError(120009, serverErrorMessage);
                                            }

                                            if (httpResponse != null)
                                            {
                                                httpResponse.Close();
                                            }
                                        }
                                        return;
                                    }
                                    finally
                                    {
                                        // reset the list and containers of modifications for the next batch
                                        listOfModifies.Clear();
                                        changeSetItems.Clear();

                                        if (httpResponse != null)
                                        {
                                            httpResponse.Close();
                                        }
                                    }

                                    if (TrackCancel.Continue() == false)
                                    {
                                        closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                                        return;
                                    }

                                    CreateNextChangeSet(message, createChangeSetOSM, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, ref changeSetID, baseURLGPString, ref featureUpdateCounter);
                                }

                                switch (elementType)
                                {
                                    case "node":
                                        node updateNode = CreateNodeRepresentation(pointFeatureClass, action, modifyID, changeSetID, osmVersion, null, internalExtensionVersion);
                                        listOfModifies.Add(updateNode);
                                        break;
                                    case "way":
                                        way updateWay = null;
                                        if (sourceFCName.Contains("_osm_ln"))
                                        {
                                            updateWay = CreateWayRepresentation(lineFeatureClass, action, modifyID, changeSetID, osmVersion, nodeosmIDLookup, pointFeatureClass, pointOSMIDFieldIndex, internalExtensionVersion);
                                        }
                                        else if (sourceFCName.Contains("_osm_ply"))
                                        {
                                            updateWay = CreateWayRepresentation(polygonFeatureClass, action, modifyID, changeSetID, osmVersion, nodeosmIDLookup, pointFeatureClass, pointOSMIDFieldIndex, internalExtensionVersion);
                                        }
                                        listOfModifies.Add(updateWay);
                                        break;
                                    case "relation":
                                        relation updateRelation = null;
                                        if (sourceFCName.Contains("_osm_ln"))
                                        {
                                            updateRelation = CreateRelationRepresentation((ITable)lineFeatureClass, action, modifyID, changeSetID, osmVersion, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                        }
                                        else if (sourceFCName.Contains("_osm_ply"))
                                        {
                                            updateRelation = CreateRelationRepresentation((ITable)polygonFeatureClass, action, modifyID, changeSetID, osmVersion, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                        }
                                        else if (sourceFCName.Contains("_osm_relation"))
                                        {
                                            updateRelation = CreateRelationRepresentation(relationTable, action, modifyID, changeSetID, osmVersion, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                        }
                                        listOfModifies.Add(updateRelation);
                                        break;
                                    default:
                                        break;
                                }

                                // track the update/sync requests against the server
                                featureUpdateCounter = featureUpdateCounter + 1;
                            }
                            catch
                            {
                            }

                            searchRowToUpdate = searchCursor.NextRow();
                        }

                        if (listOfModifies != null && uploadModify != null)
                        {
                            uploadModify.Items = listOfModifies.ToArray();
                            // in case there are any creates let's add them to the changeset document
                            changeSetItems.Add(uploadModify);
                        }

                    }
                    #endregion

                    #region upload delete actions
                    // loop through deletes in "reverse" - relation, then way, then node
                    string[] elementTypes = new string[] { "relation", "way", "node" };

                    foreach (string osmElementType in elementTypes)
                    {
                        using (ComReleaser comReleaser = new ComReleaser())
                        {
                            queryFilter.WhereClause = "(" +  sqlFormatter.SqlIdentifier("osmstatuscode") + " <> 200 OR "
                                + sqlFormatter.SqlIdentifier("osmstatus") + " IS NULL) AND "
                                + sqlFormatter.SqlIdentifier("osmaction") + " = 'delete' AND "
                                + sqlFormatter.SqlIdentifier("osmelementtype") + " = '" + osmElementType + "'";

                            searchCursor = revisionTable.Search(queryFilter, false);
                            comReleaser.ManageLifetime(searchCursor);

                            searchRowToUpdate = searchCursor.NextRow();

                            if (searchRowToUpdate != null)
                            {
                                if (TrackCancel.Continue() == false)
                                {
                                    closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                                    return;
                                }

                                if (uploadDelete == null)
                                {
                                    uploadDelete = new delete();
                                    listOfDeletes = new List<object>();
                                }
                            }

                            while (searchRowToUpdate != null)
                            {
                                try
                                {
                                    string action = String.Empty;
                                    if (revActionFieldIndex != -1)
                                    {
                                        action = searchRowToUpdate.get_Value(revActionFieldIndex) as string;
                                    }

                                    string elementType = String.Empty;
                                    if (revElementTypeFieldIndex != -1)
                                    {
                                        elementType = searchRowToUpdate.get_Value(revElementTypeFieldIndex) as string;
                                    }

                                    string sourceFCName = String.Empty;
                                    if (revFCNameFieldIndex != -1)
                                    {
                                        sourceFCName = searchRowToUpdate.get_Value(revFCNameFieldIndex) as string;
                                    }

                                    long osmOldID = -1;
                                    if (revOldIDFieldIndex != -1)
                                    {
                                        osmOldID = Convert.ToInt64(searchRowToUpdate.get_Value(revOldIDFieldIndex));
                                    }

                                    int osmVersion = -1;
                                    if (revVersionFieldIndex != -1)
                                    {
                                        osmVersion = Convert.ToInt32(searchRowToUpdate.get_Value(revVersionFieldIndex));
                                    }

                                    // into multiple sets
                                    if ((featureUpdateCounter % maxElementsinChangeSet) == 0)
                                    {
                                        // add any outstanding creations to the changeset items
                                        if (listOfDeletes != null && uploadDelete != null)
                                        {
                                            uploadDelete.Items = listOfDeletes.ToArray();
                                            // in case there are any creates let's add them to the changeset document
                                            changeSetItems.Add(uploadDelete);
                                        }

                                        // add all the changeset items to the changeset document
                                        osmChangeDocument.Items = changeSetItems.ToArray();

                                        // submit changeset
                                        try
                                        {
                                            httpClient = HttpWebRequest.Create(baseURLGPString.Value + "/api/0.6/changeset/" + changeSetID + "/upload") as HttpWebRequest;
                                            httpClient = OSMGPDownload.AssignProxyandCredentials(httpClient);
                                            httpClient.Method = "POST";
                                            SetBasicAuthHeader(httpClient, userCredentialGPValue.EncodedUserNamePassWord);
                                            httpClient.Timeout = secondsToTimeout * 1000;

                                            string sContent = OsmRest.SerializeUtils.CreateXmlSerializable(osmChangeDocument, null, Encoding.UTF8, "text/xml");
                                            OsmRest.HttpUtils.Post(httpClient, sContent);

                                            httpResponse = httpClient.GetResponse() as HttpWebResponse;
                                            diffResult diffResultResonse = OsmRest.HttpUtils.GetResponse(httpResponse);

                                            // parse changes locally and update local data sources
                                            if (diffResultResonse != null)
                                            {
                                                ParseResultDiff(diffResultResonse, revisionTable, pointFeatureClass, lineFeatureClass, polygonFeatureClass, relationTable, user_displayname, userID, changeSetID, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                            }

                                        }
                                        catch (Exception ex)
                                        {
                                            closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                                            message.AddError(120009, ex.Message);

                                            if (ex is WebException)
                                            {
                                                WebException webException = ex as WebException;
                                                string serverErrorMessage = webException.Response.Headers["Error"];
                                                if (!String.IsNullOrEmpty(serverErrorMessage))
                                                {
                                                    message.AddError(120009, serverErrorMessage);
                                                }
                                            }

                                            if (httpResponse != null)
                                            {
                                                httpResponse.Close();
                                            }

                                            return;
                                        }
                                        finally
                                        {
                                            // reset the list and containers of modifications for the next batch
                                            listOfDeletes.Clear();
                                            changeSetItems.Clear();

                                            if (httpResponse != null)
                                            {
                                                httpResponse.Close();
                                            }
                                        }

                                        if (TrackCancel.Continue() == false)
                                        {
                                            closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                                            return;
                                        }

                                        CreateNextChangeSet(message, createChangeSetOSM, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, ref changeSetID, baseURLGPString, ref featureUpdateCounter);
                                    }

                                    switch (elementType)
                                    {
                                        case "node":
                                            IPoint deletePoint = null;
                                            if (revLongitudeFieldIndex != -1 && revLatitudeFieldIndex != -1)
                                            {
                                                try
                                                {
                                                    // let's reconstruct the delete point
                                                    deletePoint = new PointClass();
                                                    deletePoint.X = Convert.ToDouble(searchRowToUpdate.get_Value(revLongitudeFieldIndex));
                                                    deletePoint.Y = Convert.ToDouble(searchRowToUpdate.get_Value(revLatitudeFieldIndex));
                                                    deletePoint.SpatialReference = m_wgs84;
                                                }
                                                catch (Exception ex)
                                                {
                                                    message.AddWarning(ex.Message);
                                                }

                                                if (deletePoint == null)
                                                {
                                                    // inform the about the issue - no successful creation of point and continue on to the next delete instruction
                                                    // in the revision table
                                                    message.AddWarning(resourceManager.GetString("GPTools_OSMGPUpload_invalidPoint"));
                                                    searchRowToUpdate = searchCursor.NextRow();
                                                    continue;
                                                }
                                            }

                                            node deleteNode = CreateNodeRepresentation(pointFeatureClass, action, osmOldID, changeSetID, osmVersion, deletePoint, internalExtensionVersion);
                                            listOfDeletes.Add(deleteNode);
                                            break;
                                        case "way":
                                            way deleteWay = null;
                                            if (sourceFCName.Contains("_osm_ln"))
                                            {
                                                deleteWay = CreateWayRepresentation(lineFeatureClass, action, osmOldID, changeSetID, osmVersion, nodeosmIDLookup, pointFeatureClass, pointOSMIDFieldIndex, internalExtensionVersion);
                                            }
                                            else if (sourceFCName.Contains("_osm_ply"))
                                            {
                                                deleteWay = CreateWayRepresentation(polygonFeatureClass, action, osmOldID, changeSetID, osmVersion, nodeosmIDLookup, pointFeatureClass, pointOSMIDFieldIndex, internalExtensionVersion);
                                            }
                                            listOfDeletes.Add(deleteWay);
                                            break;
                                        case "relation":
                                            relation deleteRelation = null;
                                            if (sourceFCName.Contains("_osm_ln"))
                                            {
                                                deleteRelation = CreateRelationRepresentation((ITable)lineFeatureClass, action, osmOldID, changeSetID, osmVersion, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                            }
                                            else if (sourceFCName.Contains("_osm_ply"))
                                            {
                                                deleteRelation = CreateRelationRepresentation((ITable)polygonFeatureClass, action, osmOldID, changeSetID, osmVersion, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                            }
                                            else if (sourceFCName.Contains("_osm_relation"))
                                            {
                                                deleteRelation = CreateRelationRepresentation(relationTable, action, osmOldID, changeSetID, osmVersion, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                            }
                                            listOfDeletes.Add(deleteRelation);
                                            break;
                                        default:
                                            break;
                                    }

                                    // track the update/sync requests against the server
                                    featureUpdateCounter = featureUpdateCounter + 1;
                                }
                                catch
                                {
                                }

                                searchRowToUpdate = searchCursor.NextRow();
                            }

                        }
                    }

                    if (listOfDeletes != null && uploadDelete != null)
                    {
                        uploadDelete.Items = listOfDeletes.ToArray();
                        // in case there are any creates let's add them to the changeset document
                        changeSetItems.Add(uploadDelete);
                    }
                    #endregion

                    if (TrackCancel.Continue() == false)
                    {
                        closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                        return;
                    }

                    // add all the changeset items to the changeset document
                    osmChangeDocument.Items = changeSetItems.ToArray();

                    // submit changeset
                    try
                    {
                        httpClient = HttpWebRequest.Create(baseURLGPString.Value + "/api/0.6/changeset/" + changeSetID + "/upload") as HttpWebRequest;
                        httpClient = OSMGPDownload.AssignProxyandCredentials(httpClient);
                        httpClient.Method = "POST";
                        SetBasicAuthHeader(httpClient, userCredentialGPValue.EncodedUserNamePassWord);
                        httpClient.Timeout = secondsToTimeout * 1000;

                        message.AddMessage(String.Format(resourceManager.GetString("GPTools_OSMGPUpload_featureSubmit"), featureUpdateCounter));

                        string sContent = OsmRest.SerializeUtils.CreateXmlSerializable(osmChangeDocument, null, Encoding.UTF8, "text/xml");
                        OsmRest.HttpUtils.Post(httpClient, sContent);

                        httpResponse = httpClient.GetResponse() as HttpWebResponse;

                        //Exception with an error HTTP 400
                        diffResult diffResultResonse = OsmRest.HttpUtils.GetResponse(httpResponse);

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

                        // parse changes locally and update local data sources
                        if (diffResultResonse != null)
                        {
                            ParseResultDiff(diffResultResonse, revisionTable, pointFeatureClass, lineFeatureClass, polygonFeatureClass, relationTable, user_displayname, userID, changeSetID, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                        }
                    }
                    catch (Exception ex)
                    {
                        message.AddError(120009, ex.Message);

                        try
                        {
                            if (ex is WebException)
                            {
                                WebException webException = ex as WebException;
                                string serverErrorMessage = webException.Response.Headers["Error"];
                                if (!String.IsNullOrEmpty(serverErrorMessage))
                                {
                                    message.AddError(120009, serverErrorMessage);
                                }
                            }
                        }
                        catch (Exception innerexception)
                        {
                            message.AddError(120009, innerexception.Message);
                        }
                    }
                    finally
                    {
                        if (httpResponse != null)
                        {
                            httpResponse.Close();
                        }
                    }
                    #endregion
                }
                else
                {
                    #region single upload format
                    #region submit the create nodes first
                    queryFilter.WhereClause = "(" +
                        sqlFormatter.SqlIdentifier("osmstatuscode") + " <> 200 OR "
                        + sqlFormatter.SqlIdentifier("osmstatus") + " IS NULL) AND "
                        + sqlFormatter.SqlIdentifier("osmaction") + " = 'create'  AND "
                        + sqlFormatter.SqlIdentifier("osmelementtype") + " = 'node'";

                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        searchCursor = revisionTable.Search(queryFilter, false);
                        comReleaser.ManageLifetime(searchCursor);

                        while ((searchRowToUpdate = searchCursor.NextRow()) != null)
                        {
                            try
                            {
                                string action = String.Empty;
                                if (revActionFieldIndex != -1)
                                {
                                    action = searchRowToUpdate.get_Value(revActionFieldIndex) as string;
                                }
                                string elementType = String.Empty;
                                if (revElementTypeFieldIndex != -1)
                                {
                                    elementType = searchRowToUpdate.get_Value(revElementTypeFieldIndex) as string;
                                }

                                string sourceFCName = String.Empty;
                                if (revFCNameFieldIndex != -1)
                                {
                                    sourceFCName = searchRowToUpdate.get_Value(revFCNameFieldIndex) as string;
                                }

                                long osmOldID = -1;
                                if (revOldIDFieldIndex != -1)
                                {
                                    osmOldID = Convert.ToInt64(searchRowToUpdate.get_Value(revOldIDFieldIndex));
                                }

                                // if the overall number of uploaded elements is too big for a single changeset we do need to split it up
                                // into multiple sets
                                if ((featureUpdateCounter % maxElementsinChangeSet) == 0)
                                {
                                    CreateNextChangeSet(message, createChangeSetOSM, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, ref changeSetID, baseURLGPString, ref featureUpdateCounter);
                                }

                                osm createNode = CreateOSMNodeRepresentation(pointFeatureClass, action, osmOldID, changeSetID, -1, null, internalExtensionVersion);

                                httpClient = null;
                                httpClient = HttpWebRequest.Create(baseURLGPString.Value + "/api/0.6/" + elementType + "/create") as HttpWebRequest;
                                httpClient = OSMGPDownload.AssignProxyandCredentials(httpClient);
                                httpClient.Method = "PUT";
                                SetBasicAuthHeader(httpClient, userCredentialGPValue.EncodedUserNamePassWord);
                                httpClient.Timeout = secondsToTimeout * 1000;

                                httpResponse = null;

                                string nodeContent = OsmRest.SerializeUtils.CreateXmlSerializable(createNode, serializer, Encoding.UTF8, "text/xml");

                                if (String.IsNullOrEmpty(nodeContent))
                                {
                                    continue;
                                }

                                OsmRest.HttpUtils.Put(httpClient, nodeContent);

                                httpResponse = httpClient.GetResponse() as HttpWebResponse;

                                createNode = null;

                                // track the update/sync requests against the server
                                featureUpdateCounter = featureUpdateCounter + 1;

                                if (httpResponse != null)
                                {
                                    string newIDString = OsmRest.HttpUtils.GetResponseContent(httpResponse);

                                    nodeosmIDLookup.Add(osmOldID, Convert.ToInt64(newIDString));

                                    // update the revision table
                                    if (revNewIDFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revNewIDFieldIndex, Convert.ToString(newIDString));
                                    }
                                    if (revVersionFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revVersionFieldIndex, 1);
                                    }
                                    if (revStatusFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revStatusFieldIndex, httpResponse.StatusCode.ToString());
                                    }
                                    if (revStatusCodeFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revStatusCodeFieldIndex, (int)httpResponse.StatusCode);
                                    }
                                    if (revChangeSetIDFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revChangeSetIDFieldIndex, Convert.ToString(changeSetID));
                                    }

                                    // update the source point feature class as well
                                    updateSource((ITable)pointFeatureClass, action, osmOldID, Convert.ToInt64(newIDString), user_displayname, userID, 1, Convert.ToInt32(changeSetID), nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup,internalExtensionVersion);
                                }
                            }
                            catch (Exception ex)
                            {

                                message.AddError(120009, ex.Message);

                                if (ex is WebException)
                                {
                                    updateErrorStatus(message, revStatusFieldIndex, revStatusCodeFieldIndex, revErrorMessageFieldIndex, ref searchRowToUpdate, ex);
                                }
                            }
                            finally
                            {
                                try
                                {
                                    searchRowToUpdate.Store();
                                }
                                catch (Exception ex)
                                {
                                    System.Diagnostics.Debug.WriteLine(ex.Message);
                                }

                                if (httpResponse != null)
                                {
                                    httpResponse.Close();
                                }
                            }

                            if (TrackCancel.Continue() == false)
                            {
                                closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                                return;
                            }
                        }
                    }
                    #endregion

                    #region next the create ways
                    queryFilter.WhereClause = "(" +
                        sqlFormatter.SqlIdentifier("osmstatuscode") + " <> 200 OR "
                        + sqlFormatter.SqlIdentifier("osmstatus") + " IS NULL) AND "
                        + sqlFormatter.SqlIdentifier("osmaction") + " = 'create'  AND "
                        + sqlFormatter.SqlIdentifier("osmelementtype") + " = 'way'";

                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        searchCursor = revisionTable.Search(queryFilter, false);
                        comReleaser.ManageLifetime(searchCursor);

                        while ((searchRowToUpdate = searchCursor.NextRow()) != null)
                        {
                            try
                            {
                                string action = String.Empty;
                                if (revActionFieldIndex != -1)
                                {
                                    action = searchRowToUpdate.get_Value(revActionFieldIndex) as string;
                                }
                                string elementType = String.Empty;
                                if (revElementTypeFieldIndex != -1)
                                {
                                    elementType = searchRowToUpdate.get_Value(revElementTypeFieldIndex) as string;
                                }

                                string sourceFCName = String.Empty;
                                if (revFCNameFieldIndex != -1)
                                {
                                    sourceFCName = searchRowToUpdate.get_Value(revFCNameFieldIndex) as string;
                                }

                                long osmOldID = -1;
                                if (revOldIDFieldIndex != -1)
                                {
                                    osmOldID = Convert.ToInt64(searchRowToUpdate.get_Value(revOldIDFieldIndex));
                                }

                                bool isPolygon = false;
                                if (sourceFCName.IndexOf("_osm_ply") > -1)
                                {
                                    isPolygon = true;
                                }

                                // if the overall number of uploaded elements is too big for a single changeset we do need to split it up
                                // into multiple sets
                                if ((featureUpdateCounter % maxElementsinChangeSet) == 0)
                                {
                                    CreateNextChangeSet(message, createChangeSetOSM, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, ref changeSetID, baseURLGPString, ref featureUpdateCounter);
                                }

                                osm createWay = new osm();
                                if (isPolygon == false)
                                {
                                    createWay = CreateOSMWayRepresentation(lineFeatureClass, action, osmOldID, changeSetID, -1, nodeosmIDLookup, pointFeatureClass, pointOSMIDFieldIndex, internalExtensionVersion);
                                }
                                else
                                {
                                    createWay = CreateOSMWayRepresentation(polygonFeatureClass, action, osmOldID, changeSetID, -1, nodeosmIDLookup, pointFeatureClass, pointOSMIDFieldIndex, internalExtensionVersion);
                                }

                                try
                                {
                                    HttpWebRequest httpClient3 = HttpWebRequest.Create(baseURLGPString.Value + "/api/0.6/" + elementType + "/create") as HttpWebRequest;
                                    httpClient3 = OSMGPDownload.AssignProxyandCredentials(httpClient3);
                                    httpClient3.Method = "PUT";
                                    SetBasicAuthHeader(httpClient3, userCredentialGPValue.EncodedUserNamePassWord);
                                    httpClient.Timeout = secondsToTimeout * 1000;

                                    string sContent = OsmRest.SerializeUtils.CreateXmlSerializable(createWay, serializer, Encoding.UTF8, "text/xml");
                                    OsmRest.HttpUtils.Put(httpClient3, sContent);
                                    createWay = null;

                                    httpResponse = null;
                                    httpResponse = httpClient3.GetResponse() as HttpWebResponse;

                                    // track the update/sync requests against the server
                                    featureUpdateCounter = featureUpdateCounter + 1;
                                }
                                catch (Exception ex)
                                {
                                    message.AddError(120009, ex.Message);

                                    if (ex is WebException)
                                    {
                                        updateErrorStatus(message, revStatusFieldIndex, revStatusCodeFieldIndex, revErrorMessageFieldIndex, ref searchRowToUpdate, ex);
                                    }
                                }

                                if (httpResponse != null)
                                {
                                    string newIDString = OsmRest.HttpUtils.GetResponseContent(httpResponse);

                                    wayosmIDLookup.Add(osmOldID, Convert.ToInt64(newIDString));

                                    // update the revision table
                                    if (revNewIDFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revNewIDFieldIndex, Convert.ToString(newIDString));
                                    }
                                    if (revVersionFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revVersionFieldIndex, 1);
                                    }
                                    if (revStatusFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revStatusFieldIndex, httpResponse.StatusCode.ToString());
                                    }
                                    if (revStatusCodeFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revStatusCodeFieldIndex, (int)httpResponse.StatusCode);
                                    }
                                    if (revChangeSetIDFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revChangeSetIDFieldIndex, Convert.ToString(changeSetID));
                                    }

                                    // update the source line/polygon feature class as well
                                    if (isPolygon == false)
                                    {
                                        updateSource((ITable)lineFeatureClass, action, osmOldID, Convert.ToInt64(newIDString), user_displayname, userID, 1, Convert.ToInt32(changeSetID), nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                    }
                                    else
                                    {
                                        updateSource((ITable)polygonFeatureClass, action, osmOldID, Convert.ToInt64(newIDString), user_displayname, userID, 1, Convert.ToInt32(changeSetID), nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                    }
                                }
                            }

                            catch (Exception ex)
                            {
                                message.AddError(120009, ex.Message);

                                if (ex is WebException)
                                {
                                    updateErrorStatus(message, revStatusFieldIndex, revStatusCodeFieldIndex, revErrorMessageFieldIndex, ref searchRowToUpdate, ex);
                                }
                            }
                            finally
                            {
                                try
                                {
                                    searchRowToUpdate.Store();
                                }
                                catch (Exception ex)
                                {
                                    System.Diagnostics.Debug.WriteLine(ex.Message);
                                }

                                if (httpResponse != null)
                                {
                                    httpResponse.Close();
                                }
                            }

                            if (TrackCancel.Continue() == false)
                            {
                                closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);

                                return;
                            }
                        }
                    }
                    #endregion

                    #region and then create relations
                    queryFilter.WhereClause = "(" +
                        sqlFormatter.SqlIdentifier("osmstatuscode") + " <> 200 OR "
                        + sqlFormatter.SqlIdentifier("osmstatus") + " IS NULL) AND "
                        + sqlFormatter.SqlIdentifier("osmaction") + " = 'create'  AND "
                        + sqlFormatter.SqlIdentifier("osmelementtype") + " = 'relation'";

                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        searchCursor = revisionTable.Search(queryFilter, false);
                        comReleaser.ManageLifetime(searchCursor);

                        while ((searchRowToUpdate = searchCursor.NextRow()) != null)
                        {
                            try
                            {

                                string action = String.Empty;
                                if (revActionFieldIndex != -1)
                                {
                                    action = searchRowToUpdate.get_Value(revActionFieldIndex) as string;
                                }
                                string elementType = String.Empty;
                                if (revElementTypeFieldIndex != -1)
                                {
                                    elementType = searchRowToUpdate.get_Value(revElementTypeFieldIndex) as string;
                                }

                                string sourceFCName = String.Empty;
                                if (revFCNameFieldIndex != -1)
                                {
                                    sourceFCName = searchRowToUpdate.get_Value(revFCNameFieldIndex) as string;
                                }

                                long osmOldID = -1;
                                if (revOldIDFieldIndex != -1)
                                {
                                    osmOldID = Convert.ToInt64(searchRowToUpdate.get_Value(revOldIDFieldIndex));
                                }

                                bool isPolygon = false;
                                if (sourceFCName.IndexOf("_osm_ply") > -1)
                                {
                                    isPolygon = true;
                                }

                                // if the overall number of uploaded elements is too big for a single changeset we do need to split it up
                                // into multiple sets
                                if ((featureUpdateCounter % maxElementsinChangeSet) == 0)
                                {
                                    CreateNextChangeSet(message, createChangeSetOSM, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, ref changeSetID, baseURLGPString, ref featureUpdateCounter);
                                }

                                osm createRelation = null;
                                // the relation is acutally multi-part line
                                if (sourceFCName.Contains("_osm_ln"))
                                {
                                    createRelation = CreateOSMRelationRepresentation((ITable)lineFeatureClass, action, osmOldID, changeSetID, -1, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                }
                                else if (sourceFCName.Contains("_osm_ply"))
                                {
                                    createRelation = CreateOSMRelationRepresentation((ITable)polygonFeatureClass, action, osmOldID, changeSetID, -1, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                }
                                else
                                {
                                    createRelation = CreateOSMRelationRepresentation(relationTable, action, osmOldID, changeSetID, -1, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                }
                                try
                                {
                                    HttpWebRequest httpClient4 = HttpWebRequest.Create(baseURLGPString.Value + "/api/0.6/" + elementType + "/create") as HttpWebRequest;
                                    httpClient4 = OSMGPDownload.AssignProxyandCredentials(httpClient4);
                                    SetBasicAuthHeader(httpClient4, userCredentialGPValue.EncodedUserNamePassWord);
                                    httpClient4.Timeout = secondsToTimeout * 1000;
                                    string sContent = OsmRest.SerializeUtils.CreateXmlSerializable(createRelation, serializer, Encoding.UTF8, "text/xml");

                                    OsmRest.HttpUtils.Put(httpClient4, sContent);

                                    httpResponse = null;
                                    httpResponse = httpClient4.GetResponse() as HttpWebResponse;
                                    // track the update/sync requests against the server
                                    featureUpdateCounter = featureUpdateCounter + 1;
                                }
                                catch (Exception ex)
                                {
                                    message.AddError(120009, ex.Message);

                                    if (ex is WebException)
                                    {
                                        updateErrorStatus(message, revStatusFieldIndex, revStatusCodeFieldIndex, revErrorMessageFieldIndex, ref searchRowToUpdate, ex);
                                    }
                                }

                                if (httpResponse != null)
                                {
                                    string newIDString = OsmRest.HttpUtils.GetResponseContent(httpResponse);

                                    relationosmIDLookup.Add(osmOldID, Convert.ToInt64(newIDString));

                                    // update the revision table
                                    if (revNewIDFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revNewIDFieldIndex, Convert.ToString(newIDString));
                                    }
                                    if (revVersionFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revVersionFieldIndex, 1);
                                    }
                                    if (revStatusFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revStatusFieldIndex, httpResponse.StatusCode.ToString());
                                    }
                                    if (revStatusCodeFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revStatusCodeFieldIndex, (int)httpResponse.StatusCode);
                                    }
                                    if (revChangeSetIDFieldIndex != -1)
                                    {
                                        searchRowToUpdate.set_Value(revChangeSetIDFieldIndex, Convert.ToInt32(changeSetID));
                                    }

                                    if (sourceFCName.Contains("_osm_ln"))
                                    {
                                        updateSource((ITable)lineFeatureClass, action, osmOldID, Convert.ToInt64(newIDString), user_displayname, userID, 1, Convert.ToInt32(changeSetID), nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                    }
                                    else if (sourceFCName.Contains("_osm_ply"))
                                    {
                                        updateSource((ITable)polygonFeatureClass, action, osmOldID, Convert.ToInt64(newIDString), user_displayname, userID, 1, Convert.ToInt32(changeSetID), nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                    }
                                    else
                                    {
                                        // update the source table holding the relation information class as well
                                        updateSource(relationTable, action, osmOldID, Convert.ToInt64(newIDString), user_displayname, userID, 1, Convert.ToInt32(changeSetID), nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                    }
                                }
                            }

                            catch (Exception ex)
                            {
                                message.AddError(120009, ex.Message);

                                if (ex is WebException)
                                {
                                    updateErrorStatus(message, revStatusFieldIndex, revStatusCodeFieldIndex, revErrorMessageFieldIndex, ref searchRowToUpdate, ex);
                                }
                            }
                            finally
                            {
                                try
                                {
                                    searchRowToUpdate.Store();
                                }
                                catch (Exception ex)
                                {
                                    System.Diagnostics.Debug.WriteLine(ex.Message);
                                }
                            }

                            if (TrackCancel.Continue() == false)
                            {
                                closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                                return;
                            }
                        }
                    }
                    #endregion

                    #region after that submit the modify node, way, relation
                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        queryFilter.WhereClause = "(" +
                            sqlFormatter.SqlIdentifier("osmstatuscode") + " <> 200 OR "
                            + sqlFormatter.SqlIdentifier("osmstatus") + " IS NULL) AND "
                            + sqlFormatter.SqlIdentifier("osmaction") + " = 'modify'";

                        searchCursor = revisionTable.Search(queryFilter, false);
                        comReleaser.ManageLifetime(searchCursor);

                        while ((searchRowToUpdate = searchCursor.NextRow()) != null)
                        {
                            try
                            {

                                string action = String.Empty;
                                if (revActionFieldIndex != -1)
                                {
                                    action = searchRowToUpdate.get_Value(revActionFieldIndex) as string;
                                }
                                string elementType = String.Empty;
                                if (revElementTypeFieldIndex != -1)
                                {
                                    elementType = searchRowToUpdate.get_Value(revElementTypeFieldIndex) as string;
                                }

                                string sourceFCName = String.Empty;
                                if (revFCNameFieldIndex != -1)
                                {
                                    sourceFCName = searchRowToUpdate.get_Value(revFCNameFieldIndex) as string;
                                }

                                long osmOldID = -1;
                                if (revOldIDFieldIndex != -1)
                                {
                                    osmOldID = Convert.ToInt64(searchRowToUpdate.get_Value(revOldIDFieldIndex));
                                }

                                // if the overall number of uploaded elements is too big for a single changeset we do need to split it up
                                // into multiple sets
                                if ((featureUpdateCounter % maxElementsinChangeSet) == 0)
                                {
                                    CreateNextChangeSet(message, createChangeSetOSM, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, ref changeSetID, baseURLGPString, ref featureUpdateCounter);
                                }

                                switch (elementType)
                                {
                                    case "node":
                                        #region submit nodes to OSM server
                                        switch (action)
                                        {
                                            case "modify":
                                                long modifyID = -1;

                                                if (revNewIDFieldIndex != -1)
                                                {
                                                    object osmIDValue = searchRowToUpdate.get_Value(revNewIDFieldIndex);

                                                    if (osmIDValue == DBNull.Value)
                                                    {
                                                        osmIDValue = osmOldID;
                                                    }

                                                    try
                                                    {
                                                        modifyID = Convert.ToInt64(osmIDValue);
                                                    }
                                                    catch { }

                                                    // modifies should only happen to osm IDs > 0
                                                    // if that condition is not met let's skip this feature as something is not right
                                                    if (modifyID < 0)
                                                    {
                                                        continue;
                                                    }
                                                }

                                                int osmVersion = -1;
                                                if (revVersionFieldIndex != -1)
                                                {
                                                    osmVersion = Convert.ToInt32(searchRowToUpdate.get_Value(revVersionFieldIndex));
                                                }

                                                try
                                                {
                                                    HttpWebRequest httpClient5 = HttpWebRequest.Create(baseURLGPString.Value + "/api/0.6/" + elementType + "/" + modifyID.ToString()) as HttpWebRequest;
                                                    httpClient5 = OSMGPDownload.AssignProxyandCredentials(httpClient5);
                                                    SetBasicAuthHeader(httpClient5, userCredentialGPValue.EncodedUserNamePassWord);

                                                    osm updateNode = CreateOSMNodeRepresentation(pointFeatureClass, action, modifyID, changeSetID, osmVersion, null, internalExtensionVersion);

                                                    string sContent = OsmRest.SerializeUtils.CreateXmlSerializable(updateNode, serializer, Encoding.UTF8, "text/xml");

                                                    // if the serialized node at this time is a null or an empty string let's continue to the next point
                                                    if (String.IsNullOrEmpty(sContent))
                                                    {
                                                        continue;
                                                    }

                                                    OsmRest.HttpUtils.Put(httpClient5, sContent);

                                                    httpResponse = httpClient5.GetResponse() as HttpWebResponse;

                                                    // track the update/sync requests against the server
                                                    featureUpdateCounter = featureUpdateCounter + 1;

                                                    if (httpResponse != null)
                                                    {
                                                        string newVersionString = OsmRest.HttpUtils.GetResponseContent(httpResponse);

                                                        // update the revision table
                                                        if (revVersionFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revVersionFieldIndex, Convert.ToString(newVersionString));
                                                        }
                                                        if (revStatusFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revStatusFieldIndex, httpResponse.StatusCode.ToString());
                                                        }
                                                        if (revStatusCodeFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revStatusCodeFieldIndex, (int)httpResponse.StatusCode);
                                                        }
                                                        if (revChangeSetIDFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revChangeSetIDFieldIndex, Convert.ToInt32(changeSetID));
                                                        }

                                                        // for a modify the old id is still the new id
                                                        if (revNewIDFieldIndex != -1 && revOldIDFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revNewIDFieldIndex, searchRowToUpdate.get_Value(revOldIDFieldIndex));
                                                        }

                                                        // update the source point feature class as well
                                                        updateSource((ITable)pointFeatureClass, action, modifyID, modifyID, user_displayname, userID, Convert.ToInt32(newVersionString), Convert.ToInt32(changeSetID), null, null, null, internalExtensionVersion);

                                                        httpResponse.Close();
                                                    }
                                                }
                                                catch (Exception ex)
                                                {
                                                    message.AddError(120009, ex.Message);

                                                    if (ex is WebException)
                                                    {
                                                        updateErrorStatus(message, revStatusFieldIndex, revStatusCodeFieldIndex, revErrorMessageFieldIndex, ref searchRowToUpdate, ex);
                                                    }
                                                }

                                                break;
                                            case "delete":
                                                // the delete operations are handled separately
                                                break;
                                            default:
                                                break;
                                        }
                                        break;
                                        #endregion
                                    case "way":
                                        #region submit ways to the OSM server
                                        // determine if we have a polygon or a polyline feature class
                                        bool isPolygon = false;
                                        if (sourceFCName.IndexOf("_osm_ply") > -1)
                                        {
                                            isPolygon = true;
                                        }

                                        switch (action)
                                        {
                                            case "modify":

                                                long modifyID = -1;

                                                if (revNewIDFieldIndex != -1)
                                                {
                                                    object osmIDValue = searchRowToUpdate.get_Value(revNewIDFieldIndex);

                                                    if (osmIDValue == DBNull.Value)
                                                    {
                                                        osmIDValue = osmOldID;
                                                    }

                                                    try
                                                    {
                                                        modifyID = Convert.ToInt64(osmIDValue);
                                                    }
                                                    catch { }

                                                    // modifies should only happen to osm IDs > 0
                                                    // if that condition is not met let's skip this feature as something is not right
                                                    if (modifyID < 0)
                                                    {
                                                        continue;
                                                    }
                                                }

                                                int osmVersion = -1;
                                                if (revVersionFieldIndex != -1)
                                                {
                                                    osmVersion = Convert.ToInt32(searchRowToUpdate.get_Value(revVersionFieldIndex));
                                                }

                                                osm updateWay = new osm();
                                                if (isPolygon == false)
                                                {
                                                    updateWay = CreateOSMWayRepresentation(lineFeatureClass, action, modifyID, changeSetID, osmVersion, nodeosmIDLookup, pointFeatureClass, pointOSMIDFieldIndex, internalExtensionVersion);
                                                }
                                                else
                                                {
                                                    updateWay = CreateOSMWayRepresentation(polygonFeatureClass, action, modifyID, changeSetID, osmVersion, nodeosmIDLookup, pointFeatureClass, pointOSMIDFieldIndex, internalExtensionVersion);
                                                }
                                                try
                                                {
                                                    string sContent = OsmRest.SerializeUtils.CreateXmlSerializable(updateWay, serializer, Encoding.UTF8, "text/xml");
                                                    httpClient = HttpWebRequest.Create(baseURLGPString.Value + "/api/0.6/" + elementType + "/" + modifyID.ToString()) as HttpWebRequest;
                                                    httpClient = OSMGPDownload.AssignProxyandCredentials(httpClient);
                                                    SetBasicAuthHeader(httpClient, userCredentialGPValue.EncodedUserNamePassWord);
                                                    OsmRest.HttpUtils.Put(httpClient, sContent);

                                                    httpResponse = httpClient.GetResponse() as HttpWebResponse;

                                                    // track the update/sync requests against the server
                                                    featureUpdateCounter = featureUpdateCounter + 1;

                                                    if (httpResponse != null)
                                                    {
                                                        string newVersionString = OsmRest.HttpUtils.GetResponseContent(httpResponse);

                                                        // update the revision table
                                                        if (revVersionFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revVersionFieldIndex, Convert.ToString(newVersionString));
                                                        }
                                                        if (revStatusFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revStatusFieldIndex, httpResponse.StatusCode.ToString());
                                                        }
                                                        if (revStatusCodeFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revStatusCodeFieldIndex, (int)httpResponse.StatusCode);
                                                        }
                                                        if (revChangeSetIDFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revChangeSetIDFieldIndex, Convert.ToInt32(changeSetID));
                                                        }

                                                        // for a modify the old id is still the new id
                                                        if (revNewIDFieldIndex != -1 && revOldIDFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revNewIDFieldIndex, searchRowToUpdate.get_Value(revOldIDFieldIndex));
                                                        }

                                                        // update the source line/polygon feature class as well
                                                        if (isPolygon == false)
                                                        {
                                                            updateSource((ITable)lineFeatureClass, action, modifyID, modifyID, user_displayname, userID, Convert.ToInt32(newVersionString), Convert.ToInt32(changeSetID), nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                                        }
                                                        else
                                                        {
                                                            updateSource((ITable)polygonFeatureClass, action, modifyID, modifyID, user_displayname, userID, Convert.ToInt32(newVersionString), Convert.ToInt32(changeSetID), nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);
                                                        }

                                                        httpResponse.Close();
                                                    }
                                                }
                                                catch (Exception ex)
                                                {
                                                    message.AddError(120009, ex.Message);

                                                    if (ex is WebException)
                                                    {
                                                        updateErrorStatus(message, revStatusFieldIndex, revStatusCodeFieldIndex, revErrorMessageFieldIndex, ref searchRowToUpdate, ex);
                                                    }
                                                }
                                                break;
                                            case "delete":
                                                // the delete operations are handled separately
                                                break;
                                            default:
                                                break;
                                        }
                                        break;
                                        #endregion
                                    case "relation":
                                        #region submit relations to the OSM server
                                        switch (action)
                                        {
                                            case "create":
                                                break;
                                            case "modify":

                                                long modifyID = -1;

                                                if (revNewIDFieldIndex != -1)
                                                {
                                                    object osmIDValue = searchRowToUpdate.get_Value(revNewIDFieldIndex);

                                                    if (osmIDValue == DBNull.Value)
                                                    {
                                                        osmIDValue = osmOldID;
                                                    }

                                                    try
                                                    {
                                                        modifyID = Convert.ToInt64(osmIDValue);
                                                    }
                                                    catch { }

                                                    // modifies should only happen to osm IDs > 0
                                                    // if that condition is not met let's skip this feature as something is not right
                                                    if (modifyID < 0)
                                                    {
                                                        continue;
                                                    }
                                                }

                                                int osmVersion = -1;
                                                if (revVersionFieldIndex != -1)
                                                {
                                                    osmVersion = Convert.ToInt32(searchRowToUpdate.get_Value(revVersionFieldIndex));
                                                }

                                                osm updateRelation = CreateOSMRelationRepresentation(relationTable, action, modifyID, changeSetID, osmVersion, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);

                                                try
                                                {
                                                    string sContent = OsmRest.SerializeUtils.CreateXmlSerializable(updateRelation, serializer, Encoding.UTF8, "text/xml");
                                                    httpClient = HttpWebRequest.Create(baseURLGPString.Value + "/api/0.6/" + elementType + "/" + modifyID.ToString()) as HttpWebRequest;
                                                    httpClient = OSMGPDownload.AssignProxyandCredentials(httpClient);
                                                    SetBasicAuthHeader(httpClient, userCredentialGPValue.EncodedUserNamePassWord);
                                                    OsmRest.HttpUtils.Put(httpClient, sContent);

                                                    httpResponse = httpClient.GetResponse() as HttpWebResponse;

                                                    // track the update/sync requests against the server
                                                    featureUpdateCounter = featureUpdateCounter + 1;

                                                    if (httpResponse != null)
                                                    {
                                                        string newVersionString = OsmRest.HttpUtils.GetResponseContent(httpResponse);

                                                        // update the revision table
                                                        if (revVersionFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revVersionFieldIndex, Convert.ToInt32(newVersionString));
                                                        }
                                                        if (revStatusFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revStatusFieldIndex, httpResponse.StatusCode.ToString());
                                                        }
                                                        if (revStatusCodeFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revStatusCodeFieldIndex, (int)httpResponse.StatusCode);
                                                        }
                                                        if (revChangeSetIDFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revChangeSetIDFieldIndex, Convert.ToInt32(changeSetID));
                                                        }

                                                        // for a modify the old id is still the new id
                                                        if (revNewIDFieldIndex != -1 && revOldIDFieldIndex != -1)
                                                        {
                                                            searchRowToUpdate.set_Value(revNewIDFieldIndex, searchRowToUpdate.get_Value(revOldIDFieldIndex));
                                                        }

                                                        // update the source table holding the relation information class as well
                                                        updateSource(relationTable, action, modifyID, modifyID, user_displayname, userID, Convert.ToInt32(newVersionString), Convert.ToInt32(changeSetID), nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);

                                                        httpResponse.Close();
                                                    }
                                                }
                                                catch (Exception ex)
                                                {
                                                    message.AddError(120009, ex.Message);

                                                    if (ex is WebException)
                                                    {
                                                        updateErrorStatus(message, revStatusFieldIndex, revStatusCodeFieldIndex, revErrorMessageFieldIndex, ref searchRowToUpdate, ex);
                                                    }
                                                }
                                                break;
                                            case "delete":
                                                // the delete operations are handled separately

                                                break;
                                            default:
                                                break;
                                        }
                                        break;
                                        #endregion
                                    default:
                                        break;
                                }
                            }

                            catch (Exception ex)
                            {
                                message.AddAbort(ex.Message);

                                if (ex is WebException)
                                {
                                    updateErrorStatus(message, revStatusFieldIndex, revStatusCodeFieldIndex, revErrorMessageFieldIndex, ref searchRowToUpdate, ex);
                                }
                            }
                            finally
                            {
                                try
                                {
                                    searchRowToUpdate.Store();
                                }
                                catch (Exception ex)
                                {
                                    System.Diagnostics.Debug.WriteLine(ex.Message);
                                }

                                if (httpResponse != null)
                                {
                                    httpResponse.Close();
                                }
                            }

                            if (TrackCancel.Continue() == false)
                            {
                                closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);

                                return;
                            }

                        }
                    }
                    #endregion

                    #region now let's handle the delete in the reverse order - relation first, then ways, and then nodes as the last entity
                    #region delete relations
                    // now let's handle the delete in the reverse order - relation first, then ways, and then nodes as the last entity
                    queryFilter.WhereClause = "("
                        + sqlFormatter.SqlIdentifier("osmstatuscode") + " <> 200 OR "
                        + sqlFormatter.SqlIdentifier("osmstatus") + " IS NULL) AND "
                        + sqlFormatter.SqlIdentifier("osmaction") + " = 'delete' AND "
                        + sqlFormatter.SqlIdentifier("osmelementtype") + " = 'relation'";

                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        searchCursor = revisionTable.Search(queryFilter, false);
                        comReleaser.ManageLifetime(searchCursor);

                        while ((searchRowToUpdate = searchCursor.NextRow()) != null)
                        {

                            // if the overall number of uploaded elements is too big for a single changeset we do need to split it up
                            // into multiple sets
                            if ((featureUpdateCounter % maxElementsinChangeSet) == 0)
                            {
                                CreateNextChangeSet(message, createChangeSetOSM, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, ref changeSetID, baseURLGPString, ref featureUpdateCounter);
                            }

                            long osmID = -1;
                            if (revOldIDFieldIndex != -1)
                            {
                                osmID = Convert.ToInt64(searchRowToUpdate.get_Value(revOldIDFieldIndex));
                            }
                            int osmVersion = -1;
                            if (revVersionFieldIndex != -1)
                            {
                                osmVersion = Convert.ToInt32(searchRowToUpdate.get_Value(revVersionFieldIndex));
                            }

                            osm deleteRelation = CreateOSMRelationRepresentation(relationTable, "delete", osmID, changeSetID, osmVersion, nodeosmIDLookup, wayosmIDLookup, relationosmIDLookup, internalExtensionVersion);

                            string sContent = OsmRest.SerializeUtils.CreateXmlSerializable(deleteRelation, serializer, Encoding.UTF8, "text/xml");

                            string errorMessage = String.Empty;
                            try
                            {
                                httpResponse = OsmRest.HttpUtils.Delete(baseURLGPString.Value + "/api/0.6/relation/" + Convert.ToString(osmID), sContent, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout) as HttpWebResponse;

                                // track the update/sync requests against the server
                                featureUpdateCounter = featureUpdateCounter + 1;

                                if (revStatusFieldIndex != -1)
                                {
                                    searchRowToUpdate.set_Value(revStatusFieldIndex, (int)httpResponse.StatusCode);
                                }
                                if (revStatusCodeFieldIndex != -1)
                                {
                                    searchRowToUpdate.set_Value(revStatusCodeFieldIndex, (int)httpResponse.StatusCode);
                                }

                                if (httpResponse != null)
                                {
                                    httpResponse.Close();
                                }
                            }
                            catch (Exception ex)
                            {
                                message.AddError(120009, ex.Message);

                                if (ex is WebException)
                                {
                                    updateErrorStatus(message, revStatusFieldIndex, revStatusCodeFieldIndex, revErrorMessageFieldIndex, ref searchRowToUpdate, ex);
                                }

                                if (httpResponse != null)
                                {
                                    httpResponse.Close();
                                }
                            }

                            try
                            {
                                searchRowToUpdate.Store();
                            }
                            catch { }

                            if (TrackCancel.Continue() == false)
                            {
                                closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                                return;
                            }

                        }
                    }

                    #endregion

                    #region handle delete ways
                    queryFilter.WhereClause = "("
                        + sqlFormatter.SqlIdentifier("osmstatuscode") + " <> 200 OR "
                        + sqlFormatter.SqlIdentifier("osmstatus") + " IS NULL) AND "
                        + sqlFormatter.SqlIdentifier("osmaction") + " = 'delete' AND "
                        + sqlFormatter.SqlIdentifier("osmelementtype") + " = 'way'";

                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        searchCursor = revisionTable.Search(queryFilter, false);
                        comReleaser.ManageLifetime(searchCursor);

                        while ((searchRowToUpdate = searchCursor.NextRow()) != null)
                        {

                            // if the overall number of uploaded elements is too big for a single changeset we do need to split it up
                            // into multiple sets
                            if ((featureUpdateCounter % maxElementsinChangeSet) == 0)
                            {
                                CreateNextChangeSet(message, createChangeSetOSM, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, ref changeSetID, baseURLGPString, ref featureUpdateCounter);
                            }

                            long osmID = -1;
                            if (revOldIDFieldIndex != -1)
                            {
                                osmID = Convert.ToInt64(searchRowToUpdate.get_Value(revOldIDFieldIndex));
                            }
                            int osmVersion = -1;
                            if (revVersionFieldIndex != -1)
                            {
                                osmVersion = Convert.ToInt32(searchRowToUpdate.get_Value(revVersionFieldIndex));
                            }

                            osm deleteWay = CreateOSMWayRepresentation(lineFeatureClass, "delete", osmID, changeSetID, osmVersion, wayosmIDLookup, pointFeatureClass, pointOSMIDFieldIndex, internalExtensionVersion);

                            string sContent = OsmRest.SerializeUtils.CreateXmlSerializable(deleteWay, serializer, Encoding.UTF8, "text/xml");

                            try
                            {
                                httpResponse = null;
                                httpResponse = OsmRest.HttpUtils.Delete(baseURLGPString.Value + "/api/0.6/way/" + Convert.ToString(osmID), sContent, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout) as HttpWebResponse;

                                // track the update/sync requests against the server
                                featureUpdateCounter = featureUpdateCounter + 1;

                                string errorMessage = String.Empty;
                                // just grab the response and set it on the database
                                if (revStatusFieldIndex != -1)
                                {
                                    searchRowToUpdate.set_Value(revStatusFieldIndex, (int)httpResponse.StatusCode);
                                }
                                if (revStatusCodeFieldIndex != -1)
                                {
                                    searchRowToUpdate.set_Value(revStatusCodeFieldIndex, (int)httpResponse.StatusCode);
                                }

                                if (httpResponse != null)
                                {
                                    httpResponse.Close();
                                }
                            }

                            catch (Exception ex)
                            {
                                message.AddError(1200009, ex.Message);

                                if (ex is WebException)
                                {
                                    updateErrorStatus(message, revStatusFieldIndex, revStatusCodeFieldIndex, revErrorMessageFieldIndex, ref searchRowToUpdate, ex);
                                }

                                if (httpResponse != null)
                                {
                                    httpResponse.Close();
                                }
                            }

                            try
                            {
                                searchRowToUpdate.Store();
                            }
                            catch { }

                            if (TrackCancel.Continue() == false)
                            {
                                closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                                return;
                            }
                        }
                    }

                    #endregion

                    #region handle delete points
                    queryFilter.WhereClause = "("
                        + sqlFormatter.SqlIdentifier("osmstatuscode") + " <> 200 OR "
                        + sqlFormatter.SqlIdentifier("osmstatus") + " IS NULL) AND "
                        + sqlFormatter.SqlIdentifier("osmaction") + " = 'delete' AND "
                        + sqlFormatter.SqlIdentifier("osmelementtype") + " = 'node'";

                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        searchCursor = revisionTable.Search(queryFilter, false);
                        comReleaser.ManageLifetime(searchCursor);

                        while ((searchRowToUpdate = searchCursor.NextRow()) != null)
                        {
                            // if the overall number of uploaded elements is too big for a single changeset we do need to split it up
                            // into multiple sets
                            if ((featureUpdateCounter % maxElementsinChangeSet) == 0)
                            {
                                CreateNextChangeSet(message, createChangeSetOSM, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, ref changeSetID, baseURLGPString, ref featureUpdateCounter);
                            }

                            long osmID = -1;
                            if (revOldIDFieldIndex != -1)
                            {
                                osmID = Convert.ToInt64(searchRowToUpdate.get_Value(revOldIDFieldIndex));
                            }
                            int osmVersion = -1;
                            if (revVersionFieldIndex != -1)
                            {
                                osmVersion = Convert.ToInt32(searchRowToUpdate.get_Value(revVersionFieldIndex));
                            }

                            IPoint deletePoint = null;
                            if (revLongitudeFieldIndex != -1 && revLatitudeFieldIndex != -1)
                            {
                                try
                                {
                                    // let's reconstruct the delete point
                                    deletePoint = new PointClass();
                                    deletePoint.X = Convert.ToDouble(searchRowToUpdate.get_Value(revLongitudeFieldIndex));
                                    deletePoint.Y = Convert.ToDouble(searchRowToUpdate.get_Value(revLatitudeFieldIndex));
                                    deletePoint.SpatialReference = m_wgs84;
                                }
                                catch (Exception ex)
                                {
                                    message.AddWarning(ex.Message);
                                }

                                if (deletePoint == null)
                                {
                                    // inform the about the issue - no successful creation of point and continue on to the next delete instruction
                                    // in the revision table
                                    message.AddWarning(resourceManager.GetString("GPTools_OSMGPUpload_invalidPoint"));
                                    continue;
                                }
                            }

                            osm deleteNode = CreateOSMNodeRepresentation(pointFeatureClass, "delete", osmID, changeSetID, osmVersion, deletePoint, internalExtensionVersion);

                            string sContent = OsmRest.SerializeUtils.CreateXmlSerializable(deleteNode, serializer, Encoding.UTF8, "text/xml");

                            if (String.IsNullOrEmpty(sContent))
                            {
                                continue;
                            }

                            string errorMessage = String.Empty;

                            try
                            {
                                httpResponse = OsmRest.HttpUtils.Delete(baseURLGPString.Value + "/api/0.6/node/" + Convert.ToString(osmID), sContent, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout) as HttpWebResponse;

                                if (revStatusFieldIndex != -1)
                                {
                                    searchRowToUpdate.set_Value(revStatusFieldIndex, (int)httpResponse.StatusCode);
                                }

                                if (revStatusCodeFieldIndex != -1)
                                {
                                    searchRowToUpdate.set_Value(revStatusCodeFieldIndex, (int)httpResponse.StatusCode);
                                }

                                if (httpResponse != null)
                                {
                                    httpResponse.Close();
                                }
                            }
                            catch (Exception ex)
                            {
                                message.AddError(120009, ex.Message);

                                if (ex is WebException)
                                {
                                    updateErrorStatus(message, revStatusFieldIndex, revStatusCodeFieldIndex, revErrorMessageFieldIndex, ref searchRowToUpdate, ex);
                                }

                                if (httpResponse != null)
                                {
                                    httpResponse.Close();
                                }

                            }

                            // track the update/sync requests against the server
                            featureUpdateCounter = featureUpdateCounter + 1;

                            try
                            {
                                searchRowToUpdate.Store();
                            }
                            catch { }

                            if (TrackCancel.Continue() == false)
                            {
                                closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);
                                return;
                            }
                        }
                    }

                    #endregion
                    #endregion
                    #endregion
                }
            }
            catch (Exception ex)
            {
                message.AddError(120058, ex.Message);
                message.AddError(120058, ex.StackTrace);
            }
            finally
            {
                closeChangeSet(message, userCredentialGPValue.EncodedUserNamePassWord, secondsToTimeout, changeSetID, baseURLGPString);

                if (revisionTable != null)
                {
                    try
                    {
                        ISchemaLock tableSchemaLock = revisionTable as ISchemaLock;

                        if (tableSchemaLock != null)
                        {
                            tableSchemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
                        }
                    }
                    catch (Exception eLock)
                    {
                        message.AddError(120059, resourceManager.GetString("GPTools_OSMGPUpload_LockErrorTitle") + eLock.Message);
                    }
                }

                if (revisionTable != null)
                {
                    Marshal.FinalReleaseComObject(revisionTable);
                }

                // if the searchCursor still has a reference somewhere do release it now - and as a result release any remaining table locks
                if (searchCursor != null)
                {
                    Marshal.FinalReleaseComObject(searchCursor);
                }

                gpUtilities3.RemoveInternalData();
                gpUtilities3.ReleaseInternals();

                //Marshal.ReleaseComObject(gpUtilities3);
            }
        }
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            // attempting to load the revision tables from the map
            if (m_currentMap != null)
            {
                FindTablesInsideCurrentMap();
            }

            // and/or use the provided list of tables of revision
            if (m_revisionTables != null)
            {
                for (int m_revionTabIndex = 0; m_revionTabIndex < m_revisionTables.Count; m_revionTabIndex++)
                {
                    IDataset tableDataset = m_revisionTables[m_revionTabIndex] as IDataset;

                    if (m_allRevisionTables.ContainsKey(tableDataset.Name) == false)
                    {
                        m_allRevisionTables.Add(tableDataset.Name, m_revisionTables[m_revionTabIndex]);
                    }
                }
            }

            // warn the user that no revision info is available
            if (m_allRevisionTables.Count == 0)
            {
                MessageBox.Show(resourceManager.GetString("OSMEditor_ConflictEditor_norevisionTables"), resourceManager.GetString("OSMEditor_ConflictEditor_norevisionTables_title"), MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            // prepare the map controls
            for (int layerIndex = 0; layerIndex < axMapControl1.LayerCount; layerIndex++)
            {
                axMapControl1.DeleteLayer(layerIndex);
            }

            for (int layerIndex = 0; layerIndex < axMapControl2.LayerCount; layerIndex++)
            {
                axMapControl2.DeleteLayer(layerIndex);
            }

            if (m_currentMap != null)
            {
                IEnumLayer enumLayer = m_currentMap.get_Layers(null, false);

                ILayer basemapLayer = enumLayer.Next();

                while (basemapLayer != null)
                {
                    if (basemapLayer.Valid == true)
                    {
                        if (basemapLayer is IBasemapLayer)
                        {
                            axMapControl1.Map.AddLayer(basemapLayer);
                            axMapControl2.Map.AddLayer(basemapLayer);
                        }
                    }

                    basemapLayer = enumLayer.Next();
                }
            }

            axMapControl1.OnExtentUpdated += new IMapControlEvents2_Ax_OnExtentUpdatedEventHandler(mapControlOnExtentUpdated);
            axMapControl2.OnExtentUpdated += new IMapControlEvents2_Ax_OnExtentUpdatedEventHandler(mapControlOnExtentUpdated);

            m_osmPointsFC = CreatePointFeatureClass("osm_points", null, null);
            m_osmLinesFC = CreateLineFeatureClass("osm_lines", null, null);
            m_osmPolygonFC = CreatePolygonFeatureClass("osm_polygons", null, null);

            errorTreeView.Nodes.Add(resourceManager.GetString("OSMEditor_ConflictEditor_prepareCollectData"));
            errorTreeView.Refresh();

            // prepare the tree view
            errorTreeView.BeginUpdate();

            errorTreeView.Nodes.Clear();
            int firstLevelNodeIndex = 0;

            foreach (ITable revisionTable in m_allRevisionTables.Values)
            {
                errorTreeView.Nodes.Add(new TreeNode(((IDataset)revisionTable).Name));

                // Find the elements with a conflict
                int osmIDFieldIndex = revisionTable.Fields.FindField("osmoldid");
                int sourceFCNameFieldIndex = revisionTable.Fields.FindField("sourcefcname");
                int errorMessageFieldIndex = revisionTable.Fields.FindField("osmerrormessage");
                int elementTypeFieldIndex = revisionTable.Fields.FindField("osmelementtype");
                int errorStatusCodeFieldIndex = revisionTable.Fields.FindField("osmstatuscode");

                IQueryFilter searchFilter = new QueryFilterClass();
                searchFilter.WhereClause = SqlFormatterExt.SqlIdentifier(revisionTable, "osmstatuscode") + " <> 200";

                using (ESRI.ArcGIS.OSM.OSMClassExtension.ComReleaser comReleaser = new ESRI.ArcGIS.OSM.OSMClassExtension.ComReleaser())
                {
                    IFeatureWorkspace featureWorkspace = ((IDataset)revisionTable).Workspace as IFeatureWorkspace;
                    comReleaser.ManageLifetime(featureWorkspace);

                    ICursor searchCursor = revisionTable.Search(searchFilter, false);
                    comReleaser.ManageLifetime(searchCursor);

                    IRow errorRow = searchCursor.NextRow();
                    comReleaser.ManageLifetime(errorRow);

                    while (errorRow != null)
                    {
                        string osmElementType = errorRow.get_Value(elementTypeFieldIndex).ToString();
                        string osmIDString = errorRow.get_Value(osmIDFieldIndex).ToString();

                        RequestOSMServerData(osmElementType, osmIDString, m_osmPointsFC, m_osmLinesFC, m_osmPolygonFC);

                        string osmTypeSuffix = RetrieveOSMTypeAddendum(errorRow, sourceFCNameFieldIndex);

                        string errorMessage = errorRow.get_Value(errorMessageFieldIndex) as string;

                        TreeNode errorNode = new TreeNode("(" + osmIDString + ", " + osmTypeSuffix + ")");

                        if (String.IsNullOrEmpty(errorMessage) == false)
                        {
                            errorNode.ToolTipText = errorMessage;
                        }

                        int errorStatusCode = -1;
                        if (errorStatusCodeFieldIndex != -1)
                        {
                            errorStatusCode = (int) errorRow.get_Value(errorStatusCodeFieldIndex);
                        }

                        conflictTag errorNodeConflictTag = new conflictTag(errorRow.OID, osmIDString, errorStatusCode, errorRow.get_Value(sourceFCNameFieldIndex).ToString());

                        errorNode.Tag = errorNodeConflictTag;
                        errorNode.ContextMenuStrip = CreateErrorContextMenu(errorStatusCode, "");

                        errorTreeView.Nodes[firstLevelNodeIndex].Nodes.Add(errorNode);

                        errorTreeView.Nodes[firstLevelNodeIndex].ExpandAll();

                        errorRow = searchCursor.NextRow();
                        comReleaser.ManageLifetime(errorRow);
                    }
                }

                firstLevelNodeIndex = firstLevelNodeIndex + 1;
            }

            errorTreeView.EndUpdate();

            // clean the remaining UI components
            UpdateDataGridViewColumn(1, Color.White);
            UpdateDataGridViewColumn(2, Color.White);
            dataGridView2.Rows.Clear();
            dataGridView2.Invalidate();

            DeleteAllGraphicElements();
        }
        /// <summary>
        /// This function assembles a version of the logged relation action from the revision table in the OsmChange format http://wiki.openstreetmap.org/wiki/OsmChange
        /// </summary>
        /// <param name="relationTable"></param>
        /// <param name="action"></param>
        /// <param name="osmID"></param>
        /// <param name="changeSetID"></param>
        /// <param name="osmVersion"></param>
        /// <param name="nodeosmIDLookup"></param>
        /// <param name="wayosmIDLookup"></param>
        /// <param name="relationosmIDLookup"></param>
        /// <param name="extensionVersion"></param>
        /// <returns></returns>
        private ESRI.ArcGIS.OSM.OSMClassExtension.relation CreateRelationRepresentation(ITable relationTable, string action, long osmID, string changeSetID, int osmVersion, Dictionary<long, long> nodeosmIDLookup, Dictionary<long, long> wayosmIDLookup, Dictionary<long, long> relationosmIDLookup, int extensionVersion)
        {
            ESRI.ArcGIS.OSM.OSMClassExtension.relation relationRepresentation = new ESRI.ArcGIS.OSM.OSMClassExtension.relation();

            // let's find all the rows that have a different status than 200 - meaning success
            IQueryFilter queryFilter = new QueryFilterClass();
            queryFilter.WhereClause = relationTable.WhereClauseByExtensionVersion(osmID, "OSMID", extensionVersion);

            using (ComReleaser comReleaser = new ComReleaser())
            {
                ICursor searchCursor = relationTable.Search(queryFilter, false);
                comReleaser.ManageLifetime(searchCursor);

                IRow relationRow = searchCursor.NextRow();

                int osmTagsFieldIndex = relationTable.Fields.FindField("osmTags");
                int osmIDFieldIndex = relationTable.Fields.FindField("osmID");
                int osmUserFieldIndex = relationTable.Fields.FindField("osmuser");
                int osmUIDFieldIndex = relationTable.Fields.FindField("osmuid");
                int osmVisibleFieldIndex = relationTable.Fields.FindField("osmvisible");
                int osmVersionFieldIndex = relationTable.Fields.FindField("osmversion");
                int osmMembersFieldIndex = relationTable.Fields.FindField("osmMembers");

                if (relationRow != null)
                {
                    switch (action)
                    {
                        case "create":
                            // the newly created node needs to carry the changeset info, the coordinate and the tags
                            relationRepresentation.changeset = changeSetID;

                            ESRI.ArcGIS.OSM.OSMClassExtension.tag[] tags = null;
                            if (osmTagsFieldIndex > -1)
                            {
                                tags = _osmUtility.retrieveOSMTags(relationRow, osmTagsFieldIndex, ((IDataset)relationTable).Workspace);
                            }

                            List<tag> valueOnlyTags = new List<tag>();

                            for (int index = 0; index < tags.Length; index++)
                            {
                                if (!String.IsNullOrEmpty(tags[index].v))
                                {
                                    valueOnlyTags.Add(tags[index]);
                                }
                            }

                            if (osmIDFieldIndex > -1)
                            {
                                relationRepresentation.id = osmID.ToString();
                            }

                            ESRI.ArcGIS.OSM.OSMClassExtension.member[] members = null;
                            if (osmMembersFieldIndex > -1)
                            {
                                members = _osmUtility.retrieveMembers(relationRow, osmMembersFieldIndex);

                                // run the member ids through the lookup table
                                for (int memberIndex = 0; memberIndex < members.Length; memberIndex++)
                                {
                                    switch (members[memberIndex].type)
                                    {
                                        case ESRI.ArcGIS.OSM.OSMClassExtension.memberType.way:
                                            if (wayosmIDLookup.ContainsKey(Convert.ToInt64(members[memberIndex].@ref)))
                                            {
                                                members[memberIndex].@ref = Convert.ToString(wayosmIDLookup[Convert.ToInt64(members[memberIndex].@ref)]);
                                            }
                                            break;
                                        case ESRI.ArcGIS.OSM.OSMClassExtension.memberType.node:
                                            if (nodeosmIDLookup.ContainsKey(Convert.ToInt64(members[memberIndex].@ref)))
                                            {
                                                members[memberIndex].@ref = Convert.ToString(nodeosmIDLookup[Convert.ToInt64(members[memberIndex].@ref)]);
                                            }
                                            break;
                                        case ESRI.ArcGIS.OSM.OSMClassExtension.memberType.relation:
                                            if (relationosmIDLookup.ContainsKey(Convert.ToInt64(members[memberIndex].@ref)))
                                            {
                                                members[memberIndex].@ref = Convert.ToString(relationosmIDLookup[Convert.ToInt64(members[memberIndex].@ref)]);
                                            }
                                            break;
                                        default:
                                            break;
                                    }
                                }

                                _osmUtility.insertMembers(osmMembersFieldIndex, relationRow, members);
                            }

                            // add the member and the tags to the relation element
                            List<object> relationItems = new List<object>();
                            relationItems.AddRange(members);
                            relationItems.AddRange(valueOnlyTags.ToArray());

                            relationRepresentation.Items = relationItems.ToArray();

                            break;
                        case "modify":
                            // for an update the complete (full) relation needs to be returned
                            relationRepresentation.changeset = changeSetID;
                            if (osmIDFieldIndex > -1)
                            {
                                relationRepresentation.id = Convert.ToString(relationRow.get_Value(osmIDFieldIndex), new CultureInfo("en-US"));
                            }

                            if (osmUserFieldIndex > -1)
                            {
                                relationRepresentation.user = Convert.ToString(relationRow.get_Value(osmUserFieldIndex));
                            }

                            if (osmUIDFieldIndex > -1)
                            {
                                relationRepresentation.uid = Convert.ToString(relationRow.get_Value(osmUIDFieldIndex), new CultureInfo("en-US"));
                            }

                            if (osmVersionFieldIndex > -1)
                            {
                                relationRepresentation.version = Convert.ToString(relationRow.get_Value(osmVersionFieldIndex));
                            }

                            tags = null;
                            if (osmTagsFieldIndex > -1)
                            {
                                tags = _osmUtility.retrieveOSMTags((IRow)relationRow, osmTagsFieldIndex, ((IDataset)relationTable).Workspace);
                            }

                            valueOnlyTags = new List<tag>();

                            for (int index = 0; index < tags.Length; index++)
                            {
                                if (!String.IsNullOrEmpty(tags[index].v))
                                {
                                    valueOnlyTags.Add(tags[index]);
                                }
                            }

                            members = null;
                            if (osmMembersFieldIndex > -1)
                            {
                                members = _osmUtility.retrieveMembers(relationRow, osmMembersFieldIndex);

                                // run the member ids through the lookup table
                                for (int memberIndex = 0; memberIndex < members.Length; memberIndex++)
                                {
                                    switch (members[memberIndex].type)
                                    {
                                        case memberType.way:
                                            if (wayosmIDLookup.ContainsKey(Convert.ToInt64(members[memberIndex].@ref)))
                                            {
                                                members[memberIndex].@ref = Convert.ToString(wayosmIDLookup[Convert.ToInt64(members[memberIndex].@ref)]);
                                            }
                                            break;
                                        case memberType.node:
                                            if (nodeosmIDLookup.ContainsKey(Convert.ToInt64(members[memberIndex].@ref)))
                                            {
                                                members[memberIndex].@ref = Convert.ToString(nodeosmIDLookup[Convert.ToInt64(members[memberIndex].@ref)]);
                                            }
                                            break;
                                        case memberType.relation:
                                            if (relationosmIDLookup.ContainsKey(Convert.ToInt64(members[memberIndex].@ref)))
                                            {
                                                members[memberIndex].@ref = Convert.ToString(relationosmIDLookup[Convert.ToInt64(members[memberIndex].@ref)]);
                                            }
                                            break;
                                        default:
                                            break;
                                    }
                                }

                                _osmUtility.insertMembers(osmMembersFieldIndex, relationRow, members);
                            }

                            // add the member and the tags to the relation element
                            relationItems = new List<object>();
                            relationItems.AddRange(valueOnlyTags.ToArray());
                            relationItems.AddRange(members);

                            relationRepresentation.Items = relationItems.ToArray();

                            break;
                        case "delete":

                            relationRepresentation.changeset = changeSetID;
                            relationRepresentation.id = Convert.ToString(osmID);
                            relationRepresentation.version = Convert.ToString(osmVersion);

                            break;
                        default:
                            break;
                    }
                }
                else
                {
                    if (action.Equals("delete", StringComparison.InvariantCultureIgnoreCase))
                    {
                        relationRepresentation.changeset = changeSetID;
                        relationRepresentation.id = Convert.ToString(osmID);
                        relationRepresentation.version = Convert.ToString(osmVersion);
                    }
                }
            }

            return relationRepresentation;
        }
        public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriSystem.ITrackCancel TrackCancel, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr, ESRI.ArcGIS.Geodatabase.IGPMessages message)
        {

            try
            {
                IGPUtilities3 gpUtilities3 = new GPUtilitiesClass() as IGPUtilities3;

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

                // decode in the input layers
                IGPParameter in_SourceFeatureClassParameter = paramvalues.get_Element(in_sourceFeatureClassNumber) as IGPParameter;
                IGPValue in_SourceFeatureGPValue = gpUtilities3.UnpackGPValue(in_SourceFeatureClassParameter) as IGPValue;

                IFeatureClass sourceFeatureClass = null;
                IQueryFilter queryFilter = null;

                gpUtilities3.DecodeFeatureLayer((IGPValue)in_SourceFeatureGPValue, out sourceFeatureClass, out queryFilter);

                if (sourceFeatureClass == null)
                {
                    message.AddError(120027, resourceManager.GetString("GPTools_OSMGPFeatureComparison_source_nullpointer"));
                    return;
                }

                IGPParameter in_NumberOfIntersectionsFieldParameter = paramvalues.get_Element(in_sourceIntersectionFieldNumber) as IGPParameter;
                IGPValue in_NumberOfIntersectionsFieldGPValue = gpUtilities3.UnpackGPValue(in_NumberOfIntersectionsFieldParameter) as IGPValue;

                IGPParameter in_SourceRefIDFieldParameter = paramvalues.get_Element(in_sourceRefIDsFieldNumber) as IGPParameter;
                IGPValue in_SourceRefIDFieldGPValue = gpUtilities3.UnpackGPValue(in_SourceRefIDFieldParameter) as IGPValue;

                IGPParameter in_MatchFeatureClassParameter = paramvalues.get_Element(in_MatchFeatureClassNumber) as IGPParameter;
                IGPValue in_MatchFeatureGPValue = gpUtilities3.UnpackGPValue(in_MatchFeatureClassParameter) as IGPValue;

                IFeatureClass matchFeatureClass = null;
                IQueryFilter matchQueryFilter = null;

                gpUtilities3.DecodeFeatureLayer((IGPValue)in_MatchFeatureGPValue, out matchFeatureClass, out matchQueryFilter);


                if (matchFeatureClass == null)
                {
                    message.AddError(120028, resourceManager.GetString("GPTools_OSMGPFeatureComparison_match_nullpointer"));
                    return;
                }

                if (queryFilter != null)
                {
                    if (((IGeoDataset)matchFeatureClass).SpatialReference != null)
                    {
                        queryFilter.set_OutputSpatialReference(sourceFeatureClass.ShapeFieldName, ((IGeoDataset)matchFeatureClass).SpatialReference);
                    }
                }


                IWorkspace sourceWorkspace = ((IDataset) sourceFeatureClass).Workspace;
                IWorkspaceEdit sourceWorkspaceEdit = sourceWorkspace as IWorkspaceEdit;

                if (sourceWorkspace.Type == esriWorkspaceType.esriRemoteDatabaseWorkspace)
                {
                    sourceWorkspaceEdit = sourceWorkspace as IWorkspaceEdit;
                    sourceWorkspaceEdit.StartEditing(false);
                    sourceWorkspaceEdit.StartEditOperation();
                }

                // get an overall feature count as that determines the progress indicator
                int featureCount = ((ITable)sourceFeatureClass).RowCount(queryFilter);

                // set up the progress indicator
                IStepProgressor stepProgressor = TrackCancel as IStepProgressor;

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

                int numberOfIntersectionsFieldIndex = sourceFeatureClass.FindField(in_NumberOfIntersectionsFieldGPValue.GetAsText());
                int sourceRefIDFieldIndex = sourceFeatureClass.FindField(in_SourceRefIDFieldGPValue.GetAsText());

                ISpatialFilter matchFCSpatialFilter = new SpatialFilter();
                matchFCSpatialFilter.GeometryField = matchFeatureClass.ShapeFieldName;
                matchFCSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                matchFCSpatialFilter.WhereClause = matchQueryFilter.WhereClause;

                using (ComReleaser comReleaser = new ComReleaser())
                {
                    IFeatureCursor sourceFeatureCursor = sourceFeatureClass.Search(queryFilter, false);
                    comReleaser.ManageLifetime(sourceFeatureCursor);

                    IFeature sourceFeature = null;

                    while ((sourceFeature = sourceFeatureCursor.NextFeature()) != null)
                    {
                        int numberOfIntersections = 0;
                        string intersectedFeatures = String.Empty;

                        IPolyline sourceLine = sourceFeature.Shape as IPolyline;

                        matchFCSpatialFilter.Geometry = sourceLine;

                        using (ComReleaser innerReleaser = new ComReleaser())
                        {
                            IFeatureCursor matchFeatureCursor = matchFeatureClass.Search(matchFCSpatialFilter, false);
                            innerReleaser.ManageLifetime(matchFeatureCursor);

                            IFeature matchFeature = null;

                            while ((matchFeature = matchFeatureCursor.NextFeature()) != null)
                            {
                                IPointCollection intersectionPointCollection = null;
                                try
                                {
                                    ITopologicalOperator topoOperator = sourceLine as ITopologicalOperator;

                                    if (topoOperator.IsSimple == false)
                                    {
                                        ((ITopologicalOperator2)topoOperator).IsKnownSimple_2 = false;
                                        topoOperator.Simplify();
                                    }

                                    IPolyline matchPolyline = matchFeature.Shape as IPolyline;

                                    if (queryFilter != null)
                                    {
                                        matchPolyline.Project(sourceLine.SpatialReference);
                                    }

                                    if (((ITopologicalOperator)matchPolyline).IsSimple == false)
                                    {
                                        ((ITopologicalOperator2)matchPolyline).IsKnownSimple_2 = false;
                                        ((ITopologicalOperator)matchPolyline).Simplify();
                                    }

                                    intersectionPointCollection = topoOperator.Intersect(matchPolyline, esriGeometryDimension.esriGeometry0Dimension) as IPointCollection;
                                }
                                catch (Exception ex)
                                {
                                    message.AddWarning(ex.Message);
                                    continue;
                                }

                                if (intersectionPointCollection != null && intersectionPointCollection.PointCount > 0)
                                {
                                    numberOfIntersections = numberOfIntersections + intersectionPointCollection.PointCount;

                                    if (String.IsNullOrEmpty(intersectedFeatures))
                                    {
                                        intersectedFeatures = matchFeature.OID.ToString();
                                    }
                                    else
                                    {
                                        intersectedFeatures = intersectedFeatures + "," + matchFeature.OID.ToString();
                                    }
                                }
                            }

                            if (numberOfIntersectionsFieldIndex > -1)
                            {
                                sourceFeature.set_Value(numberOfIntersectionsFieldIndex, numberOfIntersections);
                            }

                            if (sourceRefIDFieldIndex > -1)
                            {
                                if (intersectedFeatures.Length > sourceFeatureClass.Fields.get_Field(sourceRefIDFieldIndex).Length)
                                {
                                    sourceFeature.set_Value(sourceRefIDFieldIndex, intersectedFeatures.Substring(0, sourceFeatureClass.Fields.get_Field(sourceRefIDFieldIndex).Length));
                                }
                                else
                                {
                                    sourceFeature.set_Value(sourceRefIDFieldIndex, intersectedFeatures);
                                }
                            }
                        }

                        try
                        {
                            sourceFeature.Store();
                        }
                        catch (Exception ex)
                        {
                            message.AddWarning(ex.Message);
                        }

                        if (stepProgressor != null)
                        {
                            // update the progress UI
                            stepProgressor.Step();
                        }

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

                    }
                }

                if (sourceWorkspaceEdit != null)
                {
                    sourceWorkspaceEdit.StopEditOperation();
                    sourceWorkspaceEdit.StopEditing(true);
                }

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

            }
            catch (Exception ex)
            {
                message.AddAbort(ex.Message);
            }

        }
        private void ParseResultDiff(diffResult diffResultResponse, ITable revisionTable, IFeatureClass pointFeatureClass, IFeatureClass lineFeatureClass, IFeatureClass polygonFeatureClass, ITable relationTable, string userName, int userID, string changetSetID, Dictionary<long, long> nodeIDLookup, Dictionary<long, long> wayIDLookup, Dictionary<long, long> relationIDLookup, int extensionVersion)
        {
            if (diffResultResponse == null)
                return;

            if (diffResultResponse.Items == null)
                return;

            // let's find all the matching row with the old osm feature ID
            IQueryFilter queryFilter = new QueryFilterClass();

            int sourceFCNameFieldIndex = revisionTable.Fields.FindField("sourcefcname");
            int statusFieldIndex = revisionTable.Fields.FindField("osmstatus");
            int statusCodeFieldIndex = revisionTable.Fields.FindField("osmstatuscode");
            int newIDFieldIndex = revisionTable.Fields.FindField("osmnewid");
            int osmVersionFieldIndex = revisionTable.Fields.FindField("osmversion");
            int changesetIDFieldIndex = revisionTable.Fields.FindField("osmchangeset");

            SQLFormatter sqlFormatter = new SQLFormatter(revisionTable);

            foreach (var item in diffResultResponse.Items)
            {
                if (item is diffResultNode)
                {
                    diffResultNode diffNode = item as diffResultNode;
                    long newID = -1;
                    int newVersion = -1;
                    long oldID = -1;

                    long.TryParse(diffNode.new_id, out newID);
                    int.TryParse(diffNode.new_version, out newVersion);
                    long.TryParse(diffNode.old_id, out oldID);

                    //
                    if (nodeIDLookup.ContainsKey(oldID) == false)
                    {
                        nodeIDLookup.Add(oldID, newID);
                    }

                    updateSource((ITable)pointFeatureClass, determineAction(diffNode), Convert.ToInt64(diffNode.old_id), newID, userName, userID, newVersion, Convert.ToInt32(changetSetID), nodeIDLookup, wayIDLookup, relationIDLookup, extensionVersion);

                    queryFilter.WhereClause = revisionTable.WhereClauseByExtensionVersion(diffNode.old_id, "osmoldid", extensionVersion)
                        + " AND " + sqlFormatter.SqlIdentifier("osmelementtype") + " = 'node'" + " AND " + sqlFormatter.SqlIdentifier("osmstatuscode") + " IS NULL"; ;

                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        ICursor updateCursor = revisionTable.Update(queryFilter, false);
                        comReleaser.ManageLifetime(updateCursor);

                        IRow currentRow = updateCursor.NextRow();

                        if (currentRow == null)
                            continue;

                        if (statusFieldIndex > -1)
                        {
                            currentRow.set_Value(statusFieldIndex, HttpStatusCode.OK.ToString());
                        }

                        if (statusCodeFieldIndex > -1)
                        {
                            currentRow.set_Value(statusCodeFieldIndex, (int)HttpStatusCode.OK);
                        }

                        if (newIDFieldIndex > -1)
                        {
                            currentRow.set_Value(newIDFieldIndex, newID);
                        }

                        if (osmVersionFieldIndex > -1)
                        {
                            currentRow.set_Value(osmVersionFieldIndex, newVersion);
                        }

                        if (changesetIDFieldIndex > -1)
                        {
                            currentRow.set_Value(changesetIDFieldIndex, changetSetID);
                        }

                        updateCursor.UpdateRow(currentRow);
                    }
                }
                else if (item is diffResultWay)
                {
                    diffResultWay diffWay = item as diffResultWay;
                    queryFilter.WhereClause = revisionTable.WhereClauseByExtensionVersion(diffWay.old_id, "osmoldid", extensionVersion)
                        + " AND " + sqlFormatter.SqlIdentifier("osmelementtype") + " = 'way'" + " AND " + sqlFormatter.SqlIdentifier("osmstatuscode") + " IS NULL";

                    long newID = -1;
                    int newVersion = -1;
                    long oldID = -1;

                    long.TryParse(diffWay.new_id, out newID);
                    int.TryParse(diffWay.new_version, out newVersion);
                    long.TryParse(diffWay.old_id, out oldID);

                    //
                    if (wayIDLookup.ContainsKey(oldID) == false)
                    {
                        wayIDLookup.Add(oldID, newID);
                    }

                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        ICursor updateCursor = revisionTable.Update(queryFilter, false);
                        comReleaser.ManageLifetime(updateCursor);

                        IRow currentRow = updateCursor.NextRow();

                        if (currentRow == null)
                            continue;

                        string sourceFCName = String.Empty;
                        if (sourceFCNameFieldIndex > -1)
                        {
                            sourceFCName = currentRow.get_Value(sourceFCNameFieldIndex) as string;
                        }

                        if (string.IsNullOrEmpty(sourceFCName))
                            continue;

                        if (sourceFCName.Contains("_osm_ln"))
                        {
                            updateSource((ITable)lineFeatureClass, determineAction(diffWay), Convert.ToInt64(diffWay.old_id), newID, userName, userID, newVersion, Convert.ToInt32(changetSetID), nodeIDLookup, wayIDLookup, relationIDLookup, extensionVersion);
                        }
                        else if (sourceFCName.Contains("_osm_ply"))
                        {
                            updateSource((ITable)polygonFeatureClass, determineAction(diffWay), Convert.ToInt64(diffWay.old_id), newID, userName, userID, newVersion, Convert.ToInt32(changetSetID), nodeIDLookup, wayIDLookup, relationIDLookup, extensionVersion);
                        }

                        if (statusFieldIndex > -1)
                        {
                            currentRow.set_Value(statusFieldIndex, HttpStatusCode.OK.ToString());
                        }

                        if (statusCodeFieldIndex > -1)
                        {
                            currentRow.set_Value(statusCodeFieldIndex, (int)HttpStatusCode.OK);
                        }

                        if (newIDFieldIndex > -1)
                        {
                            currentRow.set_Value(newIDFieldIndex, newID);
                        }

                        if (osmVersionFieldIndex > -1)
                        {
                            currentRow.set_Value(osmVersionFieldIndex, newVersion);
                        }

                        if (changesetIDFieldIndex > -1)
                        {
                            currentRow.set_Value(changesetIDFieldIndex, changetSetID);
                        }

                        updateCursor.UpdateRow(currentRow);
                    }
                }
                else if (item is diffResultRelation)
                {
                    diffResultRelation diffRelation = item as diffResultRelation;
                    queryFilter.WhereClause = revisionTable.WhereClauseByExtensionVersion(diffRelation.old_id, "osmoldid", extensionVersion)
                        + " AND " + sqlFormatter.SqlIdentifier("osmelementtype") + " = 'relation'" + " AND " + sqlFormatter.SqlIdentifier("osmstatuscode") + " IS NULL"; ;

                    long newID = -1;
                    int newVersion = -1;
                    long oldID = -1;

                    long.TryParse(diffRelation.new_id, out newID);
                    int.TryParse(diffRelation.new_version, out newVersion);
                    long.TryParse(diffRelation.old_id, out oldID);

                    //
                    if (relationIDLookup.ContainsKey(oldID) == false)
                    {
                        relationIDLookup.Add(oldID, newID);
                    }

                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        ICursor updateCursor = revisionTable.Update(queryFilter, false);
                        comReleaser.ManageLifetime(updateCursor);

                        IRow currentRow = updateCursor.NextRow();

                        if (currentRow == null)
                            continue;

                        string sourceFCName = String.Empty;
                        if (sourceFCNameFieldIndex > -1)
                        {
                            sourceFCName = currentRow.get_Value(sourceFCNameFieldIndex) as string;
                        }

                        if (string.IsNullOrEmpty(sourceFCName))
                            continue;

                        if (sourceFCName.Contains("_osm_ln"))
                        {
                            updateSource((ITable)lineFeatureClass, determineAction(diffRelation), Convert.ToInt64(diffRelation.old_id), newID, userName, userID, newVersion, Convert.ToInt32(changetSetID), nodeIDLookup, wayIDLookup, relationIDLookup, extensionVersion);
                        }
                        else if (sourceFCName.Contains("_osm_ply"))
                        {
                            updateSource((ITable)polygonFeatureClass, determineAction(diffRelation), Convert.ToInt64(diffRelation.old_id), newID, userName, userID, newVersion, Convert.ToInt32(changetSetID), nodeIDLookup, wayIDLookup, relationIDLookup, extensionVersion);
                        }
                        else if (sourceFCName.Contains("_osm_relation"))
                        {
                            updateSource(relationTable, determineAction(diffRelation), Convert.ToInt64(diffRelation.old_id), newID, userName, userID, newVersion, Convert.ToInt32(changetSetID), nodeIDLookup, wayIDLookup, relationIDLookup, extensionVersion);
                        }

                        if (statusFieldIndex > -1)
                        {
                            currentRow.set_Value(statusFieldIndex, HttpStatusCode.OK.ToString());
                        }

                        if (statusCodeFieldIndex > -1)
                        {
                            currentRow.set_Value(statusCodeFieldIndex, (int)HttpStatusCode.OK);
                        }

                        if (newIDFieldIndex > -1)
                        {
                            currentRow.set_Value(newIDFieldIndex, newID);
                        }

                        if (osmVersionFieldIndex > -1)
                        {
                            currentRow.set_Value(osmVersionFieldIndex, newVersion);
                        }

                        if (changesetIDFieldIndex > -1)
                        {
                            currentRow.set_Value(changesetIDFieldIndex, changetSetID);
                        }

                        updateCursor.UpdateRow(currentRow);
                    }
                }
            }
        }
        public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriSystem.ITrackCancel TrackCancel, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr, ESRI.ArcGIS.Geodatabase.IGPMessages message)
        {
            try
            {
                IGPUtilities3 execute_Utilities = new GPUtilitiesClass();
                OSMUtility osmUtility = new OSMUtility();

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

                IGPParameter inputOSMParameter = paramvalues.get_Element(in_osmFeatureClassNumber) as IGPParameter;
                IGPValue inputOSMGPValue = execute_Utilities.UnpackGPValue(inputOSMParameter);

                IGPParameter tagFieldsParameter = paramvalues.get_Element(in_attributeSelectorNumber) as IGPParameter;
                IGPMultiValue tagCollectionGPValue = execute_Utilities.UnpackGPValue(tagFieldsParameter) as IGPMultiValue;

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

                IFeatureClass osmFeatureClass = null;
                ITable osmInputTable = null;
                IQueryFilter osmQueryFilter = null;

                try
                {
                    execute_Utilities.DecodeFeatureLayer(inputOSMGPValue, out osmFeatureClass, out osmQueryFilter);
                    osmInputTable = osmFeatureClass as ITable;
                }
                catch { }

                try
                {
                    if (osmInputTable == null)
                    {
                        execute_Utilities.DecodeTableView(inputOSMGPValue, out osmInputTable, out osmQueryFilter);
                    }
                }
                catch { }

                if (osmInputTable == null)
                {
                    return;
                }

                // find the field that holds tag binary/xml field
                int osmTagCollectionFieldIndex = osmInputTable.FindField("osmTags");

                // if the Field doesn't exist - wasn't found (index = -1) get out
                if (osmTagCollectionFieldIndex == -1)
                {
                    message.AddError(120005, resourceManager.GetString("GPTools_OSMGPAttributeSelector_notagfieldfound"));
                    return;
                }

                // set up the progress indicator
                IStepProgressor stepProgressor = TrackCancel as IStepProgressor;

                if (stepProgressor != null)
                {
                    int featureCount = osmInputTable.RowCount(osmQueryFilter);

                    stepProgressor.MinRange = 0;
                    stepProgressor.MaxRange = featureCount;
                    stepProgressor.Position = 0;
                    stepProgressor.Message = resourceManager.GetString("GPTools_OSMGPCombineAttributes_progressMessage");
                    stepProgressor.StepValue = 1;
                    stepProgressor.Show();
                }

                String illegalCharacters = String.Empty;

                ISQLSyntax sqlSyntax = ((IDataset)osmInputTable).Workspace as ISQLSyntax;
                if (sqlSyntax != null)
                {
                    illegalCharacters = sqlSyntax.GetInvalidCharacters();
                }

                // establish the list of field indexes only once
                Dictionary<string, int> fieldIndexes = new Dictionary<string, int>();
                for (int selectedGPValueIndex = 0; selectedGPValueIndex < tagCollectionGPValue.Count; selectedGPValueIndex++)
                {
                    // find the field index
                    int fieldIndex = osmInputTable.FindField(tagCollectionGPValue.get_Value(selectedGPValueIndex).GetAsText());

                    if (fieldIndex != -1)
                    {
                        string tagKeyName = osmInputTable.Fields.get_Field(fieldIndex).Name;

                        tagKeyName = OSMToolHelper.convert2OSMKey(tagKeyName, illegalCharacters);

                        fieldIndexes.Add(tagKeyName, fieldIndex);
                    }
                }

                ICursor updateCursor = null;
                IRow osmRow = null;

                using (ComReleaser comReleaser = new ComReleaser())
                {
                    updateCursor = osmInputTable.Update(osmQueryFilter, false);
                    comReleaser.ManageLifetime(updateCursor);

                    osmRow = updateCursor.NextRow();
                    int progressIndex = 0;

                    while (osmRow != null)
                    {
                        // get the current tag collection from the row
                        ESRI.ArcGIS.OSM.OSMClassExtension.tag[] osmTags = osmUtility.retrieveOSMTags(osmRow, osmTagCollectionFieldIndex, ((IDataset)osmInputTable).Workspace);

                        Dictionary<string, string> tagsDictionary = new Dictionary<string, string>();
                        for (int tagIndex = 0; tagIndex < osmTags.Length; tagIndex++)
                        {
                            tagsDictionary.Add(osmTags[tagIndex].k, osmTags[tagIndex].v);
                        }

                        // look if the tag needs to be updated or added
                        bool tagsUpdated = false;
                        foreach (var fieldItem in fieldIndexes)
                        {
                            object fldValue = osmRow.get_Value(fieldItem.Value);
                            if (fldValue != System.DBNull.Value)
                            {
                                if (tagsDictionary.ContainsKey(fieldItem.Key))
                                {
                                    if (!tagsDictionary[fieldItem.Key].Equals(fldValue))
                                    {
                                        tagsDictionary[fieldItem.Key] = Convert.ToString(fldValue);
                                        tagsUpdated = true;
                                    }
                                }
                                else
                                {
                                    tagsDictionary.Add(fieldItem.Key, Convert.ToString(fldValue));
                                    tagsUpdated = true;
                                }
                            }
                        }

                        if (tagsUpdated)
                        {
                            List<ESRI.ArcGIS.OSM.OSMClassExtension.tag> updatedTags = new List<ESRI.ArcGIS.OSM.OSMClassExtension.tag>();

                            foreach (var tagItem in tagsDictionary)
                            {
                                ESRI.ArcGIS.OSM.OSMClassExtension.tag newTag = new ESRI.ArcGIS.OSM.OSMClassExtension.tag();
                                newTag.k = tagItem.Key;
                                newTag.v = tagItem.Value;
                                updatedTags.Add(newTag);
                            }

                            // insert the tags back into the collection field
                            if (updatedTags.Count != 0)
                            {
                                osmUtility.insertOSMTags(osmTagCollectionFieldIndex, osmRow, updatedTags.ToArray(), ((IDataset)osmInputTable).Workspace);

                                updateCursor.UpdateRow(osmRow);
                            }
                        }

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

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

                        osmRow = updateCursor.NextRow();
                    }

                    if (stepProgressor != null)
                    {
                        stepProgressor.Hide();
                    }
                }
            }
            catch (Exception ex)
            {
                message.AddError(120007, ex.Message);
            }
        }
        public void UpdateParameters(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager pEnvMgr)
        {
            try
            {
                IGPUtilities3 gpUtilities3 = new GPUtilitiesClass();

                IGPParameter inputOSMParameter = paramvalues.get_Element(in_osmFeatureClassNumber) as IGPParameter;
                IGPValue inputOSMGPValue = gpUtilities3.UnpackGPValue(inputOSMParameter);

                if (inputOSMGPValue.IsEmpty() == false)
                {
                    if (inputOSMParameter.Altered == true)
                    {

                        IGPParameter attributeCollectionParameter = paramvalues.get_Element(in_attributeSelectorNumber) as IGPParameter;
                        IGPValue attributeCollectionGPValue = gpUtilities3.UnpackGPValue(attributeCollectionParameter);

                        if (inputOSMParameter.HasBeenValidated == false && ((IGPMultiValue)attributeCollectionGPValue).Count == 0)
                        {
                            IFeatureClass osmFeatureClass = null;
                            ITable osmInputTable = null;
                            IQueryFilter osmQueryFilter = null;

                            try
                            {
                                gpUtilities3.DecodeFeatureLayer(inputOSMGPValue, out osmFeatureClass, out osmQueryFilter);
                                osmInputTable = osmFeatureClass as ITable;
                            }
                            catch { }

                            try
                            {
                                if (osmInputTable == null)
                                {
                                    gpUtilities3.DecodeTableView(inputOSMGPValue, out osmInputTable, out osmQueryFilter);
                                }
                            }
                            catch { }

                            if (osmInputTable == null)
                            {
                                return;
                            }

                            using (ComReleaser comReleaser = new ComReleaser())
                            {
                                ICursor osmCursor = osmInputTable.Search(osmQueryFilter, true);
                                comReleaser.ManageLifetime(osmCursor);

                                IRow osmRow = osmCursor.NextRow();
                                List<string> potentialOSMFields = new List<string>();

                                if (osmRow != null)
                                {
                                    IFields osmFields = osmRow.Fields;

                                    for (int fieldIndex = 0; fieldIndex < osmFields.FieldCount; fieldIndex++)
                                    {
                                        if (osmFields.get_Field(fieldIndex).Name.Substring(0, 4).Equals("osm_"))
                                        {
                                            potentialOSMFields.Add(osmFields.get_Field(fieldIndex).Name);
                                        }
                                    }
                                }

                                if (potentialOSMFields.Count == 0)
                                {
                                    return;
                                }

                                IGPCodedValueDomain osmTagKeyCodedValues = new GPCodedValueDomainClass();
                                foreach (string tagOSMField in potentialOSMFields)
                                {
                                    osmTagKeyCodedValues.AddStringCode(tagOSMField, tagOSMField);
                                }

                                ((IGPParameterEdit)attributeCollectionParameter).Domain = (IGPDomain)osmTagKeyCodedValues;

                            }
                        }
                    }
                }
            }
            catch { }
        }
        public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriSystem.ITrackCancel TrackCancel, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr, ESRI.ArcGIS.Geodatabase.IGPMessages message)
        {
            try
            {
                IGPUtilities3 execute_Utilities = new GPUtilitiesClass();

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

                IGPParameter inputFeatureDatasetParameter = paramvalues.get_Element(in_featureDatasetParameterNumber) as IGPParameter;
                IGPValue inputFeatureDatasetGPValue = execute_Utilities.UnpackGPValue(inputFeatureDatasetParameter);
                IGPValue outputOSMFileGPValue = execute_Utilities.UnpackGPValue(paramvalues.get_Element(out_osmFileLocationParameterNumber));

                // get the name of the feature dataset
                int fdDemlimiterPosition = inputFeatureDatasetGPValue.GetAsText().LastIndexOf("\\");

                string nameOfFeatureDataset = inputFeatureDatasetGPValue.GetAsText().Substring(fdDemlimiterPosition + 1);


                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;

                System.Xml.XmlWriter xmlWriter = null;

                try
                {
                    xmlWriter = XmlWriter.Create(outputOSMFileGPValue.GetAsText(), settings);
                }
                catch (Exception ex)
                {
                    message.AddError(120021, ex.Message);
                    return;
                }

                xmlWriter.WriteStartDocument();
                xmlWriter.WriteStartElement("osm"); // start the osm root node
                xmlWriter.WriteAttributeString("version", "0.6"); // add the version attribute
                xmlWriter.WriteAttributeString("generator", "ArcGIS Editor for OpenStreetMap"); // add the generator attribute

                // write all the nodes
                // use a feature search cursor to loop through all the known points and write them out as osm node

                IFeatureClassContainer osmFeatureClasses = execute_Utilities.OpenDataset(inputFeatureDatasetGPValue) as IFeatureClassContainer;

                if (osmFeatureClasses == null)
                {
                    message.AddError(120022, string.Format(resourceManager.GetString("GPTools_NullPointerParameterType"), inputFeatureDatasetParameter.Name));
                    return;
                }

                IFeatureClass osmPointFeatureClass = osmFeatureClasses.get_ClassByName(nameOfFeatureDataset + "_osm_pt");

                if (osmPointFeatureClass == null)
                {
                    message.AddError(120023, string.Format(resourceManager.GetString("GPTools_OSMGPExport2OSM_no_pointfeatureclass"), nameOfFeatureDataset + "_osm_pt"));
                    return;
                }

                // check the extension of the point feature class to determine its version
                int internalOSMExtensionVersion = osmPointFeatureClass.OSMExtensionVersion();

                IFeatureCursor searchCursor = null;

                System.Xml.Serialization.XmlSerializerNamespaces xmlnsEmpty = new System.Xml.Serialization.XmlSerializerNamespaces();
                xmlnsEmpty.Add("", "");

                message.AddMessage(resourceManager.GetString("GPTools_OSMGPExport2OSM_exporting_pts_msg"));
                int pointCounter = 0;

                string nodesExportedMessage = String.Empty;

                // collect the indices for the point feature class once
                int pointOSMIDFieldIndex = osmPointFeatureClass.Fields.FindField("OSMID");
                int pointChangesetFieldIndex = osmPointFeatureClass.Fields.FindField("osmchangeset");
                int pointVersionFieldIndex = osmPointFeatureClass.Fields.FindField("osmversion");
                int pointUIDFieldIndex = osmPointFeatureClass.Fields.FindField("osmuid");
                int pointUserFieldIndex = osmPointFeatureClass.Fields.FindField("osmuser");
                int pointTimeStampFieldIndex = osmPointFeatureClass.Fields.FindField("osmtimestamp");
                int pointVisibleFieldIndex = osmPointFeatureClass.Fields.FindField("osmvisible");
                int pointTagsFieldIndex = osmPointFeatureClass.Fields.FindField("osmTags");

                using (ComReleaser comReleaser = new ComReleaser())
                {
                    searchCursor = osmPointFeatureClass.Search(null, false);
                    comReleaser.ManageLifetime(searchCursor);

                    System.Xml.Serialization.XmlSerializer pointSerializer = new System.Xml.Serialization.XmlSerializer(typeof(node));

                    IFeature currentFeature = searchCursor.NextFeature();

                    IWorkspace pointWorkspace = ((IDataset)osmPointFeatureClass).Workspace;

                    while (currentFeature != null)
                    {
                        if (TrackCancel.Continue() == true)
                        {
                            // convert the found point feature into a osm node representation to store into the OSM XML file
                            node osmNode = ConvertPointFeatureToOSMNode(currentFeature, pointWorkspace, pointTagsFieldIndex, pointOSMIDFieldIndex, pointChangesetFieldIndex, pointVersionFieldIndex, pointUIDFieldIndex, pointUserFieldIndex, pointTimeStampFieldIndex, pointVisibleFieldIndex, internalOSMExtensionVersion);

                            pointSerializer.Serialize(xmlWriter, osmNode, xmlnsEmpty);

                            // increase the point counter to later status report
                            pointCounter++;

                            currentFeature = searchCursor.NextFeature();
                        }
                        else
                        {
                            // properly close the document
                            xmlWriter.WriteEndElement(); // closing the osm root element
                            xmlWriter.WriteEndDocument(); // finishing the document

                            xmlWriter.Close(); // closing the document

                            // report the number of elements loader so far
                            nodesExportedMessage = String.Format(resourceManager.GetString("GPTools_OSMGPExport2OSM_pts_exported_msg"), pointCounter);
                            message.AddMessage(nodesExportedMessage);

                            return;
                        }
                    }
                }

                nodesExportedMessage = String.Format(resourceManager.GetString("GPTools_OSMGPExport2OSM_pts_exported_msg"), pointCounter);
                message.AddMessage(nodesExportedMessage);

                // next loop through the line and polygon feature classes to export those features as ways
                // in case we encounter a multi-part geometry, store it in a relation collection that will be serialized when exporting the relations table
                IFeatureClass osmLineFeatureClass = osmFeatureClasses.get_ClassByName(nameOfFeatureDataset + "_osm_ln");

                if (osmLineFeatureClass == null)
                {
                    message.AddError(120023, string.Format(resourceManager.GetString("GPTools_OSMGPExport2OSM_no_linefeatureclass"), nameOfFeatureDataset + "_osm_ln"));
                    return;
                }

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

                // as we are looping through the line and polygon feature classes let's collect the multi-part features separately 
                // as they are considered relations in the OSM world
                List<relation> multiPartElements = new List<relation>();

                System.Xml.Serialization.XmlSerializer waySerializer = new System.Xml.Serialization.XmlSerializer(typeof(way));
                int lineCounter = 0;
                int relationCounter = 0;
                string waysExportedMessage = String.Empty;

                using (ComReleaser comReleaser = new ComReleaser())
                {
                    searchCursor = osmLineFeatureClass.Search(null, false);
                    comReleaser.ManageLifetime(searchCursor);

                    IFeature currentFeature = searchCursor.NextFeature();

                    // collect the indices for the point feature class once
                    int lineOSMIDFieldIndex = osmLineFeatureClass.Fields.FindField("OSMID");
                    int lineChangesetFieldIndex = osmLineFeatureClass.Fields.FindField("osmchangeset");
                    int lineVersionFieldIndex = osmLineFeatureClass.Fields.FindField("osmversion");
                    int lineUIDFieldIndex = osmLineFeatureClass.Fields.FindField("osmuid");
                    int lineUserFieldIndex = osmLineFeatureClass.Fields.FindField("osmuser");
                    int lineTimeStampFieldIndex = osmLineFeatureClass.Fields.FindField("osmtimestamp");
                    int lineVisibleFieldIndex = osmLineFeatureClass.Fields.FindField("osmvisible");
                    int lineTagsFieldIndex = osmLineFeatureClass.Fields.FindField("osmTags");
                    int lineMembersFieldIndex = osmLineFeatureClass.Fields.FindField("osmMembers");

                    IWorkspace lineWorkspace = ((IDataset)osmLineFeatureClass).Workspace;

                    while (currentFeature != null)
                    {
                        if (TrackCancel.Continue() == false)
                        {
                            // properly close the document
                            xmlWriter.WriteEndElement(); // closing the osm root element
                            xmlWriter.WriteEndDocument(); // finishing the document

                            xmlWriter.Close(); // closing the document

                            // report the number of elements loaded so far
                            waysExportedMessage = String.Format(resourceManager.GetString("GPTools_OSMGPExport2OSM_ways_exported_msg"), lineCounter);
                            message.AddMessage(waysExportedMessage);

                            return;
                        }

                        //test if the feature geometry has multiple parts
                        IGeometryCollection geometryCollection = currentFeature.Shape as IGeometryCollection;

                        if (geometryCollection != null)
                        {
                            if (geometryCollection.GeometryCount == 1)
                            {
                                // convert the found polyline feature into a osm way representation to store into the OSM XML file
                                way osmWay = ConvertFeatureToOSMWay(currentFeature, lineWorkspace, osmPointFeatureClass, pointOSMIDFieldIndex, lineTagsFieldIndex, lineOSMIDFieldIndex, lineChangesetFieldIndex, lineVersionFieldIndex, lineUIDFieldIndex, lineUserFieldIndex, lineTimeStampFieldIndex, lineVisibleFieldIndex, internalOSMExtensionVersion);
                                waySerializer.Serialize(xmlWriter, osmWay, xmlnsEmpty);

                                // increase the line counter for later status report
                                lineCounter++;
                            }
                            else
                            {
                                relation osmRelation = ConvertRowToOSMRelation((IRow)currentFeature, lineWorkspace, lineTagsFieldIndex, lineOSMIDFieldIndex, lineChangesetFieldIndex, lineVersionFieldIndex, lineUIDFieldIndex, lineUserFieldIndex, lineTimeStampFieldIndex, lineVisibleFieldIndex, lineMembersFieldIndex, internalOSMExtensionVersion);
                                multiPartElements.Add(osmRelation);

                                // increase the line counter for later status report
                                relationCounter++;
                            }
                        }

                        currentFeature = searchCursor.NextFeature();
                    }
                }


                IFeatureClass osmPolygonFeatureClass = osmFeatureClasses.get_ClassByName(nameOfFeatureDataset + "_osm_ply");
                IFeatureWorkspace commonWorkspace = ((IDataset)osmPolygonFeatureClass).Workspace as IFeatureWorkspace;

                if (osmPolygonFeatureClass == null)
                {
                    message.AddError(120024, string.Format(resourceManager.GetString("GPTools_OSMGPExport2OSM_no_polygonfeatureclass"), nameOfFeatureDataset + "_osm_ply"));
                    return;
                }

                using (ComReleaser comReleaser = new ComReleaser())
                {
                    searchCursor = osmPolygonFeatureClass.Search(null, false);
                    comReleaser.ManageLifetime(searchCursor);

                    IFeature currentFeature = searchCursor.NextFeature();

                    // collect the indices for the point feature class once
                    int polygonOSMIDFieldIndex = osmPolygonFeatureClass.Fields.FindField("OSMID");
                    int polygonChangesetFieldIndex = osmPolygonFeatureClass.Fields.FindField("osmchangeset");
                    int polygonVersionFieldIndex = osmPolygonFeatureClass.Fields.FindField("osmversion");
                    int polygonUIDFieldIndex = osmPolygonFeatureClass.Fields.FindField("osmuid");
                    int polygonUserFieldIndex = osmPolygonFeatureClass.Fields.FindField("osmuser");
                    int polygonTimeStampFieldIndex = osmPolygonFeatureClass.Fields.FindField("osmtimestamp");
                    int polygonVisibleFieldIndex = osmPolygonFeatureClass.Fields.FindField("osmvisible");
                    int polygonTagsFieldIndex = osmPolygonFeatureClass.Fields.FindField("osmTags");
                    int polygonMembersFieldIndex = osmPolygonFeatureClass.Fields.FindField("osmMembers");

                    IWorkspace polygonWorkspace = ((IDataset)osmPolygonFeatureClass).Workspace;

                    while (currentFeature != null)
                    {
                        if (TrackCancel.Continue() == false)
                        {
                            // properly close the document
                            xmlWriter.WriteEndElement(); // closing the osm root element
                            xmlWriter.WriteEndDocument(); // finishing the document

                            xmlWriter.Close(); // closing the document

                            // report the number of elements loaded so far
                            waysExportedMessage = String.Format(resourceManager.GetString("GPTools_OSMGPExport2OSM_ways_exported_msg"), lineCounter);
                            message.AddMessage(waysExportedMessage);

                            message.AddAbort(resourceManager.GetString("GPTools_toolabort"));
                            return;
                        }

                        //test if the feature geometry has multiple parts
                        IGeometryCollection geometryCollection = currentFeature.Shape as IGeometryCollection;

                        if (geometryCollection != null)
                        {
                            if (geometryCollection.GeometryCount == 1)
                            {
                                // convert the found polyline feature into a osm way representation to store into the OSM XML file
                                way osmWay = ConvertFeatureToOSMWay(currentFeature, polygonWorkspace, osmPointFeatureClass, pointOSMIDFieldIndex, polygonTagsFieldIndex, polygonOSMIDFieldIndex, polygonChangesetFieldIndex, polygonVersionFieldIndex, polygonUIDFieldIndex, polygonUserFieldIndex, polygonTimeStampFieldIndex, polygonVisibleFieldIndex, internalOSMExtensionVersion);
                                waySerializer.Serialize(xmlWriter, osmWay, xmlnsEmpty);

                                // increase the line counter for later status report
                                lineCounter++;
                            }
                            else
                            {
                                relation osmRelation = ConvertRowToOSMRelation((IRow)currentFeature, polygonWorkspace, polygonTagsFieldIndex, polygonOSMIDFieldIndex, polygonChangesetFieldIndex, polygonVersionFieldIndex, polygonUIDFieldIndex, polygonUserFieldIndex, polygonTimeStampFieldIndex, polygonVisibleFieldIndex, polygonMembersFieldIndex, internalOSMExtensionVersion);
                                multiPartElements.Add(osmRelation);

                                // increase the line counter for later status report
                                relationCounter++;
                            }
                        }

                        currentFeature = searchCursor.NextFeature();
                    }
                }

                waysExportedMessage = String.Format(resourceManager.GetString("GPTools_OSMGPExport2OSM_ways_exported_msg"), lineCounter);
                message.AddMessage(waysExportedMessage);


                // now let's go through the relation table 
                message.AddMessage(resourceManager.GetString("GPTools_OSMGPExport2OSM_exporting_relations_msg"));
                ITable relationTable = commonWorkspace.OpenTable(nameOfFeatureDataset + "_osm_relation");

                if (relationTable == null)
                {
                    message.AddError(120025, String.Format(resourceManager.GetString("GPTools_OSMGPExport2OSM_no_relationTable"), nameOfFeatureDataset + "_osm_relation"));
                    return;
                }


                System.Xml.Serialization.XmlSerializer relationSerializer = new System.Xml.Serialization.XmlSerializer(typeof(relation));
                string relationsExportedMessage = String.Empty;

                using (ComReleaser comReleaser = new ComReleaser())
                {
                    ICursor rowCursor = relationTable.Search(null, false);
                    comReleaser.ManageLifetime(rowCursor);

                    IRow currentRow = rowCursor.NextRow();

                    // collect the indices for the relation table once
                    int relationOSMIDFieldIndex = relationTable.Fields.FindField("OSMID");
                    int relationChangesetFieldIndex = relationTable.Fields.FindField("osmchangeset");
                    int relationVersionFieldIndex = relationTable.Fields.FindField("osmversion");
                    int relationUIDFieldIndex = relationTable.Fields.FindField("osmuid");
                    int relationUserFieldIndex = relationTable.Fields.FindField("osmuser");
                    int relationTimeStampFieldIndex = relationTable.Fields.FindField("osmtimestamp");
                    int relationVisibleFieldIndex = relationTable.Fields.FindField("osmvisible");
                    int relationTagsFieldIndex = relationTable.Fields.FindField("osmTags");
                    int relationMembersFieldIndex = relationTable.Fields.FindField("osmMembers");

                    IWorkspace polygonWorkspace = ((IDataset)osmPolygonFeatureClass).Workspace;


                    while (currentRow != null)
                    {
                        if (TrackCancel.Continue() == false)
                        {
                            // properly close the document
                            xmlWriter.WriteEndElement(); // closing the osm root element
                            xmlWriter.WriteEndDocument(); // finishing the document

                            xmlWriter.Close(); // closing the document

                            // report the number of elements loaded so far
                            relationsExportedMessage = String.Format(resourceManager.GetString("GPTools_OSMGPExport2OSM_relations_exported_msg"), relationCounter);
                            message.AddMessage(relationsExportedMessage);

                            message.AddAbort(resourceManager.GetString("GPTools_toolabort"));
                            return;
                        }

                        relation osmRelation = ConvertRowToOSMRelation(currentRow, (IWorkspace)commonWorkspace, relationTagsFieldIndex, relationOSMIDFieldIndex, relationChangesetFieldIndex, relationVersionFieldIndex, relationUIDFieldIndex, relationUserFieldIndex, relationTimeStampFieldIndex, relationVisibleFieldIndex, relationMembersFieldIndex, internalOSMExtensionVersion);
                        relationSerializer.Serialize(xmlWriter, osmRelation, xmlnsEmpty);

                        // increase the line counter for later status report
                        relationCounter++;

                        currentRow = rowCursor.NextRow();
                    }
                }

                // lastly let's serialize the collected multipart-geometries back into relation elements
                foreach (relation currentRelation in multiPartElements)
                {
                    if (TrackCancel.Continue() == false)
                    {
                        // properly close the document
                        xmlWriter.WriteEndElement(); // closing the osm root element
                        xmlWriter.WriteEndDocument(); // finishing the document

                        xmlWriter.Close(); // closing the document

                        // report the number of elements loaded so far
                        relationsExportedMessage = String.Format(resourceManager.GetString("GPTools_OSMGPExport2OSM_relations_exported_msg"), relationCounter);
                        message.AddMessage(relationsExportedMessage);

                        return;
                    }

                    relationSerializer.Serialize(xmlWriter, currentRelation, xmlnsEmpty);
                    relationCounter++;
                }

                relationsExportedMessage = String.Format(resourceManager.GetString("GPTools_OSMGPExport2OSM_relations_exported_msg"), relationCounter);
                message.AddMessage(relationsExportedMessage);


                xmlWriter.WriteEndElement(); // closing the osm root element
                xmlWriter.WriteEndDocument(); // finishing the document

                xmlWriter.Close(); // closing the document
            }
            catch (Exception ex)
            {
                message.AddError(120026, ex.Message);
            }
        }
        private IFeature FindJunctionFeature(string osmid)
        {
            IFeatureClass fcPoint = OsmPointFeatureClass;

            IQueryFilter filter = new QueryFilterClass();
            filter.SubFields = string.Join(",", new string[] { fcPoint.OIDFieldName, fcPoint.ShapeFieldName, "OSMID" });
            filter.WhereClause = fcPoint.WhereClauseByExtensionVersion(osmid, "OSMID", OsmExtVersion);

            using (ComReleaser cr = new ComReleaser())
            {
                IFeatureCursor cursor = fcPoint.Search(filter, false);
                cr.ManageLifetime(cursor);

                IFeature feature = cursor.NextFeature();
                if (feature != null)
                    return feature;
            }

            return null;
        }
        public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriSystem.ITrackCancel TrackCancel, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr, ESRI.ArcGIS.Geodatabase.IGPMessages message)
        {
            try
            {
                IGPUtilities3 execute_Utilities = new GPUtilitiesClass();

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

                IGPParameter inputOSMParameter = paramvalues.get_Element(in_osmFeatureClass) as IGPParameter;
                IGPValue inputOSMGPValue = execute_Utilities.UnpackGPValue(inputOSMParameter);

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

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

                bool useUpdateCursor = false;

                IFeatureClass osmFeatureClass = null;
                ITable osmInputTable = null;
                IQueryFilter osmQueryFilter = null;

                try
                {
                    execute_Utilities.DecodeFeatureLayer(inputOSMGPValue, out osmFeatureClass, out osmQueryFilter);
                    if (osmFeatureClass != null)
                    {
                        if (osmFeatureClass.Extension is IOSMClassExtension)
                        {
                            useUpdateCursor = false;
                        }
                        else
                        {
                            useUpdateCursor = true;
                        }
                    }

                    osmInputTable = osmFeatureClass as ITable;
                }
                catch { }

                try
                {
                    if (osmInputTable == null)
                    {
                        execute_Utilities.DecodeTableView(inputOSMGPValue, out osmInputTable, out osmQueryFilter);
                    }
                }
                catch { }

                if (osmInputTable == null)
                {
                    string errorMessage = String.Format(resourceManager.GetString("GPTools_OSMGPAttributeSelecto_unableopentable"), inputOSMGPValue.GetAsText());
                    message.AddError(120053, errorMessage);
                    return;
                }

                // find the field that holds tag binary/xml field
                int osmTagCollectionFieldIndex = osmInputTable.FindField("osmTags");

                // if the Field doesn't exist - wasn't found (index = -1) get out
                if (osmTagCollectionFieldIndex == -1)
                {
                    message.AddError(120005, resourceManager.GetString("GPTools_OSMGPAttributeSelector_notagfieldfound"));
                    return;
                }

                // check if the tag collection includes the keyword "ALL", if does then we'll need to extract all tags
                bool extractAll = false;
                for (int valueIndex = 0; valueIndex < tagCollectionGPValue.Count; valueIndex++)
                {
                    if (tagCollectionGPValue.get_Value(valueIndex).GetAsText().Equals("ALL"))
                    {
                        extractAll = true;
                        break;
                    }
                }
                //if (extractAll)
                //{
                //    if (osmTagKeyCodedValues == null)
                //        extractAllTags(ref osmTagKeyCodedValues, osmInputTable, osmQueryFilter, osmTagCollectionFieldIndex, false);

                //    if (osmTagKeyCodedValues == null)
                //    {
                //        message.AddAbort(resourceManager.GetString("GPTools_OSMGPAttributeSelector_Unable2RetrieveTags"));
                //        return;
                //    }

                //    // empty the existing gp multivalue object
                //    tagCollectionGPValue = new GPMultiValueClass();

                //    // fill the coded domain in gp multivalue object
                //    for (int valueIndex = 0; valueIndex < osmTagKeyCodedValues.CodeCount; valueIndex++)
                //    {
                //        tagCollectionGPValue.AddValue(osmTagKeyCodedValues.get_Value(valueIndex));
                //    }
                //}

                // get an overall feature count as that determines the progress indicator
                int featureCount = osmInputTable.RowCount(osmQueryFilter);

                // set up the progress indicator
                IStepProgressor stepProgressor = TrackCancel as IStepProgressor;

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

                // let's get all the indices of the desired fields
                // if the field already exists get the index and if it doesn't exist create it
                Dictionary<string, int> tagsAttributesIndices = new Dictionary<string, int>();
                Dictionary<int, int> attributeFieldLength = new Dictionary<int, int>();

                IFeatureWorkspaceManage featureWorkspaceManage = ((IDataset)osmInputTable).Workspace as IFeatureWorkspaceManage;

                String illegalCharacters = String.Empty;

                ISQLSyntax sqlSyntax = ((IDataset)osmInputTable).Workspace as ISQLSyntax;
                if (sqlSyntax != null)
                {
                    illegalCharacters = sqlSyntax.GetInvalidCharacters();
                }

                IFieldsEdit fieldsEdit = osmInputTable.Fields as IFieldsEdit;

                using (SchemaLockManager lockMgr = new SchemaLockManager(osmInputTable))
                {
                    try
                    {
                        string tagKey = String.Empty;
                        ESRI.ArcGIS.Geoprocessing.IGeoProcessor2 gp = new ESRI.ArcGIS.Geoprocessing.GeoProcessorClass();

                        // if we have explicitly defined tags to extract then go through the list of values now
                        if (extractAll == false)
                        {
                            for (int valueIndex = 0; valueIndex < tagCollectionGPValue.Count; valueIndex++)
                            {
                                if (TrackCancel.Continue() == false)
                                    return;

                                try
                                {
                                    // Check if the input field already exists.
                                    string nameofTag = tagCollectionGPValue.get_Value(valueIndex).GetAsText();
                                    tagKey = convert2AttributeFieldName(nameofTag, illegalCharacters);

                                    int fieldIndex = osmInputTable.FindField(tagKey);

                                    if (fieldIndex < 0)
                                    {
                                        // generate a new attribute field
                                        IFieldEdit fieldEdit = new FieldClass();
                                        fieldEdit.Name_2 = tagKey;
                                        fieldEdit.AliasName_2 = nameofTag + resourceManager.GetString("GPTools_OSMGPAttributeSelector_aliasaddition");
                                        fieldEdit.Type_2 = esriFieldType.esriFieldTypeString;
                                        fieldEdit.Length_2 = 100;

                                        osmInputTable.AddField(fieldEdit);

                                        message.AddMessage(string.Format(resourceManager.GetString("GPTools_OSMGPAttributeSelector_addField"), tagKey, nameofTag));

                                        // re-generate the attribute index
                                        fieldIndex = osmInputTable.FindField(tagKey);
                                    }

                                    if (fieldIndex > 0)
                                    {
                                        tagsAttributesIndices.Add(nameofTag, fieldIndex);
                                        attributeFieldLength.Add(fieldIndex, osmInputTable.Fields.get_Field(fieldIndex).Length);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    // the key is already there, this might result because from multiple upper and lower-case combinations of the same key
                                    message.AddWarning(ex.Message + " (" + convert2OSMKey(tagKey, illegalCharacters) + ")");
                                }
                            }
                        }
                        else
                        {
                            List<string> listofAllTags = extractAllTags(osmInputTable, osmQueryFilter, osmTagCollectionFieldIndex);

                            foreach (string nameOfTag in listofAllTags)
                            {
                                if (TrackCancel.Continue() == false)
                                    return;

                                try
                                {
                                    // Check if the input field already exists.
                                    tagKey = convert2AttributeFieldName(nameOfTag, illegalCharacters);

                                    int fieldIndex = osmInputTable.FindField(tagKey);

                                    if (fieldIndex < 0)
                                    {
                                        // generate a new attribute field
                                        IFieldEdit fieldEdit = new FieldClass();
                                        fieldEdit.Name_2 = tagKey;
                                        fieldEdit.AliasName_2 = nameOfTag + resourceManager.GetString("GPTools_OSMGPAttributeSelector_aliasaddition");
                                        fieldEdit.Type_2 = esriFieldType.esriFieldTypeString;
                                        fieldEdit.Length_2 = 100;

                                        osmInputTable.AddField(fieldEdit);

                                        message.AddMessage(string.Format(resourceManager.GetString("GPTools_OSMGPAttributeSelector_addField"), tagKey, nameOfTag));

                                        // re-generate the attribute index
                                        fieldIndex = osmInputTable.FindField(tagKey);
                                    }

                                    if (fieldIndex > 0)
                                    {
                                        tagsAttributesIndices.Add(nameOfTag, fieldIndex);
                                        attributeFieldLength.Add(fieldIndex, osmInputTable.Fields.get_Field(fieldIndex).Length);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    // the key is already there, this might result because from multiple upper and lower-case combinations of the same key
                                    message.AddWarning(ex.Message + " (" + convert2OSMKey(tagKey, illegalCharacters) + ")");
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        message.AddWarning(ex.Message);
                    }
                }

                try
                {
                    execute_Utilities.DecodeFeatureLayer(inputOSMGPValue, out osmFeatureClass, out osmQueryFilter);
                    if (osmFeatureClass != null)
                    {
                        if (osmFeatureClass.Extension is IOSMClassExtension)
                        {
                            useUpdateCursor = false;
                        }
                        else
                        {
                            useUpdateCursor = true;
                        }
                    }

                    osmInputTable = osmFeatureClass as ITable;
                }
                catch { }

                try
                {
                    if (osmInputTable == null)
                    {
                        execute_Utilities.DecodeTableView(inputOSMGPValue, out osmInputTable, out osmQueryFilter);
                    }
                }
                catch { }

                if (osmInputTable == null)
                {
                    string errorMessage = String.Format(resourceManager.GetString("GPTools_OSMGPAttributeSelecto_unableopentable"), inputOSMGPValue.GetAsText());
                    message.AddError(120053, errorMessage);
                    return;
                }

                using (ComReleaser comReleaser = new ComReleaser())
                {

                    using (SchemaLockManager lockMgr = new SchemaLockManager(osmInputTable))
                    {
                        // get an update cursor for all the features to process
                        ICursor rowCursor = null;
                        if (useUpdateCursor)
                        {
                            rowCursor = osmInputTable.Update(osmQueryFilter, false);
                        }
                        else
                        {
                            rowCursor = osmInputTable.Search(osmQueryFilter, false);
                        }

                        comReleaser.ManageLifetime(rowCursor);

                        IRow osmRow = null;

                        Dictionary<string, string> tagKeys = new Dictionary<string, string>();
                        int progessIndex = 0;
            #if DEBUG
                        message.AddMessage("useUpdateCursor: " + useUpdateCursor.ToString());
            #endif

                        // as long as there are features....
                        while ((osmRow = rowCursor.NextRow()) != null)
                        {
                            // retrieve the tags of the current feature
                            tag[] storedTags = _osmUtility.retrieveOSMTags(osmRow, osmTagCollectionFieldIndex, ((IDataset)osmInputTable).Workspace);

                            bool rowChanged = false;
                            if (storedTags != null)
                            {
                                foreach (tag tagItem in storedTags)
                                {
                                    // Check for matching values so we only change a minimum number of rows
                                    if (tagsAttributesIndices.ContainsKey(tagItem.k))
                                    {
                                        int fieldIndex = tagsAttributesIndices[tagItem.k];

                                        //...then stored the value in the attribute field
                                        // ensure that the content of the tag actually does fit into the field length...otherwise do truncate it
                                        string tagValue = tagItem.v;

                                        int fieldLength = attributeFieldLength[fieldIndex];

                                        if (tagValue.Length > fieldLength)
                                            tagValue = tagValue.Substring(0, fieldLength);

                                        osmRow.set_Value(fieldIndex, tagValue);
                                        rowChanged = true;
                                    }
                                    else
                                    {
            #if DEBUG
                                        //message.AddWarning(tagItem.k);
            #endif
                                    }
                                }
                            }

                            storedTags = null;

                            try
                            {
                                if (rowChanged)
                                {
                                    if (useUpdateCursor)
                                    {
                                        rowCursor.UpdateRow(osmRow);
                                    }
                                    else
                                    {
                                        // update the feature through the cursor
                                        osmRow.Store();
                                    }
                                }
                                progessIndex++;
                            }
                            catch (Exception ex)
                            {
                                System.Diagnostics.Debug.WriteLine(ex.Message);
                                message.AddWarning(ex.Message);
                            }

                            if (osmRow != null)
                            {
                                Marshal.ReleaseComObject(osmRow);
                            }

                            if (stepProgressor != null)
                            {
                                // update the progress UI
                                stepProgressor.Position = progessIndex;
                            }

                            // check for user cancellation (every 100 rows)
                            if ((progessIndex % 100 == 0) && (TrackCancel.Continue() == false))
                            {
                                return;
                            }
                        }

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

                execute_Utilities.ReleaseInternals();
                Marshal.ReleaseComObject(execute_Utilities);
            }
            catch (Exception ex)
            {
                message.AddError(120054, ex.Message);
            }
        }
        public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriSystem.ITrackCancel TrackCancel, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr, ESRI.ArcGIS.Geodatabase.IGPMessages message)
        {
            _message = message;

            IFeatureClass osmPointFeatureClass = null;
            IFeatureClass osmLineFeatureClass = null;
            IFeatureClass osmPolygonFeatureClass = null;

            try
            {
                DateTime syncTime = DateTime.Now;

                IGPUtilities3 gpUtilities3 = new GPUtilitiesClass();

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

                IGPParameter baseURLParameter = paramvalues.get_Element(in_downloadURLNumber) as IGPParameter;
                IGPString baseURLString = gpUtilities3.UnpackGPValue(baseURLParameter) as IGPString;

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

                IGPParameter downloadExtentParameter = paramvalues.get_Element(in_downloadExtentNumber) as IGPParameter;
                IGPValue downloadExtentGPValue = gpUtilities3.UnpackGPValue(downloadExtentParameter);

                esriGPExtentEnum gpExtent;
                IEnvelope downloadEnvelope = gpUtilities3.GetExtent(downloadExtentGPValue, out gpExtent);

                IGPParameter includeAllReferences = paramvalues.get_Element(in_includeReferencesNumber) as IGPParameter;
                IGPBoolean includeAllReferencesGPValue = gpUtilities3.UnpackGPValue(includeAllReferences) as IGPBoolean;

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

                IEnvelope newExtent = null;

                ISpatialReferenceFactory spatialReferenceFactory = new SpatialReferenceEnvironmentClass() as ISpatialReferenceFactory;
                ISpatialReference wgs84 = spatialReferenceFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984) as ISpatialReference;

                // this determines the spatial reference as defined from the gp environment settings and the initial wgs84 SR
                ISpatialReference downloadSpatialReference = gpUtilities3.GetGPSpRefEnv(envMgr, wgs84, newExtent, 0, 0, 0, 0, null);

                downloadEnvelope.Project(wgs84);

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

                HttpWebRequest httpClient;
                System.Xml.Serialization.XmlSerializer serializer = null;
                serializer = new XmlSerializer(typeof(osm));

                // get the capabilities from the server
                HttpWebResponse httpResponse = null;

                api apiCapabilities = null;
                CultureInfo enUSCultureInfo = new CultureInfo("en-US");

#if DEBUG
                Console.WriteLine("Debbuging");
                message.AddMessage("Debugging...");
#endif

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

                try
                {
                    httpClient = HttpWebRequest.Create(baseURLString.Value + "/api/capabilities") as HttpWebRequest;
                    httpClient = AssignProxyandCredentials(httpClient);

                    httpResponse = httpClient.GetResponse() as HttpWebResponse;

                    osm osmCapabilities = null;

                    Stream stream = httpResponse.GetResponseStream();

                    XmlTextReader xmlReader = new XmlTextReader(stream);
                    osmCapabilities = serializer.Deserialize(xmlReader) as osm;
                    xmlReader.Close();

                    apiCapabilities = osmCapabilities.Items[0] as api;

                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    message.AddError(120009, ex.Message);

                    if (ex is WebException)
                    {
                        WebException webException = ex as WebException;
                        string serverErrorMessage = webException.Response.Headers["Error"];
                        if (!String.IsNullOrEmpty(serverErrorMessage))
                        {
                            message.AddError(120009, serverErrorMessage);
                        }
                    }

                }
                finally
                {
                    if (httpResponse != null)
                    {
                        httpResponse.Close();
                    }
                    httpClient = null;
                }

                if (apiCapabilities != null)
                {
                    // check for the extent
                    double roiArea = ((IArea)downloadEnvelope).Area;
                    double capabilitiyArea = Convert.ToDouble(apiCapabilities.area.maximum, new CultureInfo("en-US"));

                    if (roiArea > capabilitiyArea)
                    {
                        message.AddAbort(resourceManager.GetString("GPTools_OSMGPDownload_exceedDownloadROI"));
                        return;
                    }
                }

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

                // list containing either only one document for a single bbox request or multiple if relation references need to be resolved
                List<string> downloadedOSMDocuments = new List<string>();

                string requestURL = baseURLString.Value + "/api/0.6/map?bbox=" + downloadEnvelope.XMin.ToString("f5", enUSCultureInfo) + "," + downloadEnvelope.YMin.ToString("f5", enUSCultureInfo) + "," + downloadEnvelope.XMax.ToString("f5", enUSCultureInfo) + "," + downloadEnvelope.YMax.ToString("f5", enUSCultureInfo);
                string osmMasterDocument = downloadOSMDocument(ref message, requestURL, apiCapabilities);

                // check if the initial request was successfull
                // it might have failed at this point because too many nodes were requested or because of something else
                if (String.IsNullOrEmpty(osmMasterDocument))
                {
                    message.AddAbort(resourceManager.GetString("GPTools_OSMGPDownload_noValidOSMResponse"));
                    return;
                }

                // add the "master document" ) original bbox request to the list
                downloadedOSMDocuments.Add(osmMasterDocument);

                if (includeAllReferencesGPValue.Value)
                {
                    List<string> nodeList = new List<string>();
                    List<string> wayList = new List<string>();
                    List<string> relationList = new List<string>();
                    // check for user interruption
                    if (TrackCancel.Continue() == false)
                    {
                        return;
                    }

                    parseOSMDocument(osmMasterDocument, ref message, ref nodeList, ref wayList, ref relationList, ref downloadedOSMDocuments, baseURLString.Value, apiCapabilities);
                }

                string metadataAbstract = resourceManager.GetString("GPTools_OSMGPDownload_metadata_abstract");
                string metadataPurpose = resourceManager.GetString("GPTools_OSMGPDownload_metadata_purpose");

                IGPParameter targetDatasetParameter = paramvalues.get_Element(out_targetDatasetNumber) as IGPParameter;
                IDEDataset2 targetDEDataset2 = gpUtilities3.UnpackGPValue(targetDatasetParameter) as IDEDataset2;
                IGPValue targetDatasetGPValue = gpUtilities3.UnpackGPValue(targetDatasetParameter);
                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(120010, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_basenamealreadyexists"), targetDataElement.Name));
                        return;
                    }
                }

                string Container = "";
                IDEUtilities deUtilities = new DEUtilitiesClass();
                deUtilities.ParseContainer(targetDataElement.CatalogPath, ref Container);

                IFeatureWorkspace featureWorkspace = gpUtilities3.OpenFromString(Container) as IFeatureWorkspace;

                if (featureWorkspace == null)
                {
                    message.AddError(120011, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nofeatureworkspace"), Container));
                    return;
                }

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

                System.Xml.XmlTextReader reader = null;
                try
                {
                    if (File.Exists(m_editorConfigurationSettings["osmdomainsfilepath"]))
                    {
                        reader = new System.Xml.XmlTextReader(m_editorConfigurationSettings["osmdomainsfilepath"]);
                    }
                }
                // If is in the server and hasn't been install all the configuration files
                catch
                {
                    if (File.Exists(System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetAssembly(typeof(OSMGPDownload)).Location), "osm_domains.xml")))
                    {
                        reader = new System.Xml.XmlTextReader(System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetAssembly(typeof(OSMGPDownload)).Location), "osm_domains.xml"));
                    }
                }

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

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

                #region define and add domains to the workspace
                // we are using domains to guide the edit templates in the editor for ArcGIS desktop
                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 = featureWorkspace as IWorkspaceDomains;
                foreach (var domain in codedValueDomains.Values)
                {
                    IDomain testDomain = null;
                    try
                    {
                        testDomain = workspaceDomain.get_DomainByName(domain.Name);
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine(ex.Message);
                        System.Diagnostics.Debug.WriteLine(ex.StackTrace);
                    }

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

                IGPEnvironment configKeyword = getEnvironment(envMgr, "configKeyword");
                IGPString gpString = null;
                if (configKeyword != null)
                    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);
                }


                ESRI.ArcGIS.esriSystem.UID osmClassExtensionUID = new ESRI.ArcGIS.esriSystem.UIDClass();
                //GUID for the OSM feature class extension
                osmClassExtensionUID.Value = "{65CA4847-8661-45eb-8E1E-B2985CA17C78}";


                downloadSpatialReference = ((IGeoDataset)targetFeatureDataset).SpatialReference;
                OSMToolHelper osmToolHelper = new OSMToolHelper();

                #region create point/line/polygon feature classes and tables
                // points
                try
                {
                    osmPointFeatureClass = osmToolHelper.CreatePointFeatureClass((IWorkspace2)featureWorkspace, targetFeatureDataset, targetDataElement.Name + "_osm_pt", null, null, osmClassExtensionUID, storageKeyword, availableDomains, metadataAbstract, metadataPurpose);
                }
                catch (Exception ex)
                {
                    message.AddError(120014, 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();

                // lines
                try
                {
                    osmLineFeatureClass = osmToolHelper.CreateLineFeatureClass((IWorkspace2)featureWorkspace, targetFeatureDataset, targetDataElement.Name + "_osm_ln", null, null, osmClassExtensionUID, storageKeyword, availableDomains, metadataAbstract, metadataPurpose);
                }
                catch (Exception ex)
                {
                    message.AddError(120015, 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();

                // polygons
                try
                {
                    osmPolygonFeatureClass = osmToolHelper.CreatePolygonFeatureClass((IWorkspace2)featureWorkspace, targetFeatureDataset, targetDataElement.Name + "_osm_ply", null, null, osmClassExtensionUID, storageKeyword, availableDomains, metadataAbstract, metadataPurpose);
                }
                catch (Exception ex)
                {
                    message.AddError(120016, 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();

                // relation table
                ITable relationTable = null;

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

                if (relationTable == null)
                {
                    return;
                }

                // revision table 
                ITable revisionTable = null;

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

                if (revisionTable == null)
                {
                    return;
                }

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

                #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

                Dictionary<string, OSMToolHelper.simplePointRef> osmNodeDictionary = null;

                foreach (string osmDownloadDocument in downloadedOSMDocuments.Reverse<string>())
                {
                    long nodeCapacity = 0;
                    long wayCapacity = 0;
                    long relationCapacity = 0;

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

                    osmToolHelper.countOSMStuff(osmDownloadDocument, ref nodeCapacity, ref wayCapacity, ref relationCapacity, ref TrackCancel);
                    message.AddMessage(String.Format(resourceManager.GetString("GPTools_OSMGPFileReader_countedElements"), nodeCapacity, wayCapacity, relationCapacity));

                    if (osmNodeDictionary == null)
                        osmNodeDictionary = new Dictionary<string, OSMToolHelper.simplePointRef>(Convert.ToInt32(nodeCapacity));

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

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

                    #region load ways
                    if (wayCapacity > 0)
                    {
                        List<string> missingWays = null;
                        missingWays = osmToolHelper.loadOSMWays(osmDownloadDocument, ref TrackCancel, ref message, targetDatasetGPValue, osmPointFeatureClass, osmLineFeatureClass, osmPolygonFeatureClass, false, false, Convert.ToInt32(wayCapacity), ref osmNodeDictionary, featureWorkspace, downloadSpatialReference, availableDomains, false);
                    }
                    #endregion

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

                    # region for conserve memory condition, update refcount
                    int refCounterFieldIndex = osmPointFeatureClass.Fields.FindField("wayRefCount");
                    if (refCounterFieldIndex > -1)
                    {
                        foreach (var refNode in osmNodeDictionary)
                        {
                            try
                            {
                                IFeature updateFeature = osmPointFeatureClass.GetFeature(refNode.Value.pointObjectID);

                                int refCount = refNode.Value.RefCounter;
                                if (refCount == 0)
                                {
                                    refCount = 1;
                                }

                                updateFeature.set_Value(refCounterFieldIndex, refCount);
                                updateFeature.Store();
                            }
                            catch { }
                        }
                    }

                    #endregion

                    // check for user interruption
                    if (TrackCancel.Continue() == false)
                    {
                        return;
                    }
                    ESRI.ArcGIS.Geoprocessor.Geoprocessor geoProcessor = new ESRI.ArcGIS.Geoprocessor.Geoprocessor();

                    #region for local geodatabases enforce spatial integrity
                    bool storedOriginal = geoProcessor.AddOutputsToMap;
                    geoProcessor.AddOutputsToMap = false;

                    try
                    {
                        if (osmLineFeatureClass != null)
                        {
                            if (((IDataset)osmLineFeatureClass).Workspace.Type == esriWorkspaceType.esriLocalDatabaseWorkspace)
                            {
                                IVariantArray lineRepairParameters = new VarArrayClass();
                                lineRepairParameters.Add(((IWorkspace)featureWorkspace).PathName + "\\" + targetDataElement.Name + "\\" + targetDataElement.Name + "_osm_ln");
                                lineRepairParameters.Add("DELETE_NULL");

                                IGeoProcessorResult2 gpResults = gp.Execute("RepairGeometry_management", lineRepairParameters, TrackCancel) as IGeoProcessorResult2;
                                message.AddMessages(gpResults.GetResultMessages());
                            }
                        }

                        if (osmPolygonFeatureClass != null)
                        {
                            if (((IDataset)osmPolygonFeatureClass).Workspace.Type == esriWorkspaceType.esriLocalDatabaseWorkspace)
                            {
                                IVariantArray polygonRepairParameters = new VarArrayClass();
                                polygonRepairParameters.Add(((IWorkspace)featureWorkspace).PathName + "\\" + targetDataElement.Name + "\\" + targetDataElement.Name + "_osm_ply");
                                polygonRepairParameters.Add("DELETE_NULL");

                                IGeoProcessorResult2 gpResults = gp.Execute("RepairGeometry_management", polygonRepairParameters, TrackCancel) as IGeoProcessorResult2;
                                message.AddMessages(gpResults.GetResultMessages());
                            }
                        }
                    }
                    catch
                    {
                        message.AddWarning(resourceManager.GetString("GPTools_OSMGPDownload_repairgeometryfailure"));
                    }
                    geoProcessor.AddOutputsToMap = storedOriginal;
                    #endregion



                    #region load relations
                    if (relationCapacity > 0)
                    {
                        List<string> missingRelations = null;
                        missingRelations = osmToolHelper.loadOSMRelations(osmDownloadDocument, ref TrackCancel, ref message, targetDatasetGPValue, osmPointFeatureClass, osmLineFeatureClass, osmPolygonFeatureClass, Convert.ToInt32(relationCapacity), relationTable, availableDomains, false, false);
                    }
                    #endregion
                }

                #region update the references counts and member lists for nodes
                message.AddMessage(resourceManager.GetString("GPTools_OSMGPFileReader_updatereferences"));
                IFeatureCursor pointUpdateCursor = null;

                using (SchemaLockManager ptLockManager = new SchemaLockManager(osmPointFeatureClass as ITable))
                {
                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        int updateCount = 0;
                        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 osmPointIDFieldIndex = osmPointFeatureClass.FindField("OSMID");
                        int osmWayRefCountFieldIndex = osmPointFeatureClass.FindField("wayRefCount");
                        int positionCounter = 0;
                        while (pointFeature != null)
                        {
                            positionCounter++;
                            string nodeID = Convert.ToString(pointFeature.get_Value(osmPointIDFieldIndex));

                            // 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);
                            }

                            pointUpdateCursor.UpdateFeature(pointFeature);

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

                            pointFeature = pointUpdateCursor.NextFeature();

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

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

                // clean all the downloaded OSM files
                foreach (string osmFile in downloadedOSMDocuments)
                {
                    if (File.Exists(osmFile))
                    {
                        try
                        {
                            File.Delete(osmFile);
                        }
                        catch { }
                    }
                }

                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 pointFeatureClassPackGPValue = gpUtilities3.UnpackGPValue(pointFeatureClassParameter);
                gpUtilities3.PackGPValue(pointFeatureClassPackGPValue, pointFeatureClassParameter);

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

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

                gpUtilities3.ReleaseInternals();
                Marshal.ReleaseComObject(gpUtilities3);

                Marshal.ReleaseComObject(baseURLString);
                Marshal.ReleaseComObject(downloadExtentGPValue);
                Marshal.ReleaseComObject(downloadEnvelope);
                Marshal.ReleaseComObject(includeAllReferences);
                Marshal.ReleaseComObject(downloadSpatialReference);

                if (osmToolHelper != null)
                    osmToolHelper = null;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.StackTrace);
                message.AddError(120019, ex.Message);
            }
            finally
            {
                try
                {
                    if (osmPointFeatureClass != null)
                    {
                        osmPointFeatureClass.ApplyOSMClassExtension();
                        Marshal.ReleaseComObject(osmPointFeatureClass);
                    }

                    if (osmLineFeatureClass != null)
                    {
                        osmLineFeatureClass.ApplyOSMClassExtension();
                        Marshal.ReleaseComObject(osmLineFeatureClass);
                    }

                    if (osmPolygonFeatureClass != null)
                    {
                        osmPolygonFeatureClass.ApplyOSMClassExtension();
                        Marshal.ReleaseComObject(osmPolygonFeatureClass);
                    }
                }
                catch (Exception ex)
                {
                    message.AddError(120020, ex.ToString());
                }
            }
        }
        internal void loadOSMNodes(string osmFileLocation, ref ITrackCancel TrackCancel, ref IGPMessages message,IGPValue targetGPValue,  IFeatureClass osmPointFeatureClass, bool conserveMemory, bool fastLoad, int nodeCapacity, ref Dictionary<string, simplePointRef> osmNodeDictionary, IFeatureWorkspace featureWorkspace, ISpatialReference downloadSpatialReference, OSMDomains availableDomains, bool checkForExisting)
        {
            XmlReader osmFileXmlReader = null;
            XmlSerializer nodeSerializer = null;

            try
            {
                osmFileXmlReader = System.Xml.XmlReader.Create(osmFileLocation);
                nodeSerializer = new XmlSerializer(typeof(node));

                ISpatialReferenceFactory spatialRef = new SpatialReferenceEnvironmentClass();
                ISpatialReference wgs84 = spatialRef.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984);

                bool shouldProject = !((IClone)wgs84).IsEqual((IClone)downloadSpatialReference);

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

                foreach (var domains in availableDomains.domain)
                {
                    int currentFieldIndex = osmPointFeatureClass.FindField(domains.name);

                    if (currentFieldIndex != -1)
                    {
                        osmPointDomainAttributeFieldIndices.Add(domains.name, currentFieldIndex);
                        osmPointDomainAttributeFieldLength.Add(domains.name, osmPointFeatureClass.Fields.get_Field(currentFieldIndex).Length);
                    }
                }

                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");

                // set up the progress indicator
                IStepProgressor stepProgressor = TrackCancel as IStepProgressor;

                if (stepProgressor != null)
                {
                    stepProgressor.MinRange = 0;
                    stepProgressor.MaxRange = nodeCapacity;
                    stepProgressor.StepValue = (1);
                    stepProgressor.Message = _resourceManager.GetString("GPTools_OSMGPFileReader_loadingNodes");
                    stepProgressor.Position = 0;
                    stepProgressor.Show();
                }

                // flag to determine if a computation of indices is required
                bool indexBuildRequired = false;
                if (nodeCapacity > 0)
                    indexBuildRequired = true;

                int pointCount = 0;

                // let's insert all the points first
                if (osmPointFeatureClass != null)
                {
                    IFeatureBuffer pointFeature = null;
                    IFeatureClassLoad pointFeatureLoad = null;

                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        using (SchemaLockManager schemaLockManager = new SchemaLockManager(osmPointFeatureClass as ITable))
                        {

                            if (((IWorkspace)featureWorkspace).WorkspaceFactory.WorkspaceType == esriWorkspaceType.esriRemoteDatabaseWorkspace)
                            {
                                pointFeatureLoad = osmPointFeatureClass as IFeatureClassLoad;
                            }

                            IFeatureCursor pointInsertCursor = osmPointFeatureClass.Insert(true);
                            comReleaser.ManageLifetime(pointInsertCursor);

                            pointFeature = osmPointFeatureClass.CreateFeatureBuffer();
                            comReleaser.ManageLifetime(pointFeature);

                            if (pointFeatureLoad != null)
                            {
                                pointFeatureLoad.LoadOnlyMode = true;
                            }

                            osmFileXmlReader.MoveToContent();

                            while (osmFileXmlReader.Read())
                            {
                                if (osmFileXmlReader.IsStartElement())
                                {
                                    if (osmFileXmlReader.Name == "node")
                                    {
                                        string currentNodeString = osmFileXmlReader.ReadOuterXml();
                                        // turn the xml node representation into a node class representation
                                        ESRI.ArcGIS.OSM.OSMClassExtension.node currentNode = null;
                                        using (StringReader nodeReader = new System.IO.StringReader(currentNodeString))
                                        {
                                            currentNode = nodeSerializer.Deserialize(nodeReader) as ESRI.ArcGIS.OSM.OSMClassExtension.node;
                                        }

                                        // check if a feature with the same OSMID already exists, because the can only be one
                                        if (checkForExisting == true)
                                        {
                                            if (CheckIfExists(osmPointFeatureClass as ITable, currentNode.id))
                                            {
                                                continue;
                                            }
                                        }

                                        try
                                        {
                                            //if (pointFeature == null)
                                            //{
                                            pointFeature = osmPointFeatureClass.CreateFeatureBuffer();
                                            comReleaser.ManageLifetime(pointFeature);
                                            //}

                                            IPoint pointGeometry = new PointClass();
                                            comReleaser.ManageLifetime(pointGeometry);

                                            pointGeometry.X = Convert.ToDouble(currentNode.lon, new CultureInfo("en-US"));
                                            pointGeometry.Y = Convert.ToDouble(currentNode.lat, new CultureInfo("en-US"));
                                            pointGeometry.SpatialReference = wgs84;

                                            if (shouldProject)
                                            {
                                                pointGeometry.Project(downloadSpatialReference);
                                            }

                                            pointFeature.Shape = pointGeometry;

                                            pointFeature.set_Value(osmPointIDFieldIndex, currentNode.id);

                                            string isSupportingNode = "";
                                            if (_osmUtility.DoesHaveKeys(currentNode))
                                            {
                                                // if case it has tags I assume that the node presents an entity of it own,
                                                // hence it is not a supporting node in the context of supporting a way or relation
                                                isSupportingNode = "no";

                                                if (conserveMemory == false)
                                                {
                                                    osmNodeDictionary[currentNode.id] = new simplePointRef(Convert.ToSingle(currentNode.lon, new CultureInfo("en-US")), Convert.ToSingle(currentNode.lat, new CultureInfo("en-US")), 0, 0);
                                                }
                                            }
                                            else
                                            {
                                                // node has no tags -- at this point I assume that the absence of tags indicates that it is a supporting node
                                                // for a way or a relation
                                                isSupportingNode = "yes";

                                                if (conserveMemory == false)
                                                {
                                                    osmNodeDictionary[currentNode.id] = new simplePointRef(Convert.ToSingle(currentNode.lon, new CultureInfo("en-US")), Convert.ToSingle(currentNode.lat, new CultureInfo("en-US")), 0, 0);
                                                }
                                            }

                                            insertTags(osmPointDomainAttributeFieldIndices, osmPointDomainAttributeFieldLength, tagCollectionPointFieldIndex, pointFeature, currentNode.tag);

                                            if (fastLoad == false)
                                            {
                                                if (osmSupportingElementPointFieldIndex > -1)
                                                {
                                                    pointFeature.set_Value(osmSupportingElementPointFieldIndex, isSupportingNode);
                                                }

                                                if (osmWayRefCountFieldIndex > -1)
                                                {
                                                    pointFeature.set_Value(osmWayRefCountFieldIndex, 0);
                                                }

                                                // store the administrative attributes
                                                // user, uid, version, changeset, timestamp, visible
                                                if (osmUserPointFieldIndex > -1)
                                                {
                                                    if (!String.IsNullOrEmpty(currentNode.user))
                                                    {
                                                        pointFeature.set_Value(osmUserPointFieldIndex, currentNode.user);
                                                    }
                                                }

                                                if (osmUIDPointFieldIndex > -1)
                                                {
                                                    if (!String.IsNullOrEmpty(currentNode.uid))
                                                    {
                                                        pointFeature.set_Value(osmUIDPointFieldIndex, Convert.ToInt32(currentNode.uid));
                                                    }
                                                }

                                                if (osmVisiblePointFieldIndex > -1)
                                                {
                                                    pointFeature.set_Value(osmVisiblePointFieldIndex, currentNode.visible.ToString());
                                                }

                                                if (osmVersionPointFieldIndex > -1)
                                                {
                                                    if (!String.IsNullOrEmpty(currentNode.version))
                                                    {
                                                        pointFeature.set_Value(osmVersionPointFieldIndex, Convert.ToInt32(currentNode.version));
                                                    }
                                                }

                                                if (osmChangesetPointFieldIndex > -1)
                                                {
                                                    if (!String.IsNullOrEmpty(currentNode.changeset))
                                                    {
                                                        pointFeature.set_Value(osmChangesetPointFieldIndex, Convert.ToInt32(currentNode.changeset));
                                                    }
                                                }

                                                if (osmTimeStampPointFieldIndex > -1)
                                                {
                                                    if (!String.IsNullOrEmpty(currentNode.timestamp))
                                                    {
                                                        try
                                                        {
                                                            pointFeature.set_Value(osmTimeStampPointFieldIndex, Convert.ToDateTime(currentNode.timestamp));
                                                        }
                                                        catch (Exception ex)
                                                        {
                                                            message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_invalidTimeFormat"), ex.Message));
                                                        }
                                                    }
                                                }
                                            }
                                            try
                                            {
                                                pointInsertCursor.InsertFeature(pointFeature);
                                                pointCount = pointCount + 1;

                                                if (stepProgressor != null)
                                                {
                                                    stepProgressor.Position = pointCount;
                                                }
                                            }
                                            catch (Exception ex)
                                            {
                                                System.Diagnostics.Debug.WriteLine(ex.Message);
                                                message.AddWarning(ex.Message);
                                            }

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

                                            if ((pointCount % 50000) == 0)
                                            {
                                                message.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_pointsloaded"), pointCount));
                                                pointInsertCursor.Flush();
                                                System.GC.Collect();
                                            }

                                            if (pointGeometry != null)
                                                Marshal.ReleaseComObject(pointGeometry);
                                        }
                                        catch (Exception ex)
                                        {
                                            System.Diagnostics.Debug.WriteLine(ex.Message);
                                            message.AddWarning(ex.Message);
                                        }
                                        finally
                                        {
                                            if (pointFeature != null)
                                            {
                                                Marshal.ReleaseComObject(pointFeature);

                                                if (pointFeature != null)
                                                    pointFeature = null;

                                            }
                                        }

                                        currentNode = null;
                                    }
                                }
                            }

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

                            pointInsertCursor.Flush();
                            osmFileXmlReader.Close();

                            message.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_pointsloaded"), pointCount));
                            message.AddMessage(_resourceManager.GetString("GPTools_buildingpointidx"));

                            if (pointFeatureLoad != null)
                            {
                                pointFeatureLoad.LoadOnlyMode = false;
                            }
                        }
                    }

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

                    using (ComReleaser comReleaser = new ComReleaser())
                    {
                        IFeatureCursor updatePoints = osmPointFeatureClass.Update(null, false);
                        comReleaser.ManageLifetime(updatePoints);

                        IFeature feature2Update = updatePoints.NextFeature();

                        while (feature2Update != null)
                        {
                            IPoint pointGeometry = feature2Update.Shape as IPoint;
                            pointGeometry.ID = feature2Update.OID;
                            feature2Update.Shape = pointGeometry;

                            if (conserveMemory == false)
                            {
                                string osmid = Convert.ToString(feature2Update.get_Value(osmPointIDFieldIndex));
                                if (osmNodeDictionary.ContainsKey(osmid))
                                    osmNodeDictionary[osmid].pointObjectID = feature2Update.OID;
                            }

                            updatePoints.UpdateFeature(feature2Update);

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

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

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

                            feature2Update = updatePoints.NextFeature();
                        }
                    }

                    if (indexBuildRequired)
                    {

                        IGeoProcessor2 geoProcessor = new GeoProcessorClass();
                        bool storedOriginal = geoProcessor.AddOutputsToMap;

                        try
                        {
                            IGPUtilities3 gpUtilities3 = new GPUtilitiesClass();

                            IGPValue pointFeatureClass = gpUtilities3.MakeGPValueFromObject(osmPointFeatureClass);

                            string fcLocation = GetLocationString(targetGPValue, osmPointFeatureClass);

                            IIndexes featureClassIndexes = osmPointFeatureClass.Indexes;
                            int indexPosition = -1;
                            featureClassIndexes.FindIndex("osmID_IDX", out indexPosition);

                            if (indexPosition == -1)
                            {
                                {
                                    geoProcessor.AddOutputsToMap = false;

                                    IVariantArray parameterArrary = CreateAddIndexParameterArray(fcLocation, "OSMID", "osmID_IDX", "UNIQUE", "");
                                    IGeoProcessorResult2 gpResults2 = geoProcessor.Execute("AddIndex_management", parameterArrary, TrackCancel) as IGeoProcessorResult2;
                                }
                            }
                            if (pointCount > 500)
                            {
                                if (pointFeatureLoad == null)
                                {
                                    UpdateSpatialGridIndex(TrackCancel, message, geoProcessor, fcLocation);
                                }
                            }
                        }
                        catch (COMException comEx)
                        {
                            message.AddWarning(comEx.Message);
                        }
                        catch (Exception ex)
                        {
                            message.AddWarning(ex.Message);
                        }
                        finally
                        {
                            geoProcessor.AddOutputsToMap = storedOriginal;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                message.AddError(120100, String.Format(_resourceManager.GetString("GPTools_Utility_NodeLoadError"), ex.Message));
            }
            finally
            {
                if (osmFileXmlReader != null)
                    osmFileXmlReader = null;

                if (nodeSerializer != null)
                    nodeSerializer = null;
            }
        }