@@ -7,12 +7,11 @@ import org.modelix.model.data.ModelData
7
7
import org.modelix.model.data.NodeData
8
8
import java.io.File
9
9
10
- class ModelImporter (private val root : INode ) {
10
+ class ModelImporter (private val root : INode , val stats : ImportStats ? = null ) {
11
11
12
- private lateinit var originalIdToRef: MutableMap <String , INodeReference >
13
12
private lateinit var originalIdToSpec: MutableMap <String , NodeData >
14
- private lateinit var originalIdToParentSpec: MutableMap <String , NodeData >
15
13
private lateinit var originalIdToExisting: MutableMap <String , INode >
14
+ private lateinit var originalIdToRef: MutableMap <String , INodeReference >
16
15
17
16
fun import (jsonFile : File ) {
18
17
require(jsonFile.exists())
@@ -29,9 +28,6 @@ class ModelImporter(private val root: INode) {
29
28
originalIdToSpec = mutableMapOf ()
30
29
buildSpecIndex(data.root)
31
30
32
- originalIdToParentSpec = mutableMapOf ()
33
- buildParentSpecIndex(data.root)
34
-
35
31
syncNode(root, data.root)
36
32
37
33
originalIdToRef = mutableMapOf ()
@@ -46,13 +42,6 @@ class ModelImporter(private val root: INode) {
46
42
root.allChildren.forEach { buildExistingIndex(it) }
47
43
}
48
44
49
- private fun buildParentSpecIndex (nodeData : NodeData ) {
50
- for (child in nodeData.children) {
51
- child.originalId()?.let { originalIdToParentSpec[it] = nodeData }
52
- buildParentSpecIndex(child)
53
- }
54
- }
55
-
56
45
private fun buildRefIndex (node : INode ) {
57
46
node.originalId()?.let { originalIdToRef[it] = node.reference }
58
47
node.allChildren.forEach { buildRefIndex(it) }
@@ -69,11 +58,15 @@ class ModelImporter(private val root: INode) {
69
58
}
70
59
71
60
private fun syncProperties (node : INode , nodeData : NodeData ) {
72
- nodeData.properties.forEach { node.setPropertyValue(it.key, it.value) }
61
+ nodeData.properties.forEach {
62
+ if (node.getPropertyValue(it.key) != it.value) {
63
+ node.setPropertyValueWithStats(it.key, it.value)
64
+ }
65
+ }
73
66
val toBeRemoved = node.getPropertyRoles().toSet()
74
67
.subtract(nodeData.properties.keys)
75
68
.filter { it != NodeData .idPropertyKey }
76
- toBeRemoved.forEach { node.setPropertyValue (it, null ) }
69
+ toBeRemoved.forEach { node.setPropertyValueWithStats (it, null ) }
77
70
}
78
71
79
72
private fun syncAllReferences (root : INode , rootData : NodeData ) {
@@ -84,9 +77,13 @@ class ModelImporter(private val root: INode) {
84
77
}
85
78
86
79
private fun syncReferences (node : INode , nodeData : NodeData ) {
87
- nodeData.references.forEach { node.setReferenceTarget(it.key, originalIdToRef[it.value]) }
80
+ nodeData.references.forEach {
81
+ if (node.getReferenceTargetRef(it.key) != originalIdToRef[it.value]) {
82
+ node.setReferenceTargetWithStats(it.key, originalIdToRef[it.value])
83
+ }
84
+ }
88
85
val toBeRemoved = node.getReferenceRoles().toSet().subtract(nodeData.references.keys)
89
- toBeRemoved.forEach { node.setPropertyValue (it, null ) }
86
+ toBeRemoved.forEach { node.setReferenceTargetWithStats (it, null ) }
90
87
}
91
88
92
89
private fun syncChildNodes (node : INode , nodeData : NodeData ) {
@@ -99,20 +96,19 @@ class ModelImporter(private val root: INode) {
99
96
100
97
toBeAdded.forEach {
101
98
val index = nodeData.children.indexOf(it)
102
- val createdNode = node.addNewChild(it.role, index, it.concept?.let { s -> ConceptReference (s) })
103
- createdNode.setPropertyValue(NodeData .idPropertyKey, it.originalId())
99
+ node.addNewChildWithStats(it, index)
104
100
}
105
101
106
102
toBeMovedHere.forEach {
107
103
val actualNode = originalIdToExisting[it.originalId()]
108
104
val targetIndex = it.getIndexWithinRole(nodeData)
109
105
if (actualNode != null ) {
110
- node.moveChild (it.role, targetIndex, actualNode)
106
+ node.moveChildWithStats (it.role, targetIndex, actualNode)
111
107
}
112
108
}
113
109
114
110
val toBeRemoved = node.allChildren.filter { ! originalIdToSpec.contains(it.originalId()) }
115
- toBeRemoved.forEach { node.removeChild (it) }
111
+ toBeRemoved.forEach { node.removeChildWithStats (it) }
116
112
117
113
node.allChildren.forEach {
118
114
val childData = originalIdToSpec[it.originalId()]
@@ -140,9 +136,11 @@ class ModelImporter(private val root: INode) {
140
136
targetIndices[specifiedChild.originalId()] = index
141
137
}
142
138
143
- for (child in existingChildren) {
139
+ for ((index, child) in existingChildren.withIndex() ) {
144
140
val targetIndex = targetIndices[child.originalId()] ? : - 1
145
- node.moveChild(child.roleInParent, targetIndex, child)
141
+ if (targetIndex != index) {
142
+ node.moveChildWithStats(child.roleInParent, targetIndex, child)
143
+ }
146
144
}
147
145
}
148
146
@@ -158,4 +156,43 @@ class ModelImporter(private val root: INode) {
158
156
return properties[NodeData .idPropertyKey] ? : id
159
157
}
160
158
159
+ private fun INode.addNewChildWithStats (spec : NodeData , index : Int ) : INode {
160
+ val concept = spec.concept?.let { s -> ConceptReference (s) }
161
+
162
+ val createdNode = addNewChild(spec.role, index, concept)
163
+ createdNode.setPropertyValue(NodeData .idPropertyKey, spec.originalId())
164
+ if (this @ModelImporter.stats != null ) {
165
+ createdNode.originalId()?.let { stats.addAddition(it) }
166
+ }
167
+ return createdNode
168
+ }
169
+
170
+ private fun INode.moveChildWithStats (role : String? , index : Int , child : INode ) {
171
+ if (this @ModelImporter.stats != null ) {
172
+ child.originalId()?.let { stats.addMove(it) }
173
+ }
174
+ return moveChild(role, index, child)
175
+ }
176
+
177
+ private fun INode.removeChildWithStats (child : INode ) {
178
+ if (this @ModelImporter.stats != null ) {
179
+ child.originalId()?.let { stats.addDeletion(it) }
180
+ }
181
+ return removeChild(child)
182
+ }
183
+
184
+ private fun INode.setPropertyValueWithStats (role : String , value : String? ) {
185
+ if (this @ModelImporter.stats != null ) {
186
+ this .originalId()?.let { stats.addPropertyChange(it, role) }
187
+ }
188
+ return setPropertyValue(role, value)
189
+ }
190
+
191
+ private fun INode.setReferenceTargetWithStats (role : String , target : INodeReference ? ) {
192
+ if (this @ModelImporter.stats != null ) {
193
+ this .originalId()?.let { stats.addReferenceChange(it, role) }
194
+ }
195
+ return setReferenceTarget(role, target)
196
+ }
197
+
161
198
}
0 commit comments