<commit_before><?xml version="1.0" encoding="utf-8"?>
<!--
    Copyright (C) 2007-2008 Orbeon, Inc.

    This program is free software; you can redistribute it and/or modify it under the terms of the
    GNU Lesser General Public License as published by the Free Software Foundation; either version
    2.1 of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
    without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    See the GNU Lesser General Public License for more details.

    The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
-->
<xforms:model id="fr-persistence-model"
              xmlns:xs="http://www.w3.org/2001/XMLSchema"
              xmlns:xforms="http://www.w3.org/2002/xforms"
              xmlns:ev="http://www.w3.org/2001/xml-events"
              xmlns:xxforms="http://orbeon.org/oxf/xml/xforms"
              xmlns:xi="http://www.w3.org/2001/XInclude"
              xmlns:xxi="http://orbeon.org/oxf/xml/xinclude"
              xmlns:f="http://orbeon.org/oxf/xml/formatting"
              xmlns:xhtml="http://www.w3.org/1999/xhtml"
              xmlns:saxon="http://saxon.sf.net/"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
              xmlns:pipeline="java:org.orbeon.oxf.processor.pipeline.PipelineFunctionLibrary">

    <xxforms:variable name="parameters" select="xxforms:instance('fr-parameters-instance')"/>
    <xxforms:variable name="app" select="$parameters/app"/>
    <xxforms:variable name="form" select="$parameters/form"/>
    <xxforms:variable name="document" select="$parameters/document"/>

    <!-- Model initialization -->
    <!-- TODO: Should not do this on summary page, for example -->
    <xforms:action ev:event="xforms-model-construct-done">

        <!-- Initialize form, data, and new service URIs from properties properties -->
        <xforms:setvalue ref="instance('fr-uris-instance')/form-collection"
                         value="concat(xxforms:property('oxf.fr.appserver.uri'),
                                    xxforms:property(string-join(('oxf.fr.persistence.app.uri', $app, $form, 'form'), '.')))"/>
        <xforms:setvalue ref="instance('fr-uris-instance')/data-collection"
                         value="concat(xxforms:property('oxf.fr.appserver.uri'),
                                    xxforms:property(string-join(('oxf.fr.persistence.app.uri', $app, $form, 'data'), '.')))"/>
        <xxforms:variable name="new-service-uri" select="xxforms:property(string-join(('oxf.fr.detail.new.service.uri', $app, $form), '.'))"/>
        <xforms:setvalue ref="instance('fr-uris-instance')/new-service-uri"
                         value="if (starts-with($new-service-uri, '/'))
                            then concat(xxforms:property('oxf.fr.appserver.uri'), $new-service-uri)
                            else $new-service-uri"/>

        <!-- Initialize parameters to pass to "new" service -->
        <xxforms:variable name="pass-request-parameters" select="xxforms:property(string-join(('oxf.fr.detail.new.service.passing-request-parameters', $app, $form), '.'))"/>
        <xforms:action xxforms:iterate="tokenize($pass-request-parameters, '\s')">
            <xxforms:variable name="parameter-name" select="."/>
            <xxforms:variable name="parameter-value" select="xxforms:get-request-parameter($parameter-name)"/>
            <xforms:insert context="instance('fr-service-parameters')" origin="xxforms:element($parameter-name, $parameter-value)"/>
        </xforms:action>

        <!-- Initialize username and roles -->
        <xforms:action if="xxforms:property('oxf.fr.authentication.method') = 'container'">
            <!-- Case where we get the username and roles from the container -->
            <xforms:setvalue ref="instance('fr-authentication-headers')/header[@name = 'username']/@value" value="xxforms:get-remote-user()"/>
            <xforms:message level="xxforms:log-info">Roles: <xforms:output value="xxforms:property('oxf.fr.authentication.container.roles')"/></xforms:message>
            <xforms:action xxforms:iterate="tokenize(xxforms:property('oxf.fr.authentication.container.roles'), '\s')">
                <xxforms:variable name="role" select="."/>
                <xforms:action if="xxforms:is-user-in-role($role)">
                    <xforms:setvalue ref="instance('fr-authentication-headers')/header[@name = 'roles']/@value" value="if (. = '') then $role else concat(., ' ', $role)"/>
                </xforms:action>
            </xforms:action>
        </xforms:action>
        <xforms:action if="xxforms:property('oxf.fr.authentication.method') = 'header'">
            <!-- Case where we get the username and roles from headers -->
            <xforms:setvalue ref="instance('fr-authentication-headers')/header[@name = 'username']/@value" value="xxforms:get-request-header(xxforms:property('oxf.fr.authentication.header.username'))"/>
            <xforms:setvalue ref="instance('fr-authentication-headers')/header[@name = 'roles']/@value" value="xxforms:get-request-header(xxforms:property('oxf.fr.authentication.header.roles'))"/>
        </xforms:action>

        <!-- Load current form configuration -->
        <xxforms:variable name="source-form" select="xxforms:get-request-attribute('fr-form-definition')"/>
        <xforms:action if="exists($source-form)">
            <!-- Got it from the request -->
            <xforms:message level="xxforms:log-info">Got source form from request.</xforms:message>
            <xforms:insert nodeset="instance('fr-source-form-instance')" origin="$source-form"/>
        </xforms:action>
        <xforms:action if="not(exists($source-form))">
            <!--  Try submission -->
            <xforms:message level="xxforms:log-info">Could not get source form from request. Trying submission instead.</xforms:message>
            <xforms:send submission="get-source-form-submission"/>
        </xforms:action>

        <!-- Whether a document id is provided -->
        <xxforms:variable name="is-document-id-provided" select="$document != ''" as="xs:boolean"/>
        <xforms:action if="$is-document-id-provided">
            <!-- A document id is provided -->
            <xxforms:variable name="form-data" select="xxforms:get-request-attribute('fr-form-data')" as="document-node()?"/>
            <xforms:action if="$form-data">
                <!-- An id is provided, but the form data is also available in the request, so we use that first -->
                <xforms:insert nodeset="xxforms:instance('fr-form-instance')" origin="$form-data"/>
                <!-- Set initial data as dirty, because this is the case typically of switching between script/noscript
                     mode, and we can't really know if the data is clean or dirty but would like to enable the save button -->
                <xforms:setvalue ref="instance('fr-persistence-instance')/initial-data-status">dirty</xforms:setvalue>
            </xforms:action>
            <xforms:action if="not($form-data)">
                <!-- Load document with that id from persistence layer -->
                <xforms:send submission="fr-get-document-submission"/>
            </xforms:action>
        </xforms:action>
        <xforms:action if="not($is-document-id-provided)">
            <!-- No document id is provided -->
            <!-- Are we in new/edit mode -->
            <xxforms:variable name="is-new-document" select="$parameters/mode = ('new', 'edit')" as="xs:boolean"/>
            <xforms:action if="$is-new-document">
                <!-- Create random document id -->
                <xforms:setvalue ref="$document" value="digest(string(random(true)), 'MD5', 'hex')"/>
                <!-- Do we call a service to initialize the instance? -->
                <xforms:action if="xxforms:property(string-join(('oxf.fr.detail.new.service.enable', $app, $form), '.'))">
                    <xforms:send submission="fr-get-instance-from-service"/>
                </xforms:action>
                <!-- Do we accept data posted to this page? -->
                <xforms:action if="xxforms:property(string-join(('oxf.fr.detail.new.accept-post', $app, $form), '.'))">
                    <xxforms:variable name="form-data" select="xxforms:get-request-parameter('fr-form-data')"/>
                    <!-- Do we have data posted to this form? -->
                    <xforms:action if="$form-data">
                        <xxforms:variable name="xml-data" select="saxon:parse(saxon:base64Binary-to-string(xs:base64Binary($form-data), 'UTF-8'))"/>
                        <xforms:insert nodeset="xxforms:instance('fr-form-instance')" origin="$xml-data"/>
                    </xforms:action>
                </xforms:action>
            </xforms:action>
        </xforms:action>

        <!-- Force all this so we can safely set the data status -->
        <xforms:rebuild/>
        <xforms:recalculate/>
        <xforms:revalidate/>

        <!-- Set the initial data status -->
        <xforms:setvalue ref="instance('fr-persistence-instance')/data-status" value="../initial-data-status"/>
    </xforms:action>

    <!-- In case there is an error, show it (error occured when the controls are not yet ready) -->
    <xforms:action ev:event="xforms-ready">
        <xforms:toggle if="instance('fr-persistence-instance')/is-error = 'true'" case="fr-message-fatal-error"/>
    </xforms:action>

    <!-- Clear operation -->
    <xforms:action ev:event="fr-clear">
        <!-- Copy original instance -->
        <xxforms:variable name="instance-element" as="element(xforms:instance)"
                          select="instance('fr-source-form-instance')/xhtml:head/xforms:model[@id = 'fr-form-model']/xforms:instance[@id = 'fr-form-instance']"/>
        <!-- Case of inline template -->
        <xforms:insert if="not($instance-element/@src)" nodeset="xxforms:instance('fr-form-instance')" origin="$instance-element/*"/>
        <!-- Case of @src template -->
        <xforms:insert if="$instance-element/@src" nodeset="xxforms:instance('fr-form-instance')" origin="doc($instance-element/@src)"/>
    </xforms:action>

    <!-- New document operation -->
    <xforms:setvalue ev:event="fr-new-document" ref="$document" value="digest(string(random(true)), 'MD5', 'hex')"/>

    <!-- Delete operation -->
    <xforms:action ev:event="fr-delete-data">
        <xforms:send submission="fr-delete-document-submission">
            <xxforms:context name="document-id" select="event('document-id')"/>
        </xforms:send>
    </xforms:action>

    <xforms:submission id="fr-delete-document-submission"
            method="delete" serialization="none"
            resource="{instance('fr-uris-instance')/data-collection}/crud/{$app}/{$form}/data/{event('document-id')}/data.xml"
            replace="none">
        <xi:include href="persistence-model-headers.xml"/>
    </xforms:submission>

    <!-- Publish form operation -->
    <xforms:action ev:event="fr-publish-form">

        <!-- TODO: must also publish attachments! and make sure URLs are relative (?) -->

        <!-- Determine the URI of the collection to deploy to -->
        <xxforms:variable name="app" select="event('application')"/>
        <xxforms:variable name="form" select="event('form')"/>
        <xxforms:variable name="collection"
                          select="concat(xxforms:property('oxf.fr.appserver.uri'),
                                    xxforms:property(string-join(('oxf.fr.persistence.app.uri', $app, $form, 'form'), '.')))"/>

        <xforms:send submission="fr-publish-form-submission">
            <xxforms:context name="collection" select="$collection"/>
            <xxforms:context name="application" select="$app"/>
            <xxforms:context name="form" select="$form"/>
        </xforms:send>
    </xforms:action>

    <!-- Instance to store the result of the create/update submission -->
    <xforms:instance id="fr-publish-form-submission-response">
        <response xmlns=""/>
    </xforms:instance>

    <!-- TODO: not sure why we use xxforms:ensure-uploads="false" here -->
    <xforms:submission id="fr-publish-form-submission" xxforms:ensure-uploads="false"
            ref="xxforms:instance('fr-form-instance')" method="put"
            resource="{event('collection')}/crud/{event('application')}/{event('form')}/form/form.xhtml"
            replace="text" target="instance('fr-publish-form-submission-response')">
        <xi:include href="persistence-model-headers.xml"/>
        <!--<xforms:message ev:event="xforms-submit">-->
            <!--zzz-->
            <!--<xforms:output value="event('application')"/>-->
            <!--xxx-->
            <!--<xforms:output value="event('form')"/>-->
        <!--</xforms:message>-->
    </xforms:submission>

    <!-- Respond to save button activation -->
    <xforms:action ev:event="DOMActivate" ev:observer="fr-save-button">
        <xforms:setvalue ref="instance('fr-persistence-instance')/submit-or-save-or-send">save</xforms:setvalue>
        <xforms:dispatch name="fr-save-action" target="fr-persistence-model"/>
    </xforms:action>

    <!-- Respond to submit button activation -->
    <xforms:action ev:event="DOMActivate" ev:observer="fr-submit-button">
        <xforms:setvalue ref="instance('fr-persistence-instance')/submit-or-save-or-send">submit</xforms:setvalue>
        <xforms:dispatch name="fr-save-action" target="fr-persistence-model"/>
    </xforms:action>

    <!-- Respond to workflow preview button activation -->
    <xforms:action ev:event="DOMActivate" ev:observer="fr-workflow-review-button">
        <!-- Just send the submission -->
        <xforms:send submission="fr-workflow-review-submission"/>
    </xforms:action>

    <!-- Respond to workflow edit button activation -->
    <xforms:action ev:event="DOMActivate" ev:observer="fr-workflow-edit-button">
        <!-- Just send the submission -->
        <xforms:send submission="fr-workflow-edit-submission"/>
    </xforms:action>

    <!-- Respond to send button activation -->
    <xforms:action ev:event="DOMActivate" ev:observer="fr-workflow-send-button">
        <xforms:setvalue ref="instance('fr-persistence-instance')/submit-or-save-or-send">send</xforms:setvalue>
        <xforms:dispatch name="fr-save-action" target="fr-persistence-model"/>
    </xforms:action>

    <xforms:action ev:event="fr-save-action">
        <xforms:setvalue ref="instance('fr-persistence-instance')/save-attempted">true</xforms:setvalue>
        <xforms:action if="$document != ''">

            <!-- Handle attachments -->
            <xxforms:variable name="attachment-controls"
                              select="instance('fr-source-form-instance')/xhtml:body//(xforms:* | fr:*)[@bind and @class and tokenize(@class, ' ') = 'fr-attachment']"/>

            <!-- Find all binds with fb-attachment, or to which controls with fb-attachment are bound -->
            <xxforms:variable name="attachment-binds"
                              select="instance('fr-source-form-instance')/xhtml:head/xforms:model//xforms:bind[(@class and tokenize(@class, ' ') = 'fr-attachment')
                                        or @id = $attachment-controls/@bind]"/>

            <!--<xforms:message level="xxforms:log-error">-->
                <!--xxx 0-->
                <!--<xforms:output value="count($attachment-controls)"/>-->
            <!--</xforms:message>-->

            <!-- Use a global variable to determine whether we must continue -->
            <xforms:setvalue ref="instance('fr-persistence-instance')/is-error">false</xforms:setvalue>
            <xforms:setvalue ref="instance('fr-persistence-instance')/error"/>

            <!-- Iterate over attachment controls while there is no submission error -->
            <!--<xforms:action xxforms:iterate="$attachment-binds">-->
            <xforms:action xxforms:iterate="(1 to count($attachment-binds))">

                <xforms:action if="instance('fr-persistence-instance')/is-error = 'false'">
                    <xxforms:variable name="bind" select="(instance('fr-source-form-instance')/xhtml:head/xforms:model//xforms:bind[(@class and tokenize(@class, ' ') = 'fr-attachment')
                                        or @id = $attachment-controls/@bind])[number(context())]"/>

                    <!--
                        Argh: why does the sequence below suddenly does not contain nodes in document order? This
                        doesn't work properly:

                          string-join($bind/ancestor-or-self::xforms:bind/@nodeset, '/')

                        But it does work if split between:

                          o $bind/ancestor-or-self::xforms:bind and
                          o string-join($binds/@nodeset, '/')

                        This sounds like an issue similar to the one we had with preceding-sibling:: a while ago, and
                        was fixed in NodeWrapper. See:

                          http://forge.objectweb.org/tracker/?group_id=168&atid=350207&func=detail&aid=306836
                          http://forge.objectweb.org/tracker/?group_id=168&atid=350207&func=detail&aid=304850

                    -->
                    <xxforms:variable name="binds" select="$bind/ancestor-or-self::xforms:bind"/>
                    <xxforms:variable name="expression" select="string-join($binds/@nodeset, '/')"/>

                    <!--<xforms:message level="xxforms:log-error">-->
                        <!--xxx <xforms:output value="string-join($binds/@nodeset, '/')"/> xxx-->
                        <!--xxx <xforms:output value="string-join(($bind/ancestor-or-self::xforms:bind/@nodeset), '/')"/> xxx-->
                        <!--xxx <xforms:output value="string-join(reverse($bind/ancestor-or-self::xforms:bind/@nodeset), '/')"/> xxx-->
                    <!--</xforms:message>-->

                    <xxforms:variable name="holders" model="fr-form-model" select="instance('fr-form-instance')/saxon:evaluate($expression)"/>

                    <xforms:action xxforms:iterate="$holders">
                        <xxforms:variable name="holder" select="."/>
                        <!-- Found attachment URI location -->
                        <xxforms:variable name="uri" select="normalize-space($holder)"/>
                        <xforms:action if="$uri != '' and starts-with($uri, 'file:')">
                            <!-- There is a URI to process -->

                            <xxforms:variable name="upload-extension" select="normalize-space(tokenize($holder/@filename, '\.')[last()])"/>
                            <xxforms:variable name="upload-has-extension" select="count(tokenize($holder/@filename, '\.')) gt 1 and $upload-extension != ''"/>
                            <xxforms:variable name="new-id" select="digest(string(random(true)), 'MD5', 'hex')"/>
                            <xxforms:variable name="new-filename" select="string-join(($new-id,
                                                                                        if (not($upload-has-extension)) then 'bin' else $upload-extension), '.')"/>
                            <xxforms:variable name="resource"
                                              select="concat(instance('fr-uris-instance')/data-collection, '/crud/',
                                                        $app, '/', $form, '/data/',
                                                        $document, '/', $new-filename)"/>


                            <!--<xforms:message level="xxforms:log-error">-->
                                <!--<xforms:output value="$upload-extension"/> - -->
                                <!--<xforms:output value="$upload-has-extension"/> - -->
                                <!--<xforms:output value="$new-id"/> - -->
                                <!--<xforms:output value="$new-filename"/> - -->
                                <!--<xforms:output value="$resource"/>-->
                            <!--</xforms:message>-->

                            <!-- Save attachment -->
                            <xforms:send submission="fr-create-update-attachment-submission">
                                <xxforms:context name="holder" select="$holder"/>
                                <xxforms:context name="resource" select="$resource"/>
                            </xforms:send>

                            <!-- Only keep the last part of the path -->
                            <xforms:setvalue ref="$holder" value="$resource"/>

                        </xforms:action>
                    </xforms:action>
                </xforms:action>
                
            </xforms:action>

            <!-- Handle XML document if there was no submission error -->
            <xforms:send submission="fr-create-update-submission" if="instance('fr-persistence-instance')/is-error = 'false'">
                <xxforms:context name="holder" select="xxforms:instance('fr-form-instance')"/>
                <!-- We always store form data as "data.xml" -->
                <xxforms:context name="resource" select="'data.xml'"/>
            </xforms:send>
        </xforms:action>
    </xforms:action>

    <!-- Persistence URIs -->
    <xforms:instance id="fr-uris-instance">
        <uris xmlns="">
            <form-collection/>
            <data-collection/>
            <new-service-uri/>
        </uris>
    </xforms:instance>

    <!-- Instance to store the result of the create/update submission -->
    <xforms:instance id="fr-create-update-submission-response">
        <response xmlns=""/>
    </xforms:instance>

    <!-- Submission to create/update the XML form -->
    <!-- TODO: not sure why we use xxforms:ensure-uploads="false" here -->
    <xforms:submission id="fr-create-update-submission"
            validate="true" method="put"
            ref="event('holder')" xxforms:ensure-uploads="false"
            resource="{instance('fr-uris-instance')/data-collection}/crud/{$app}/{$form}/data/{$document}/{event('resource')}"
            replace="text" target="instance('fr-create-update-submission-response')">
        <xi:include href="persistence-model-headers.xml"/>
    </xforms:submission>

    <!-- Submission to create/update an attachment -->
    <!-- TODO: not sure why we use xxforms:ensure-uploads="false" here -->
    <xforms:submission id="fr-create-update-attachment-submission"
            method="put" serialization="application/octet-stream"
            ref="event('holder')" xxforms:ensure-uploads="false"
            resource="{event('resource')}"
            replace="none">
        <xi:include href="persistence-model-headers.xml"/>
    </xforms:submission>

    <!-- Submission to preview the XML form -->
    <!-- TODO: not sure why we use xxforms:ensure-uploads="false" here -->
    <xforms:submission id="fr-workflow-review-submission"
            validate="true" method="post"
            ref="xxforms:instance('fr-form-instance')" xxforms:ensure-uploads="false"
            resource="/fr/{$app}/{$form}/view/{$document}/?fr-language={xxforms:instance('fr-language-instance')}{if (property('xxforms:noscript')) then '&amp;fr-noscript=true' else ''}"
            replace="all">
        <!-- Set data-safe-override -->
        <xforms:setvalue ev:event="xforms-submit" ref="instance('fr-persistence-instance')/data-safe-override">true</xforms:setvalue>
        <!-- Reset data-safe-override -->
        <xforms:setvalue ev:event="xforms-submit-done xforms-submit-error" ref="instance('fr-persistence-instance')/data-safe-override"/>
        <xi:include href="persistence-model-headers.xml"/>
    </xforms:submission>

    <!-- Submission to go back to editing the XML form -->
    <xforms:submission id="fr-workflow-edit-submission"
            validate="true" method="post"
            ref="xxforms:instance('fr-form-instance')"
            resource="/fr/{$app}/{$form}/edit/{$document}/?fr-language={xxforms:instance('fr-language-instance')}{if (property('xxforms:noscript')) then '&amp;fr-noscript=true' else ''}"
            replace="all">
        <!-- Set data-safe-override -->
        <xforms:setvalue ev:event="xforms-submit" ref="instance('fr-persistence-instance')/data-safe-override">true</xforms:setvalue>
        <!-- Reset data-safe-override -->
        <xforms:setvalue ev:event="xforms-submit-done xforms-submit-error" ref="instance('fr-persistence-instance')/data-safe-override"/>
        <xi:include href="persistence-model-headers.xml"/>
    </xforms:submission>

    <!-- Get document -->
    <xforms:submission id="fr-get-document-submission"
            method="get" serialization="none"
            resource="{instance('fr-uris-instance')/data-collection}/crud/{$app}/{$form}/data/{$document}/data.xml"
            replace="instance" xxforms:instance="fr-form-instance">
        <xi:include href="persistence-model-headers.xml"/>
    </xforms:submission>

    <!-- Source form with metadata -->
    <xforms:instance id="fr-source-form-instance" xxforms:readonly="false"><!-- Set to false so that xforms:insert works -->
        <form xmlns=""/>
    </xforms:instance>

    <xforms:submission id="get-source-form-submission"
            method="get" serialization="none"
            resource="{instance('fr-uris-instance')/form-collection}/crud/{$app}/{$form}/form/form.xhtml"
            replace="instance" instance="fr-source-form-instance" xxforms:readonly="true" xxforms:xinclude="true">
        <xi:include href="persistence-model-headers.xml"/>
    </xforms:submission>

    <xforms:instance id="fr-service-parameters">
        <parameters/>
    </xforms:instance>

    <!-- Calls a service to get the initial instance -->
    <xforms:submission id="fr-get-instance-from-service"
            method="get" separator="&amp;" ref="instance('fr-service-parameters')"
            resource="{instance('fr-uris-instance')/new-service-uri}"
            replace="instance" xxforms:instance="fr-form-instance"/>

    <xforms:instance id="fr-persistence-instance">
        <save xmlns="">
            <!-- Initial data status -->
            <initial-data-status>clean</initial-data-status>
            <!-- Whether form data is clean or dirty (i.e. saved or not saved) -->
            <data-status>clean</data-status>
            <!-- Whether an attempt to submit was ever done -->
            <save-attempted>false</save-attempted>
            <!-- Success or error message to display -->
            <message/>
            <!-- Error document returned -->
            <error/>
            <!-- Whether an error was received -->
            <is-error>false</is-error>
            <!-- Whether the last action that triggered the a fr-create-update-submission is a "submit" or a "save" -->
            <submit-or-save-or-send/>
            <!-- Flag to override data-safe -->
            <data-safe-override/>
            <!-- Whether data is safe -->
            <data-safe/>
        </save>
    </xforms:instance>

    <xforms:bind nodeset="instance('fr-persistence-instance')">
        <xforms:bind nodeset="data-safe" calculate="../data-status = 'clean' or ../data-safe-override = 'true'"/>
    </xforms:bind>

    <!-- Configuration for Saxon serialization -->
    <xforms:instance id="fr-xsl-output-instance">
        <xsl:output xmlns:xsl="http://www.w3.org/1999/XSL/Transform" method="xml" omit-xml-declaration="yes" indent="yes" saxon:indent-spaces="4"/>
    </xforms:instance>

    <xforms:instance id="fr-triggers-instance">
        <triggers xmlns="">
            <save/>
            <submit/>
            <discard/>
        </triggers>
    </xforms:instance>

    <xforms:instance id="fr-authentication-headers">
        <headers>
            <header name="username" value=""/>
            <header name="roles" value=""/>
        </headers>
    </xforms:instance>

    <xforms:bind nodeset="instance('fr-triggers-instance')">
        <xforms:bind nodeset="save" readonly="not(property('xxforms:noscript'))
            and (instance('fr-persistence-instance')/data-status = 'clean' or xxforms:instance('fr-form-valid-instance') = 'false')"/>
        <xforms:bind nodeset="submit" readonly="not(property('xxforms:noscript')) and xxforms:instance('fr-form-valid-instance') = 'false'"/>
    </xforms:bind>

    <!-- React to successful submission when saving/updating -->
    <xforms:action ev:event="xforms-submit-done" ev:target="fr-create-update-submission">
        <xforms:setvalue ref="instance('fr-persistence-instance')/message"
                         value="xxforms:instance('fr-fr-current-resources')/detail/messages/save-success"/>

        <!-- Show success message -->
        <xforms:toggle case="fr-message-success"/>

        <!-- HACK: Force this before cleaning the status because we do a setvalue just before calling the submission -->
        <xforms:recalculate/>
        <xforms:refresh/>

        <xforms:setvalue ref="instance('fr-persistence-instance')/data-status">clean</xforms:setvalue>

        <!-- If the document was saved because of a "submit", handle the rest of the submission process in dialog -->
        <xforms:action if="instance('fr-persistence-instance')/submit-or-save-or-send = 'submit'">
            <!-- Show the submission result dialog -->
            <xxforms:show dialog="fr-submission-result-dialog">
                <xxforms:context name="fr:content" select="instance('fr-create-update-submission-response')"/>
            </xxforms:show>
        </xforms:action>

        <!-- If the document was saved because of a "send", handle the rest of the submission process -->
        <xforms:action if="instance('fr-persistence-instance')/submit-or-save-or-send = 'send'">

            <!-- Create PDF if requested -->
            <xforms:send if="xxforms:property(string-join(('oxf.fr.detail.send.pdf', $app, $form), '.'))
                                or xxforms:property(string-join(('oxf.fr.email.attach-pdf', $app, $form), '.'))
                                or xxforms:property(string-join(('oxf.fr.alfresco.send-pdf', $app, $form), '.'))" submission="fr-pdf-service-submission"/>

            <xforms:action if="instance('fr-persistence-instance')/is-error = 'false'">
                <!-- Send to Alfresco if requested -->
                <xforms:action if="xxforms:property(string-join(('oxf.fr.detail.send.alfresco', $app, $form), '.'))">

                    <!-- Form definition -->
                    <xxforms:variable name="html" select="instance('fr-source-form-instance')" as="element(xhtml:html)"/>

                    <!-- Pass metadata with current language, or first language if current language is not found -->
                    <xxforms:variable name="form-titles" select="$html/xhtml:head//xforms:instance[@id = 'fr-form-metadata']/*/title" as="xs:string"/>
                    <xxforms:variable name="form-descriptions" select="$html/xhtml:head//xforms:instance[@id = 'fr-form-metadata']/*/description" as="xs:string"/>
                    <xxforms:variable name="form-title" select="($form-titles[@xml:lang = xxforms:instance('fr-language-instance')], $form-titles[1])[1]" as="xs:string"/>
                    <xxforms:variable name="form-description" select="($form-descriptions[@xml:lang = xxforms:instance('fr-language-instance')], $form-descriptions[1])[1]" as="xs:string"/>

                    <!-- Send PDF data if requested -->
                    <xforms:action if="xxforms:property(string-join(('oxf.fr.alfresco.send-pdf', $app, $form), '.'))">
                        <!-- Get URI of PDF data -->
                        <xxforms:variable name="pdf-uri" select="pipeline:rewriteResourceURI(concat(xxforms:property('oxf.fr.appserver.uri'), instance('fr-workflow-confirmation-instance')), true())" as="xs:anyURI"/>

                        <!-- Send everything to Alfresco -->
                        <xforms:dispatch target="fr-alfresco-model" name="alfresco-send-document">
                            <xxforms:context name="fr:name" select="concat($form-title, ' (#', $document, ').pdf')"/><commit_msg>Comment.<commit_after><?xml version="1.0" encoding="utf-8"?>
<!--
    Copyright (C) 2007-2008 Orbeon, Inc.

    This program is free software; you can redistribute it and/or modify it under the terms of the
    GNU Lesser General Public License as published by the Free Software Foundation; either version
    2.1 of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
    without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    See the GNU Lesser General Public License for more details.

    The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
-->
<xforms:model id="fr-persistence-model"
              xmlns:xs="http://www.w3.org/2001/XMLSchema"
              xmlns:xforms="http://www.w3.org/2002/xforms"
              xmlns:ev="http://www.w3.org/2001/xml-events"
              xmlns:xxforms="http://orbeon.org/oxf/xml/xforms"
              xmlns:xi="http://www.w3.org/2001/XInclude"
              xmlns:xxi="http://orbeon.org/oxf/xml/xinclude"
              xmlns:f="http://orbeon.org/oxf/xml/formatting"
              xmlns:xhtml="http://www.w3.org/1999/xhtml"
              xmlns:saxon="http://saxon.sf.net/"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
              xmlns:pipeline="java:org.orbeon.oxf.processor.pipeline.PipelineFunctionLibrary">

    <xxforms:variable name="parameters" select="xxforms:instance('fr-parameters-instance')"/>
    <xxforms:variable name="app" select="$parameters/app"/>
    <xxforms:variable name="form" select="$parameters/form"/>
    <xxforms:variable name="document" select="$parameters/document"/>

    <!-- Model initialization -->
    <!-- TODO: Should not do this on summary page, for example -->
    <xforms:action ev:event="xforms-model-construct-done">

        <!-- Initialize form, data, and new service URIs from properties properties -->
        <xforms:setvalue ref="instance('fr-uris-instance')/form-collection"
                         value="concat(xxforms:property('oxf.fr.appserver.uri'),
                                    xxforms:property(string-join(('oxf.fr.persistence.app.uri', $app, $form, 'form'), '.')))"/>
        <xforms:setvalue ref="instance('fr-uris-instance')/data-collection"
                         value="concat(xxforms:property('oxf.fr.appserver.uri'),
                                    xxforms:property(string-join(('oxf.fr.persistence.app.uri', $app, $form, 'data'), '.')))"/>
        <xxforms:variable name="new-service-uri" select="xxforms:property(string-join(('oxf.fr.detail.new.service.uri', $app, $form), '.'))"/>
        <xforms:setvalue ref="instance('fr-uris-instance')/new-service-uri"
                         value="if (starts-with($new-service-uri, '/'))
                            then concat(xxforms:property('oxf.fr.appserver.uri'), $new-service-uri)
                            else $new-service-uri"/>

        <!-- Initialize parameters to pass to "new" service -->
        <xxforms:variable name="pass-request-parameters" select="xxforms:property(string-join(('oxf.fr.detail.new.service.passing-request-parameters', $app, $form), '.'))"/>
        <xforms:action xxforms:iterate="tokenize($pass-request-parameters, '\s')">
            <xxforms:variable name="parameter-name" select="."/>
            <xxforms:variable name="parameter-value" select="xxforms:get-request-parameter($parameter-name)"/>
            <xforms:insert context="instance('fr-service-parameters')" origin="xxforms:element($parameter-name, $parameter-value)"/>
        </xforms:action>

        <!-- Initialize username and roles -->
        <xforms:action if="xxforms:property('oxf.fr.authentication.method') = 'container'">
            <!-- Case where we get the username and roles from the container -->
            <xforms:setvalue ref="instance('fr-authentication-headers')/header[@name = 'username']/@value" value="xxforms:get-remote-user()"/>
            <xforms:message level="xxforms:log-info">Roles: <xforms:output value="xxforms:property('oxf.fr.authentication.container.roles')"/></xforms:message>
            <xforms:action xxforms:iterate="tokenize(xxforms:property('oxf.fr.authentication.container.roles'), '\s')">
                <xxforms:variable name="role" select="."/>
                <xforms:action if="xxforms:is-user-in-role($role)">
                    <xforms:setvalue ref="instance('fr-authentication-headers')/header[@name = 'roles']/@value" value="if (. = '') then $role else concat(., ' ', $role)"/>
                </xforms:action>
            </xforms:action>
        </xforms:action>
        <xforms:action if="xxforms:property('oxf.fr.authentication.method') = 'header'">
            <!-- Case where we get the username and roles from headers -->
            <xforms:setvalue ref="instance('fr-authentication-headers')/header[@name = 'username']/@value" value="xxforms:get-request-header(xxforms:property('oxf.fr.authentication.header.username'))"/>
            <xforms:setvalue ref="instance('fr-authentication-headers')/header[@name = 'roles']/@value" value="xxforms:get-request-header(xxforms:property('oxf.fr.authentication.header.roles'))"/>
        </xforms:action>

        <!-- Load current form configuration -->
        <xxforms:variable name="source-form" select="xxforms:get-request-attribute('fr-form-definition')"/>
        <xforms:action if="exists($source-form)">
            <!-- Got it from the request -->
            <xforms:message level="xxforms:log-info">Got source form from request.</xforms:message>
            <xforms:insert nodeset="instance('fr-source-form-instance')" origin="$source-form"/>
        </xforms:action>
        <xforms:action if="not(exists($source-form))">
            <!--  Try submission -->
            <xforms:message level="xxforms:log-info">Could not get source form from request. Trying submission instead.</xforms:message>
            <xforms:send submission="get-source-form-submission"/>
        </xforms:action>

        <!-- Whether a document id is provided -->
        <xxforms:variable name="is-document-id-provided" select="$document != ''" as="xs:boolean"/>
        <xforms:action if="$is-document-id-provided">
            <!-- A document id is provided -->
            <xxforms:variable name="form-data" select="xxforms:get-request-attribute('fr-form-data')" as="document-node()?"/>
            <xforms:action if="$form-data">
                <!-- An id is provided, but the form data is also available in the request, so we use that first -->
                <xforms:insert nodeset="xxforms:instance('fr-form-instance')" origin="$form-data"/>
                <!-- Set initial data as dirty, because this is the case typically of switching between script/noscript
                     mode, and we can't really know if the data is clean or dirty but would like to enable the save button -->
                <xforms:setvalue ref="instance('fr-persistence-instance')/initial-data-status">dirty</xforms:setvalue>
            </xforms:action>
            <xforms:action if="not($form-data)">
                <!-- Load document with that id from persistence layer -->
                <xforms:send submission="fr-get-document-submission"/>
            </xforms:action>
        </xforms:action>
        <xforms:action if="not($is-document-id-provided)">
            <!-- No document id is provided -->
            <!-- Are we in new/edit mode -->
            <xxforms:variable name="is-new-document" select="$parameters/mode = ('new', 'edit')" as="xs:boolean"/>
            <xforms:action if="$is-new-document">
                <!-- Create random document id -->
                <xforms:setvalue ref="$document" value="digest(string(random(true)), 'MD5', 'hex')"/>
                <!-- Do we call a service to initialize the instance? -->
                <xforms:action if="xxforms:property(string-join(('oxf.fr.detail.new.service.enable', $app, $form), '.'))">
                    <xforms:send submission="fr-get-instance-from-service"/>
                </xforms:action>
                <!-- Do we accept data posted to this page? -->
                <xforms:action if="xxforms:property(string-join(('oxf.fr.detail.new.accept-post', $app, $form), '.'))">
                    <xxforms:variable name="form-data" select="xxforms:get-request-parameter('fr-form-data')"/>
                    <!-- Do we have data posted to this form? -->
                    <xforms:action if="$form-data">
                        <xxforms:variable name="xml-data" select="saxon:parse(saxon:base64Binary-to-string(xs:base64Binary($form-data), 'UTF-8'))"/>
                        <xforms:insert nodeset="xxforms:instance('fr-form-instance')" origin="$xml-data"/>
                    </xforms:action>
                </xforms:action>
            </xforms:action>
        </xforms:action>

        <!-- Force all this so we can safely set the data status -->
        <xforms:rebuild/>
        <xforms:recalculate/>
        <xforms:revalidate/>

        <!-- Set the initial data status -->
        <xforms:setvalue ref="instance('fr-persistence-instance')/data-status" value="../initial-data-status"/>
    </xforms:action>

    <!-- In case there is an error, show it (error occured when the controls are not yet ready) -->
    <xforms:action ev:event="xforms-ready">
        <xforms:toggle if="instance('fr-persistence-instance')/is-error = 'true'" case="fr-message-fatal-error"/>
    </xforms:action>

    <!-- Clear operation -->
    <xforms:action ev:event="fr-clear">
        <!-- Copy original instance -->
        <xxforms:variable name="instance-element" as="element(xforms:instance)"
                          select="instance('fr-source-form-instance')/xhtml:head/xforms:model[@id = 'fr-form-model']/xforms:instance[@id = 'fr-form-instance']"/>
        <!-- Case of inline template -->
        <xforms:insert if="not($instance-element/@src)" nodeset="xxforms:instance('fr-form-instance')" origin="$instance-element/*"/>
        <!-- Case of @src template -->
        <xforms:insert if="$instance-element/@src" nodeset="xxforms:instance('fr-form-instance')" origin="doc($instance-element/@src)"/>
    </xforms:action>

    <!-- New document operation -->
    <xforms:setvalue ev:event="fr-new-document" ref="$document" value="digest(string(random(true)), 'MD5', 'hex')"/>

    <!-- Delete operation -->
    <xforms:action ev:event="fr-delete-data">
        <xforms:send submission="fr-delete-document-submission">
            <xxforms:context name="document-id" select="event('document-id')"/>
        </xforms:send>
    </xforms:action>

    <xforms:submission id="fr-delete-document-submission"
            method="delete" serialization="none"
            resource="{instance('fr-uris-instance')/data-collection}/crud/{$app}/{$form}/data/{event('document-id')}/data.xml"
            replace="none">
        <xi:include href="persistence-model-headers.xml"/>
    </xforms:submission>

    <!-- Publish form operation -->
    <xforms:action ev:event="fr-publish-form">

        <!-- TODO: must also publish attachments! and make sure URLs are relative (?) -->

        <!-- Determine the URI of the collection to deploy to -->
        <xxforms:variable name="app" select="event('application')"/>
        <xxforms:variable name="form" select="event('form')"/>
        <xxforms:variable name="collection"
                          select="concat(xxforms:property('oxf.fr.appserver.uri'),
                                    xxforms:property(string-join(('oxf.fr.persistence.app.uri', $app, $form, 'form'), '.')))"/>

        <xforms:send submission="fr-publish-form-submission">
            <xxforms:context name="collection" select="$collection"/>
            <xxforms:context name="application" select="$app"/>
            <xxforms:context name="form" select="$form"/>
        </xforms:send>
    </xforms:action>

    <!-- Instance to store the result of the create/update submission -->
    <xforms:instance id="fr-publish-form-submission-response">
        <response xmlns=""/>
    </xforms:instance>

    <!-- TODO: not sure why we use xxforms:ensure-uploads="false" here -->
    <xforms:submission id="fr-publish-form-submission" xxforms:ensure-uploads="false"
            ref="xxforms:instance('fr-form-instance')" method="put"
            resource="{event('collection')}/crud/{event('application')}/{event('form')}/form/form.xhtml"
            replace="text" target="instance('fr-publish-form-submission-response')">
        <xi:include href="persistence-model-headers.xml"/>
        <!--<xforms:message ev:event="xforms-submit">-->
            <!--zzz-->
            <!--<xforms:output value="event('application')"/>-->
            <!--xxx-->
            <!--<xforms:output value="event('form')"/>-->
        <!--</xforms:message>-->
    </xforms:submission>

    <!-- Respond to save button activation -->
    <xforms:action ev:event="DOMActivate" ev:observer="fr-save-button">
        <xforms:setvalue ref="instance('fr-persistence-instance')/submit-or-save-or-send">save</xforms:setvalue>
        <xforms:dispatch name="fr-save-action" target="fr-persistence-model"/>
    </xforms:action>

    <!-- Respond to submit button activation -->
    <xforms:action ev:event="DOMActivate" ev:observer="fr-submit-button">
        <xforms:setvalue ref="instance('fr-persistence-instance')/submit-or-save-or-send">submit</xforms:setvalue>
        <xforms:dispatch name="fr-save-action" target="fr-persistence-model"/>
    </xforms:action>

    <!-- Respond to workflow preview button activation -->
    <xforms:action ev:event="DOMActivate" ev:observer="fr-workflow-review-button">
        <!-- Just send the submission -->
        <xforms:send submission="fr-workflow-review-submission"/>
    </xforms:action>

    <!-- Respond to workflow edit button activation -->
    <xforms:action ev:event="DOMActivate" ev:observer="fr-workflow-edit-button">
        <!-- Just send the submission -->
        <xforms:send submission="fr-workflow-edit-submission"/>
    </xforms:action>

    <!-- Respond to send button activation -->
    <xforms:action ev:event="DOMActivate" ev:observer="fr-workflow-send-button">
        <xforms:setvalue ref="instance('fr-persistence-instance')/submit-or-save-or-send">send</xforms:setvalue>
        <xforms:dispatch name="fr-save-action" target="fr-persistence-model"/>
    </xforms:action>

    <xforms:action ev:event="fr-save-action">
        <xforms:setvalue ref="instance('fr-persistence-instance')/save-attempted">true</xforms:setvalue>
        <xforms:action if="$document != ''">

            <!-- Handle attachments -->
            <xxforms:variable name="attachment-controls"
                              select="instance('fr-source-form-instance')/xhtml:body//(xforms:* | fr:*)[@bind and @class and tokenize(@class, ' ') = 'fr-attachment']"/>

            <!-- Find all binds with fb-attachment, or to which controls with fb-attachment are bound -->
            <xxforms:variable name="attachment-binds"
                              select="instance('fr-source-form-instance')/xhtml:head/xforms:model//xforms:bind[(@class and tokenize(@class, ' ') = 'fr-attachment')
                                        or @id = $attachment-controls/@bind]"/>

            <!--<xforms:message level="xxforms:log-error">-->
                <!--xxx 0-->
                <!--<xforms:output value="count($attachment-controls)"/>-->
            <!--</xforms:message>-->

            <!-- Use a global variable to determine whether we must continue -->
            <xforms:setvalue ref="instance('fr-persistence-instance')/is-error">false</xforms:setvalue>
            <xforms:setvalue ref="instance('fr-persistence-instance')/error"/>

            <!-- Iterate over attachment controls while there is no submission error -->
            <!--<xforms:action xxforms:iterate="$attachment-binds">-->
            <xforms:action xxforms:iterate="(1 to count($attachment-binds))">

                <xforms:action if="instance('fr-persistence-instance')/is-error = 'false'">
                    <xxforms:variable name="bind" select="(instance('fr-source-form-instance')/xhtml:head/xforms:model//xforms:bind[(@class and tokenize(@class, ' ') = 'fr-attachment')
                                        or @id = $attachment-controls/@bind])[number(context())]"/>

                    <!--
                        Argh: why does the sequence below suddenly does not contain nodes in document order? This
                        doesn't work properly:

                          string-join($bind/ancestor-or-self::xforms:bind/@nodeset, '/')

                        But it does work if split between:

                          o $bind/ancestor-or-self::xforms:bind and
                          o string-join($binds/@nodeset, '/')

                        This sounds like an issue similar to the one we had with preceding-sibling:: a while ago, and
                        was fixed in NodeWrapper. See:

                          http://forge.objectweb.org/tracker/?group_id=168&atid=350207&func=detail&aid=306836
                          http://forge.objectweb.org/tracker/?group_id=168&atid=350207&func=detail&aid=304850

                    -->
                    <xxforms:variable name="binds" select="$bind/ancestor-or-self::xforms:bind"/>
                    <xxforms:variable name="expression" select="string-join($binds/@nodeset, '/')"/>

                    <!--<xforms:message level="xxforms:log-error">-->
                        <!--xxx <xforms:output value="string-join($binds/@nodeset, '/')"/> xxx-->
                        <!--xxx <xforms:output value="string-join(($bind/ancestor-or-self::xforms:bind/@nodeset), '/')"/> xxx-->
                        <!--xxx <xforms:output value="string-join(reverse($bind/ancestor-or-self::xforms:bind/@nodeset), '/')"/> xxx-->
                    <!--</xforms:message>-->

                    <xxforms:variable name="holders" model="fr-form-model" select="instance('fr-form-instance')/saxon:evaluate($expression)"/>

                    <xforms:action xxforms:iterate="$holders">
                        <xxforms:variable name="holder" select="."/>
                        <!-- Found attachment URI location -->
                        <xxforms:variable name="uri" select="normalize-space($holder)"/>
                        <xforms:action if="$uri != '' and starts-with($uri, 'file:')">
                            <!-- There is a URI to process -->

                            <xxforms:variable name="upload-extension" select="normalize-space(tokenize($holder/@filename, '\.')[last()])"/>
                            <xxforms:variable name="upload-has-extension" select="count(tokenize($holder/@filename, '\.')) gt 1 and $upload-extension != ''"/>
                            <xxforms:variable name="new-id" select="digest(string(random(true)), 'MD5', 'hex')"/>
                            <xxforms:variable name="new-filename" select="string-join(($new-id,
                                                                                        if (not($upload-has-extension)) then 'bin' else $upload-extension), '.')"/>
                            <xxforms:variable name="resource"
                                              select="concat(instance('fr-uris-instance')/data-collection, '/crud/',
                                                        $app, '/', $form, '/data/',
                                                        $document, '/', $new-filename)"/>


                            <!--<xforms:message level="xxforms:log-error">-->
                                <!--<xforms:output value="$upload-extension"/> - -->
                                <!--<xforms:output value="$upload-has-extension"/> - -->
                                <!--<xforms:output value="$new-id"/> - -->
                                <!--<xforms:output value="$new-filename"/> - -->
                                <!--<xforms:output value="$resource"/>-->
                            <!--</xforms:message>-->

                            <!-- Save attachment -->
                            <xforms:send submission="fr-create-update-attachment-submission">
                                <xxforms:context name="holder" select="$holder"/>
                                <xxforms:context name="resource" select="$resource"/>
                            </xforms:send>

                            <!-- Only keep the last part of the path -->
                            <xforms:setvalue ref="$holder" value="$resource"/>

                        </xforms:action>
                    </xforms:action>
                </xforms:action>
                
            </xforms:action>

            <!-- Handle XML document if there was no submission error -->
            <xforms:send submission="fr-create-update-submission" if="instance('fr-persistence-instance')/is-error = 'false'">
                <xxforms:context name="holder" select="xxforms:instance('fr-form-instance')"/>
                <!-- We always store form data as "data.xml" -->
                <xxforms:context name="resource" select="'data.xml'"/>
            </xforms:send>
        </xforms:action>
    </xforms:action>

    <!-- Persistence URIs -->
    <xforms:instance id="fr-uris-instance">
        <uris xmlns="">
            <form-collection/>
            <data-collection/>
            <new-service-uri/>
        </uris>
    </xforms:instance>

    <!-- Instance to store the result of the create/update submission -->
    <xforms:instance id="fr-create-update-submission-response">
        <response xmlns=""/>
    </xforms:instance>

    <!-- Submission to create/update the XML form -->
    <!-- TODO: not sure why we use xxforms:ensure-uploads="false" here -->
    <xforms:submission id="fr-create-update-submission"
            validate="true" method="put"
            ref="event('holder')" xxforms:ensure-uploads="false"
            resource="{instance('fr-uris-instance')/data-collection}/crud/{$app}/{$form}/data/{$document}/{event('resource')}"
            replace="text" target="instance('fr-create-update-submission-response')">
        <xi:include href="persistence-model-headers.xml"/>
    </xforms:submission>

    <!-- Submission to create/update an attachment -->
    <!-- TODO: not sure why we use xxforms:ensure-uploads="false" here -->
    <xforms:submission id="fr-create-update-attachment-submission"
            method="put" serialization="application/octet-stream"
            ref="event('holder')" xxforms:ensure-uploads="false"
            resource="{event('resource')}"
            replace="none">
        <xi:include href="persistence-model-headers.xml"/>
    </xforms:submission>

    <!-- Submission to preview the XML form -->
    <!-- TODO: not sure why we use xxforms:ensure-uploads="false" here -->
    <xforms:submission id="fr-workflow-review-submission"
            validate="true" method="post"
            ref="xxforms:instance('fr-form-instance')" xxforms:ensure-uploads="false"
            resource="/fr/{$app}/{$form}/view/{$document}/?fr-language={xxforms:instance('fr-language-instance')}{if (property('xxforms:noscript')) then '&amp;fr-noscript=true' else ''}"
            replace="all">
        <!-- Set data-safe-override -->
        <xforms:setvalue ev:event="xforms-submit" ref="instance('fr-persistence-instance')/data-safe-override">true</xforms:setvalue>
        <!-- Reset data-safe-override -->
        <xforms:setvalue ev:event="xforms-submit-done xforms-submit-error" ref="instance('fr-persistence-instance')/data-safe-override"/>
        <xi:include href="persistence-model-headers.xml"/>
    </xforms:submission>

    <!-- Submission to go back to editing the XML form -->
    <xforms:submission id="fr-workflow-edit-submission"
            validate="true" method="post"
            ref="xxforms:instance('fr-form-instance')"
            resource="/fr/{$app}/{$form}/edit/{$document}/?fr-language={xxforms:instance('fr-language-instance')}{if (property('xxforms:noscript')) then '&amp;fr-noscript=true' else ''}"
            replace="all">
        <!-- Set data-safe-override -->
        <xforms:setvalue ev:event="xforms-submit" ref="instance('fr-persistence-instance')/data-safe-override">true</xforms:setvalue>
        <!-- Reset data-safe-override -->
        <xforms:setvalue ev:event="xforms-submit-done xforms-submit-error" ref="instance('fr-persistence-instance')/data-safe-override"/>
        <xi:include href="persistence-model-headers.xml"/>
    </xforms:submission>

    <!-- Get document -->
    <xforms:submission id="fr-get-document-submission"
            method="get" serialization="none"
            resource="{instance('fr-uris-instance')/data-collection}/crud/{$app}/{$form}/data/{$document}/data.xml"
            replace="instance" xxforms:instance="fr-form-instance">
        <xi:include href="persistence-model-headers.xml"/>
    </xforms:submission>

    <!-- Source form with metadata -->
    <xforms:instance id="fr-source-form-instance" xxforms:readonly="false"><!-- Set to false so that xforms:insert works -->
        <form xmlns=""/>
    </xforms:instance>

    <xforms:submission id="get-source-form-submission"
            method="get" serialization="none"
            resource="{instance('fr-uris-instance')/form-collection}/crud/{$app}/{$form}/form/form.xhtml"
            replace="instance" instance="fr-source-form-instance" xxforms:readonly="true" xxforms:xinclude="true">
        <xi:include href="persistence-model-headers.xml"/>
    </xforms:submission>

    <xforms:instance id="fr-service-parameters">
        <parameters/>
    </xforms:instance>

    <!-- Calls a service to get the initial instance -->
    <xforms:submission id="fr-get-instance-from-service"
            method="get" separator="&amp;" ref="instance('fr-service-parameters')"
            resource="{instance('fr-uris-instance')/new-service-uri}"
            replace="instance" xxforms:instance="fr-form-instance"/>

    <xforms:instance id="fr-persistence-instance">
        <save xmlns="">
            <!-- Initial data status -->
            <initial-data-status>clean</initial-data-status>
            <!-- Whether form data is clean or dirty (i.e. saved or not saved) -->
            <data-status>clean</data-status>
            <!-- Whether an attempt to submit was ever done -->
            <save-attempted>false</save-attempted>
            <!-- Success or error message to display -->
            <message/>
            <!-- Error document returned -->
            <error/>
            <!-- Whether an error was received -->
            <is-error>false</is-error>
            <!-- Whether the last action that triggered the a fr-create-update-submission is a "submit" or a "save" -->
            <submit-or-save-or-send/>
            <!-- Flag to override data-safe -->
            <data-safe-override/>
            <!-- Whether data is safe -->
            <data-safe/>
        </save>
    </xforms:instance>

    <xforms:bind nodeset="instance('fr-persistence-instance')">
        <xforms:bind nodeset="data-safe" calculate="../data-status = 'clean' or ../data-safe-override = 'true'"/>
    </xforms:bind>

    <!-- Configuration for Saxon serialization -->
    <xforms:instance id="fr-xsl-output-instance">
        <xsl:output xmlns:xsl="http://www.w3.org/1999/XSL/Transform" method="xml" omit-xml-declaration="yes" indent="yes" saxon:indent-spaces="4"/>
    </xforms:instance>

    <xforms:instance id="fr-triggers-instance">
        <triggers xmlns="">
            <save/>
            <submit/>
            <discard/>
        </triggers>
    </xforms:instance>

    <xforms:instance id="fr-authentication-headers">
        <headers>
            <header name="username" value=""/>
            <header name="roles" value=""/>
        </headers>
    </xforms:instance>

    <xforms:bind nodeset="instance('fr-triggers-instance')">
        <xforms:bind nodeset="save" readonly="not(property('xxforms:noscript'))
            and (instance('fr-persistence-instance')/data-status = 'clean' or xxforms:instance('fr-form-valid-instance') = 'false')"/>
        <xforms:bind nodeset="submit" readonly="not(property('xxforms:noscript')) and xxforms:instance('fr-form-valid-instance') = 'false'"/>
    </xforms:bind>

    <!-- React to successful submission when saving/updating -->
    <xforms:action ev:event="xforms-submit-done" ev:target="fr-create-update-submission">
        <xforms:setvalue ref="instance('fr-persistence-instance')/message"
                         value="xxforms:instance('fr-fr-current-resources')/detail/messages/save-success"/>

        <!-- Show success message -->
        <xforms:toggle case="fr-message-success"/>

        <!-- HACK: Force this before cleaning the status because we do a setvalue just before calling the submission -->
        <xforms:recalculate/>
        <xforms:refresh/>

        <xforms:setvalue ref="instance('fr-persistence-instance')/data-status">clean</xforms:setvalue>

        <!-- If the document was saved because of a "submit", handle the rest of the submission process in dialog -->
        <xforms:action if="instance('fr-persistence-instance')/submit-or-save-or-send = 'submit'">
            <!-- Show the submission result dialog -->
            <xxforms:show dialog="fr-submission-result-dialog">
                <xxforms:context name="fr:content" select="instance('fr-create-update-submission-response')"/>
            </xxforms:show>
        </xforms:action>

        <!-- If the document was saved because of a "send", handle the rest of the submission process -->
        <xforms:action if="instance('fr-persistence-instance')/submit-or-save-or-send = 'send'">
            <!-- TODO: move this to separate model (fr-send-model or fr-workflow-model) -->

            <!-- Create PDF if requested -->
            <xforms:send if="xxforms:property(string-join(('oxf.fr.detail.send.pdf', $app, $form), '.'))
                                or xxforms:property(string-join(('oxf.fr.email.attach-pdf', $app, $form), '.'))
                                or xxforms:property(string-join(('oxf.fr.alfresco.send-pdf', $app, $form), '.'))" submission="fr-pdf-service-submission"/>

            <xforms:action if="instance('fr-persistence-instance')/is-error = 'false'">
                <!-- Send to Alfresco if requested -->
                <xforms:action if="xxforms:property(string-join(('oxf.fr.detail.send.alfresco', $app, $form), '.'))">

                    <!-- Form definition -->
                    <xxforms:variable name="html" select="instance('fr-source-form-instance')" as="element(xhtml:html)"/>

                    <!-- Pass metadata with current language, or first language if current language is not found -->
                    <xxforms:variable name="form-titles" select="$html/xhtml:head//xforms:instance[@id = 'fr-form-metadata']/*/title" as="xs:string"/>
                    <xxforms:variable name="form-descriptions" select="$html/xhtml:head//xforms:instance[@id = 'fr-form-metadata']/*/description" as="xs:string"/>
                    <xxforms:variable name="form-title" select="($form-titles[@xml:lang = xxforms:instance('fr-language-instance')], $form-titles[1])[1]" as="xs:string"/>
                    <xxforms:variable name="form-description" select="($form-descriptions[@xml:lang = xxforms:instance('fr-language-instance')], $form-descriptions[1])[1]" as="xs:string"/>

                    <!-- Send PDF data if requested -->
                    <xforms:action if="xxforms:property(string-join(('oxf.fr.alfresco.send-pdf', $app, $form), '.'))">
                        <!-- Get URI of PDF data -->
                        <xxforms:variable name="pdf-uri" select="pipeline:rewriteResourceURI(concat(xxforms:property('oxf.fr.appserver.uri'), instance('fr-workflow-confirmation-instance')), true())" as="xs:anyURI"/>

                        <!-- Send everything to Alfresco -->
                        <xforms:dispatch target="fr-alfresco-model" name="alfresco-send-document">
                            <xxforms:context name="fr:name" select="concat($form-title, ' (#', $document, ').pdf')"/>
{'fraction_non_alphanumeric': 0.16982067853877034, 'fraction_numerical': 0.0029137800096092747, 'mean_word_length': 2.4289206568528456, 'pattern_counts': {'":': 0, '<': 830, '<?xml version=': 2, '>': 830, 'https://': 0, 'lorem ipsum': 0, 'www.': 16, 'xml': 86}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 40, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5708182', 'n_tokens_mistral': 18222, 'n_tokens_neox': 17543, 'n_words': 3202}