<!--
  ~ Copyright (c) 2010-2025 Evolveum
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~     http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
-->

<!--
Task to batch update the Archetype assignment.

== Use case ==

In case just one Archetype used to be applied on Users and new
configuration require to apply multiple one.

== Assumptions for the "automatic" transition using this task directly ==

The "original" Archetype suppose to be Person (filter in <object>).
Newly used archetype is based on value available on the user object ( newVal calculation in the task).

== Technical background ==

On the User object there are currently 3 relevant places where the current Archetype is visible.
 - assignment / targetRef ( type = ArchetypeType )
 - archetypeRef ( type = ArchetypeType )
 - roleMembershipRef ( type = ArchetypeType )

To change the Archetype the current assignment has to be replaced.
Other relevant items ( archetypeRef and roleMembershipRef ) are updated automatically during the assignment
change processing.

[NOTE] The task is imported in state closed - it is not automatically started ( run it manually after import ).
-->

<task xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
      xmlns:c="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
      xmlns:q="http://prism.evolveum.com/xml/ns/public/query-3"
      xmlns:s="http://midpoint.evolveum.com/xml/ns/public/model/scripting-3">
    <name>Change Archetype for the user</name>
    <ownerRef oid="00000000-0000-0000-0000-000000000002"/>
    <executionState>closed</executionState>
    <activity>
        <work>
            <iterativeScripting>
                <objects>
                    <type>c:UserType</type>
                    <query>
                        <q:filter>
                            <!-- Query filter to reduce amount of object to process -->
                            <q:text>assignment/targetRef matches ( targetType = ArchetypeType ) and assignment/targetRef/@/name = "Person"</q:text>
                        </q:filter>
                    </query>
                </objects>
                <scriptExecutionRequest>
                    <s:execute>
                        <s:script>
                            <code>

                                import com.evolveum.midpoint.prism.path.ItemPath
                                import com.evolveum.midpoint.schema.result.OperationResult
                                import com.evolveum.midpoint.schema.result.OperationResultStatus
                                import com.evolveum.midpoint.xml.ns._public.common.common_3.ArchetypeType
                                import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType
                                import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType
                                import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType

                                // preparing the delta structure for the changes
                                def deltas = midpoint.deltaFor(UserType.class)

                                // preparing the string with information about currently processed user
                                String userId = "User : " + input.getName().toString() + " (" + input.getOid() + ")"

                                // Iterate the assignments on the object
                                for (AssignmentType iterAssignment in input.getAssignment()) {

                                    // continue only in case the type is Archetype
                                    if (iterAssignment.getTargetRef().getType() == ArchetypeType.COMPLEX_TYPE) {

                                        // may be also other test if Archetype is matching (e.g. structural Archetype vs. Auxiliary Archetype)
                                        // in this example we expect just one Archetype ( Structural archetype ) so no other test is needed

                                        // test if the information for change is valid (e.g. content of the Title)
                                        if (!basic.isEmpty(input.getTitle())) {

                                            // condition for newly applied Archetype name
                                            // e.g. New name is set based on the value of Title
                                            String newVal = "N/A"
                                            switch(input.getTitle().toString()) {
                                                case "5":
                                                    newVal = "arch-000005"
                                                    break
                                                case "8":
                                                    newVal = "arch-000008"
                                                    break
                                                case "10":
                                                    newVal = "arch-000010"
                                                    break
                                            }

                                            // search for the Archetype to
                                            //  - confirm proper calculation
                                            //  - to get new object information
                                            def archetypeList = midpoint.searchObjects(midpoint.queryFor(ArchetypeType.class,
                                                    "name = \"" + newVal + "\""
                                            ))

                                            // just one archetype have to match to continue
                                            if (archetypeList.size() == 1) {

                                                // add current assignment to remove into the delta
                                                deltas = deltas.item(ItemPath.create(UserType.F_ASSIGNMENT))
                                                        .delete(iterAssignment.clone())

                                                // build up the new Archetype assignment to add
                                                ObjectReferenceType toAddRef = new ObjectReferenceType()
                                                toAddRef.setOid(archetypeList.get(0).getOid())
                                                toAddRef.setType(ArchetypeType.COMPLEX_TYPE)
                                                AssignmentType toAdd = new AssignmentType()
                                                toAdd.setTargetRef(toAddRef)

                                                // add new assignment into the delta
                                                deltas = deltas.item(ItemPath.create(UserType.F_ASSIGNMENT))
                                                        .add(toAdd)

                                                // execute the delta - update the archetype
                                                midpoint.executeChanges(deltas.asObjectDeltas(input.getOid()))
                                            } else {
                                                // OPTIONAL : set overall status to Partial Error to see not all the users has been changed
                                                midpoint.getCurrentResult().recordPartialError("No new valid Archetype found - keep original one")

                                                // OPTIONAL : log user information
                                                log.info("{} - the archetype kept.", userId)

                                                // OPTIONAL : the information about unchanged users can be logged in the result of the task
                                                OperationResult info = new OperationResult(userId)
                                                info.setStatus(OperationResultStatus.PARTIAL_ERROR)
                                                info.setMessage("the archetype kept")
                                                info.recordEnd()
                                                midpoint.getCurrentTask().getResult().addSubresult(info)
                                            }
                                        }
                                    }
                                }
                            </code>
                        </s:script>
                    </s:execute>
                </scriptExecutionRequest>
            </iterativeScripting>
        </work>
    </activity>
</task>