private way ConvertFeatureToOSMWay(IFeature currentFeature, IWorkspace featureWorkspace, IFeatureClass pointFeatureClass, int osmIDPointFieldIndex, int tagsFieldIndex, int osmIDFieldIndex, int changesetIDFieldIndex, int osmVersionFieldIndex, int userIDFieldIndex, int userNameFieldIndex, int timeStampFieldIndex, int visibleFieldIndex, int extensionVersion)
        {

            if (currentFeature == null)
                throw new ArgumentNullException("currentFeature");

            way osmWay = new way();
            object featureValue = DBNull.Value;

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

            if (currentFeature.Shape.IsEmpty == false)
            {
                IPointCollection pointCollection = currentFeature.Shape as IPointCollection;

                if (currentFeature.Shape.GeometryType == esriGeometryType.esriGeometryPolygon)
                {
                    for (int pointIndex = 0; pointIndex < pointCollection.PointCount - 1; pointIndex++)
                    {
                        nd vertex = new nd();
                        vertex.@ref = OSMToolHelper.retrieveNodeID(pointFeatureClass, osmIDPointFieldIndex, extensionVersion, pointCollection.get_Point(pointIndex));
                        vertexIDs.Add(vertex);
                    }

                    // the last node is the first one again even though it doesn't have an internal ID
                    nd lastVertex = new nd();
                    lastVertex.@ref = OSMToolHelper.retrieveNodeID(pointFeatureClass, osmIDPointFieldIndex, extensionVersion, pointCollection.get_Point(0));
                    vertexIDs.Add(lastVertex);

                }
                else
                {
                    for (int pointIndex = 0; pointIndex < pointCollection.PointCount; pointIndex++)
                    {
                        nd vertex = new nd();
                        vertex.@ref = OSMToolHelper.retrieveNodeID(pointFeatureClass, osmIDPointFieldIndex, extensionVersion, pointCollection.get_Point(pointIndex));
                        vertexIDs.Add(vertex);
                    }
                }

                osmWay.nd = vertexIDs.ToArray();
            }

            if (osmIDFieldIndex != -1)
            {
                osmWay.id = Convert.ToString(currentFeature.get_Value(osmIDFieldIndex));
            }

            if (changesetIDFieldIndex != -1)
            {
                featureValue = currentFeature.get_Value(changesetIDFieldIndex);

                if (featureValue != DBNull.Value)
                {
                    osmWay.changeset = Convert.ToString(currentFeature.get_Value(changesetIDFieldIndex));
                }
            }

            if (osmVersionFieldIndex != -1)
            {
                featureValue = currentFeature.get_Value(osmVersionFieldIndex);

                if (featureValue != DBNull.Value)
                {
                    osmWay.version = Convert.ToString(featureValue);
                }
            }

            if (userIDFieldIndex != -1)
            {
                featureValue = currentFeature.get_Value(userIDFieldIndex);

                if (featureValue != DBNull.Value)
                {
                    osmWay.uid = Convert.ToString(featureValue);
                }
            }

            if (userNameFieldIndex != -1)
            {
                featureValue = currentFeature.get_Value(userNameFieldIndex);

                if (featureValue != DBNull.Value)
                {
                    osmWay.user = Convert.ToString(featureValue);
                }
            }

            if (timeStampFieldIndex != -1)
            {
                featureValue = currentFeature.get_Value(timeStampFieldIndex);

                if (featureValue != DBNull.Value)
                {
                    osmWay.timestamp = Convert.ToDateTime(featureValue).ToUniversalTime().ToString("u");
                }
            }

            if (visibleFieldIndex != -1)
            {
                featureValue = currentFeature.get_Value(visibleFieldIndex);

                if (featureValue != DBNull.Value)
                {
                    try
                    {
                        osmWay.visible = (wayVisible)Enum.Parse(typeof(wayVisible), Convert.ToString(featureValue));
                    }
                    catch
                    {
                        osmWay.visible = wayVisible.@true;
                    }
                }
            }

            if (tagsFieldIndex > -1)
            {
                tag[] tags = null;
                tags = _osmUtility.retrieveOSMTags((IRow)currentFeature, tagsFieldIndex, featureWorkspace);

                if (tags.Length != 0)
                {
                    osmWay.tag = tags;
                }
            }

            return osmWay;
        }
        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;
        }
        public static bool IsThisWayALine(way currentway)
        {
            bool isALine = true;

            try
            {
                if (currentway.nd != null)
                {
                    if (currentway.nd[0].@ref == currentway.nd[currentway.nd.Length - 1].@ref)
                    {
                        isALine = false;
                    }
                    else
                    {
                        isALine = true;
                    }
                }

                // coastlines are special cases and we will accept them as lines only
                bool isCoastline = false;

                if (currentway.tag != null)
                {
                    tag coastlineTag = new tag();
                    coastlineTag.k = "natural";
                    coastlineTag.v = "coastline";

                    tag areaTag = new tag();
                    areaTag.k = "area";
                    areaTag.v = "yes";

                    tag highwayTag = new tag();
                    highwayTag.k = "highway";
                    highwayTag.v = "something";

                    if (currentway.tag.Contains(coastlineTag, new TagKeyValueComparer()))
                    {
                        isCoastline = true;
                        isALine = true;
                    }

                    if (currentway.tag.Contains(highwayTag, new TagKeyComparer()))
                    {
                        isALine = true;
                    }

                    if (currentway.tag.Contains(areaTag, new TagKeyValueComparer()))
                    {
                        if (isCoastline == false)
                        {
                            isALine = false;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.StackTrace);
            }

            return isALine;
        }