diff --git a/hoot-core/src/main/cpp/hoot/core/io/OsmApiChangeset.h b/hoot-core/src/main/cpp/hoot/core/io/OsmApiChangeset.h
index 551e915..522aad5 100644
--- a/hoot-core/src/main/cpp/hoot/core/io/OsmApiChangeset.h
+++ b/hoot-core/src/main/cpp/hoot/core/io/OsmApiChangeset.h
@@ -69,10 +69,10 @@ public:
/** Allow test class to access protected members for white box testing */
friend class OsmApiChangesetTest;
/**
- * @brief loadChangeset Load changeset file, can be called multiple times on changeset that are split across files
- * @param changesetPath
+ * @brief loadChangeset Load changeset file or string, can be called multiple times on changeset that are split across files
+ * @param changeset Path to changeset file or changeset as a string
*/
- void loadChangeset(const QString& changesetPath);
+ void loadChangeset(const QString& changeset);
/**
* @brief splitLongWays The API defaults to only allowing a maximum of 2000 nodes per way, split the way if necessary
* @param maxWayNodes Maximum number of nodes per way from the API capabilities query
@@ -132,7 +132,7 @@ public:
* @brief updateFailedChangeset Update the changeset to mark elements as failed if the ChangesetInfo object has been "fixed"
* @param changeset - Pointer to changeset info object with one element that has failed
*/
- void updateFailedChangeset(ChangesetInfoPtr changeset);
+ void updateFailedChangeset(ChangesetInfoPtr changeset, bool forceFailure = false);
/**
* @brief getChangesetString Get the .OSC formatted string for this subset of the changeset with the changeset ID in it
* @param changeset - Subset of the changeset to render
@@ -201,9 +201,75 @@ public:
* @return Number of elements processed so far
*/
long getProcessedCount() { return _processedCount; }
+ /**
+ * @brief matchesPlaceholderFailure Checks the return from the API to see if it is similar to the following error message:
+ * "Placeholder node not found for reference -145213 in way -5687"
+ * @param hint Error message from OSM API
+ * @param member_id ID of the member element that caused the element to fail
+ * @param member_type Type of the member element that caused the element to fail
+ * @param element_id ID of the element that failed
+ * @param element_type Type of the element that failed
+ * @return True if the message matches and was parsed
+ */
+ static bool matchesPlaceholderFailure(const QString& hint,
+ long& member_id, ElementType::Type& member_type,
+ long& element_id, ElementType::Type& element_type);
+ /**
+ * @brief matchesRelationFailure Checks the return from the API to see if it is similar to the following error message:
+ * @param hint Error message from OSM API
+ * @param element_id ID of the element that failed
+ * @param member_id ID of the member element that caused the element to fail
+ * @param member_type Type of the member element that caused the element to fail
+ * @return True if the message matches and was parsed
+ */
+ static bool matchesRelationFailure(const QString& hint, long& element_id, long& member_id, ElementType::Type& member_type);
+ /**
+ * @brief matchesChangesetPreconditionFailure
+ * @param hint Error message from OSM API
+ * @param member_id ID of the member element that caused the element to fail
+ * @param member_type Type of the member element that caused the element to fail
+ * @param element_id ID of the element that failed
+ * @param element_type Type of the element that failed
+ * @return True if the message matches and was parsed
+ */
+ static bool matchesChangesetPreconditionFailure(const QString& hint,
+ long& member_id, ElementType::Type& member_type,
+ long& element_id, ElementType::Type& element_type);
+ /**
+ * @brief matchesChangesetConflictVersionMismatchFailure
+ * @param hint
+ * @param element_id
+ * @param element_type
+ * @param version_old
+ * @param version_new
+ * @return
+ */
+ static bool matchesChangesetConflictVersionMismatchFailure(const QString& hint,
+ long& element_id, ElementType::Type& element_type,
+ long& version_old, long& version_new);
private:
/**
+ * @brief loadChangesetFile Load changeset file, can be called multiple times on changeset that are split across files
+ * @param changesetPath
+ */
+ void loadChangesetFile(const QString& changesetPath);
+ /**
+ * @brief loadChangesetXml Load changeset XML text, can be called multiple times on changesets that are split
+ * @param changesetXml
+ */
+ void loadChangesetXml(const QString& changesetXml);
+ /**
+ * @brief loadChangeset Load a .osc changeset file
+ * @param reader
+ */
+ void loadChangeset(QXmlStreamReader& reader);
+ /**
+ * @brief loadOsmAsChangeset Load an OSM file as a changeset of <create> elements
+ * @param reader
+ */
+ void loadOsmAsChangeset(QXmlStreamReader& reader);
+ /**
* @brief updateElement Update the element ID map with the new ID and update the version of the element
* @param map Map of elements (nodes/ways/relations)
* @param old_id
@@ -278,6 +344,17 @@ private:
bool moveWay(ChangesetInfoPtr& source, ChangesetInfoPtr& destination, ChangesetType type, XmlWay* way);
bool moveRelation(ChangesetInfoPtr& source, ChangesetInfoPtr& destination, ChangesetType type, XmlRelation* relation);
/**
+ * @brief moveOrRemoveNode/Way/Relation Move an element from one subset to another, or if all related elements aren't
+ * able to be moved, the element is removed from the subset and returned to the `available` state
+ * @param source Subset containing the element
+ * @param destination Subset to move to
+ * @param type Type of operation (create/modify/delete)
+ * @param node/way/relation Pointer to the element to be moved
+ */
+ void moveOrRemoveNode(ChangesetInfoPtr& source, ChangesetInfoPtr& destination, ChangesetType type, XmlNode* node);
+ void moveOrRemoveWay(ChangesetInfoPtr& source, ChangesetInfoPtr& destination, ChangesetType type, XmlWay* way);
+ void moveOrRemoveRelation(ChangesetInfoPtr& source, ChangesetInfoPtr& destination, ChangesetType type, XmlRelation* relation);
+ /**
* @brief canMoveNode/Way/Relation Query if a node/way/relation can be moved. This checks downstream relations, ways,
* and nodes to see if they can also be moved.
* @param source Subset containing the element
@@ -342,40 +419,6 @@ private:
void failWay(long id, bool beforeSend = false);
void failRelation(long id, bool beforeSend = false);
/**
- * @brief matchesPlaceholderFailure Checks the return from the API to see if it is similar to the following error message:
- * "Placeholder node not found for reference -145213 in way -5687"
- * @param hint Error message from OSM API
- * @param member_id ID of the member element that caused the element to fail
- * @param member_type Type of the member element that caused the element to fail
- * @param element_id ID of the element that failed
- * @param element_type Type of the element that failed
- * @return True if the message matches and was parsed
- */
- bool matchesPlaceholderFailure(const QString& hint,
- long& member_id, ElementType::Type& member_type,
- long& element_id, ElementType::Type& element_type);
- /**
- * @brief matchesRelationFailure Checks the return from the API to see if it is similar to the following error message:
- * @param hint Error message from OSM API
- * @param element_id ID of the element that failed
- * @param member_id ID of the member element that caused the element to fail
- * @param member_type Type of the member element that caused the element to fail
- * @return True if the message matches and was parsed
- */
- bool matchesRelationFailure(const QString& hint, long& element_id, long& member_id, ElementType::Type& member_type);
- /**
- * @brief matchesChangesetPreconditionFailure
- * @param hint Error message from OSM API
- * @param member_id ID of the member element that caused the element to fail
- * @param member_type Type of the member element that caused the element to fail
- * @param element_id ID of the element that failed
- * @param element_type Type of the element that failed
- * @return True if the message matches and was parsed
- */
- bool matchesChangesetPreconditionFailure(const QString& hint,
- long& member_id, ElementType::Type& member_type,
- long& element_id, ElementType::Type& element_type);
- /**
* @brief getNodes/Ways/Relations Output node/way/relation text to the text stream
* @param changeset Pointer to the changeset to output
* @param ts TextStream to output the element to
@@ -427,41 +470,32 @@ public:
typedef typename container::iterator iterator;
typedef typename container::const_iterator const_iterator;
/** Constructor */
- ChangesetInfo() : _changesetIssuesResolved(false) { }
+ ChangesetInfo();
/**
* @brief add Add an element ID of a certain type to the changeset type
* @param element_type Describes the 'id' argument as a node, way, or relation
* @param changeset_type Describes the changeset method as create, modify, or delete
* @param id Element ID of the element to add
*/
- void add(ElementType::Type element_type, XmlChangeset::ChangesetType changeset_type, long id)
- { _changeset[element_type][changeset_type].insert(id); }
+ void add(ElementType::Type element_type, XmlChangeset::ChangesetType changeset_type, long id);
/**
* @brief remove Remove an element ID of a certain type from the changeset type
* @param element_type Describes the 'id' argument as a node, way, or relation
* @param changeset_type Describes the changeset method as create, modify, or delete
* @param id Element ID of the element to remove
*/
- void remove(ElementType::Type element_type, XmlChangeset::ChangesetType changeset_type, long id)
- {
- container& selectedSet = _changeset[element_type][changeset_type];
- if (selectedSet.find(id) != selectedSet.end())
- selectedSet.erase(id);
- }
-
- long getFirst(ElementType::Type element_type, XmlChangeset::ChangesetType changeset_type)
- { return *(_changeset[element_type][changeset_type].begin()); }
+ void remove(ElementType::Type element_type, XmlChangeset::ChangesetType changeset_type, long id);
+ /**
+ * @brief getFirst Get the first element of the types
+ * @param element_type Describes the element type: node, way, or relation
+ * @param changeset_type Describes the type: create, modify, delete
+ * @return
+ */
+ long getFirst(ElementType::Type element_type, XmlChangeset::ChangesetType changeset_type);
/**
* @brief clear Clear out this entire changeset subset
*/
- void clear()
- {
- for (int i = 0; i < (int)ElementType::Unknown; ++i)
- {
- for (int j = 0; j < (int)XmlChangeset::TypeMax; ++j)
- _changeset[i][j].clear();
- }
- }
+ void clear();
/**
* @brief contains Check if this subset contains an element described by types and ID
* @param element_type Describes the 'id' argument as a node, way, or relation
@@ -469,28 +503,21 @@ public:
* @param id Element ID that is being searched for
* @return true if it is found
*/
- bool contains(ElementType::Type element_type, XmlChangeset::ChangesetType changeset_type, long id)
- {
- return _changeset[element_type][changeset_type].find(id) != end(element_type, changeset_type);
- }
+ bool contains(ElementType::Type element_type, XmlChangeset::ChangesetType changeset_type, long id);
/**
* @brief begin Begin iterator
* @param element_type Describes the type (node/way/relation) to iterate
* @param changeset_type Describes the type (create/modify/delete) to iterate
* @return iterator pointing to the beginning of the set
*/
- iterator begin(ElementType::Type element_type, XmlChangeset::ChangesetType changeset_type)
- {
- return _changeset[element_type][changeset_type].begin();
- }
+ iterator begin(ElementType::Type element_type, XmlChangeset::ChangesetType changeset_type);
/**
* @brief end End iterator
* @param element_type Describes the type (node/way/relation) to iterate
* @param changeset_type Describes the type (create/modify/delete) to iterate
* @return iterator pointing off of the end of the set
*/
- iterator end(ElementType::Type element_type, XmlChangeset::ChangesetType changeset_type)
- { return _changeset[element_type][changeset_type].end(); }
+ iterator end(ElementType::Type element_type, XmlChangeset::ChangesetType changeset_type);
/**
* @brief size Total number of ElementType::Type elements (node/way/relation) of a specific changeset
* type (create/modify/delete) within this subset
@@ -498,35 +525,26 @@ public:
* @param changesetType Describes the type (create/modify/delete) to count
* @return count based on types
*/
- size_t size(ElementType::Type elementType, XmlChangeset::ChangesetType changesetType)
- {
- return _changeset[(int)elementType][(int)changesetType].size();
- }
+ size_t size(ElementType::Type elementType, XmlChangeset::ChangesetType changesetType);
/**
* @brief size Total number of elements in the subset
* @return total count
*/
- size_t size()
- {
- size_t s = 0;
- // Iterate element types
- for (int i = 0; i < (int)ElementType::Unknown; ++i)
- {
- // Sum up all counts for each changeset type
- for (int j = 0; j < (int)XmlChangeset::TypeMax; ++j)
- s += _changeset[i][j].size();
- }
- return s;
- }
-
- bool getChangesetIssuesResolved() { return _changesetIssuesResolved; }
- void setChangesetIssuesResolved(bool resolved) { _changesetIssuesResolved = resolved; }
-
+ size_t size();
+ /** Set/get _attemptedResolveChangesetIssues member */
+ bool getAttemptedResolveChangesetIssues();
+ void setAttemptedResolveChangesetIssues(bool attempted);
+ /** Set/get _numRetries member */
+ bool canRetry();
+ void retry();
private:
/** 3x3 array of containers for elements in this subset */
std::array<std::array<container, XmlChangeset::TypeMax>, ElementType::Unknown> _changeset;
/** Flag set after attempt to resolve changeset issues has completed. */
- bool _changesetIssuesResolved;
+ bool _attemptedResolveChangesetIssues;
+ /** Number of times this exact changeset has been retried unsuccessfully */
+ int _numRetries;
+ const int MAX_RETRIES = 5;
};
}