Index: trunk/grails-app/services/AssetService.groovy
===================================================================
--- trunk/grails-app/services/AssetService.groovy	(revision 278)
+++ trunk/grails-app/services/AssetService.groovy	(revision 278)
@@ -0,0 +1,103 @@
+class AssetService {
+
+    boolean transactional = false
+
+    def saveCopy(params) {
+        Asset.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.assetInstance && m.field)
+                    result.assetInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Asset", params.id] ]
+                return result
+            }
+
+            result.assetToCopy = Asset.get(params.assetToCopy?.id)
+            if(!result.assetToCopy)
+                return fail(code:"default.not.found")
+
+            if(!params.copyMethod)
+                fail(code:"asset.copy.method.required")
+
+            result.assetInstance =  new Asset(params)
+
+            if(result.assetInstance.hasErrors() || !result.assetInstance.save())
+                return fail(code:"default.create.failure")
+
+            def assetSubItemInstance1
+
+            // Copy subItems from level 2 and bellow.
+            def copyAssetSubItem = { assetSubItemToCopy, parentItem ->
+                def assetSubItemInstance = new AssetSubItem(name: assetSubItemToCopy.name,
+                                                                                            description: assetSubItemToCopy.description,
+                                                                                            parentItem: parentItem)
+
+                if(assetSubItemInstance.hasErrors() || !assetSubItemInstance.save())
+                    return fail(field:"subItems", code:"default.create.failure")
+
+                def i = 0
+                for(assetSubItem in assetSubItemToCopy.subItems) {
+                    call(assetSubItem, assetSubItemInstance)
+                    // Protect against endless recurrsion.
+                    i++
+                    if(i > 100)
+                        fail(code:"default.create.failure")
+                    // Stop if an error is flagged.
+                    if(result.error)
+                        break
+                }
+            } //copyAssetSubItem
+
+            // Copy the 1st level of subItems.
+            def copyAssetSubItem1 = { assetSubItemToCopy ->
+                assetSubItemInstance1 = new AssetSubItem(name: assetSubItemToCopy.name,
+                                                                                        description: assetSubItemToCopy.description,
+                                                                                        asset: result.assetInstance)
+
+                if(assetSubItemInstance1.hasErrors() || !assetSubItemInstance1.save())
+                    return fail(field:"assetSubItems", code:"default.create.failure")
+
+                result.assetInstance.addToAssetSubItems(assetSubItemInstance1)
+
+                def i = 0
+                for(assetSubItem in assetSubItemToCopy.subItems) {
+                    copyAssetSubItem(assetSubItem, assetSubItemInstance1)
+                    // Protect against endless recurrsion.
+                    i++
+                    if(i > 100)
+                        fail(code:"default.create.failure")
+                    // Stop if an error is flagged.
+                    if(result.error)
+                        break
+                }
+            } //copyAssetSubItem1
+
+            def linkAssetSubItem = { assetSubItemToLink ->
+                result.assetInstance.addToAssetSubItems(assetSubItemToLink)
+            }
+
+            def i = 0
+            for(assetSubItem in result.assetToCopy.assetSubItems) {
+
+                if(params.copyMethod == "copy")
+                    copyAssetSubItem1(assetSubItem)
+                else
+                    linkAssetSubItem(assetSubItem)
+                // Protect against endless recurrsion.
+                i++
+                if(i > 100)
+                    fail(code:"default.create.failure")
+                // Stop if an error is flagged.
+                if(result.error)
+                    break
+            }
+
+            // Success or not.
+            return result
+
+        } //end withTransaction
+    } // end saveCopySrvce
+
+} // end class
