[ignore] Fixing eXide: xcollection was removed.

svn path=/trunk/eXist/; revision=16161

(:
 :  eXide - web-based XQuery IDE
 :
 :  Copyright (C) 2011 Wolfgang Meier
 :
 :  This program is free software: you can redistribute it and/or modify
 :  it under the terms of the GNU General Public License as published by
 :  the Free Software Foundation, either version 3 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 General Public License for more details.
 :
 :  You should have received a copy of the GNU General Public License
 :  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 :)
xquery version "3.0";

import module namespace tmpl="http://exist-db.org/xquery/template" at "tmpl.xql";

(:~
    Edit the expath and repo app descriptors.
    Functions to read, update the descriptors and deploy an app.
:)
declare namespace deploy="http://exist-db.org/eXide/deploy";
declare namespace expath="http://expath.org/ns/pkg";
declare namespace repo="http://exist-db.org/xquery/repo";

declare variable $app-root := request:get-attribute("app-root");

declare variable $deploy:ANT_FILE :=
    <project default="xar" name="$$app$$">
        <property name="project.version" value="$$version$$"/>
        <property name="project.app" value="$$app$$"/>
        <property name="build.dir" value="build"/>
        <target name="xar">
            <mkdir dir="${{build.dir}}"/>
            <zip basedir="." destfile="${{build.dir}}/${{project.app}}-${{project.version}}.xar"
                excludes="${{build.dir}}/*"/>
        </target>
    </project>;

declare function deploy:select-option($value as xs:string, $current as xs:string?, $label as xs:string) {
    <option value="{$value}">
    { if (exists($current) and $value eq $current) then attribute selected { "selected" } else (), $label }
    </option>
};

declare function deploy:get-app-root($collection as xs:string) {
    if (doc(concat($collection, "/expath-pkg.xml"))) then
        $collection
    else if ($collection ne "/db") then
        let $parent := replace($collection, "^(.*)/[^/]+$", "$1")
        return
            deploy:get-app-root($parent)
    else
        ()
};

declare function deploy:store-expath($collection as xs:string?, $userData as xs:string*, $permissions as xs:int?) {
    let $descriptor :=
        <package xmlns="http://expath.org/ns/pkg"
            name="{request:get-parameter('name', ())}" abbrev="{request:get-parameter('abbrev', ())}"
            version="{request:get-parameter('version', ())}" spec="1.0">
            <title>{request:get-parameter("title", ())}</title>
        </package>
    return (
        xmldb:store($collection, "expath-pkg.xml", $descriptor, "text/xml"),
        xmldb:set-resource-permissions($collection, "expath-pkg.xml", $userData[1], $userData[2], $permissions)
    )
};

declare function deploy:repo-descriptor() {
    <meta xmlns="http://exist-db.org/xquery/repo">
        <description>
        {
            let $desc := request:get-parameter("description", ())
            return
                if ($desc) then $desc else request:get-parameter("title", ())
        }
        </description>
        {
            for $author in request:get-parameter("author", ())
            return
                <author>{$author}</author>
        }
        <website>{request:get-parameter("website", ())}</website>
        <status>{request:get-parameter("status", ())}</status>
        <license>GNU-LGPL</license>
        <copyright>true</copyright>
        <type>application</type>
        <target>{request:get-parameter("target", ())}</target>
        <prepare>{request:get-parameter("prepare", ())}</prepare>
        <finish>{request:get-parameter("finish", ())}</finish>
        {
            if (request:get-parameter("owner", ())) then
                <permissions user="{request:get-parameter('owner', ())}"
                    password="{request:get-parameter('password', ())}"
                    group="{request:get-parameter('group', ())}"
                    mode="{request:get-parameter('mode', ())}"/>
            else
                ()
        }
    </meta>
};

declare function deploy:store-repo($descriptor as element(), $collection as xs:string?, $userData as xs:string*, $permissions as xs:int?) {
    (
        xmldb:store($collection, "repo.xml", $descriptor, "text/xml"),
        xmldb:set-resource-permissions($collection, "repo.xml", $userData[1], $userData[2], $permissions)
    )
};

declare function deploy:mkcol-recursive($collection, $components, $userData as xs:string*, $permissions as xs:int?) {
    if (exists($components)) then
        let $newColl := concat($collection, "/", $components[1])
        return (
            xmldb:create-collection($collection, $components[1]),
            if (exists($userData)) then
                xmldb:set-collection-permissions($newColl, $userData[1], $userData[2], $permissions)
            else
                (),
            deploy:mkcol-recursive($newColl, subsequence($components, 2), $userData, $permissions)
        )
    else
        ()
};

declare function deploy:mkcol($path, $userData as xs:string*, $permissions as xs:int?) {
    let $path := if (starts-with($path, "/db/")) then substring-after($path, "/db/") else $path
    return
        deploy:mkcol-recursive("/db", tokenize($path, "/"), $userData, $permissions)
};

declare function deploy:create-collection($collection as xs:string, $userData as xs:string+, $permissions as xs:int) {
    let $target := collection($collection)
    return
        if ($target) then
            $target
        else
            deploy:mkcol($collection, $userData, $permissions)
};

declare function deploy:check-group($group as xs:string) {
    if (xmldb:group-exists($group)) then
        ()
    else
        xmldb:create-group($group)
};

declare function deploy:check-user($repoConf as element()) as xs:string+ {
    let $perms := $repoConf/repo:permissions
    let $user := if ($perms/@user) then $perms/@user/string() else xmldb:get-current-user()
    let $group := if ($perms/@group) then $perms/@group/string() else xmldb:get-user-groups($user)[1]
    let $create :=
        if (xmldb:exists-user($user)) then
            if (index-of(xmldb:get-user-groups($user), $group)) then
                ()
            else (
                deploy:check-group($group),
                xmldb:add-user-to-group($user, $group)
            )
        else (
            deploy:check-group($group),
            xmldb:create-user($user, $perms/@password, $group, ())
        )
    return
        ($user, $group)
};

declare function deploy:target-permissions($repoConf as element()) as xs:int {
    let $permissions := $repoConf/repo:permissions/@mode/string()
    return
        if ($permissions) then
            util:base-to-integer(xs:int($permissions), 8)
        else
            util:base-to-integer(0775, 8)
};

declare function deploy:set-execute-bit($resource as xs:string) {
    let $mode :=
        sm:get-permissions($resource)/sm:permission/@mode
    return
        replace($mode, "(..).(..).(..).", "$1x$2x$3x")
};

declare function deploy:copy-templates($target as xs:string, $source as xs:string, $userData as xs:string+, $permissions as xs:int) {
    let $null := deploy:mkcol($target, $userData, $permissions)
    return (
        for $resource in xmldb:get-child-resources($source)
        let $targetPath := xs:anyURI(concat($target, "/", $resource))
        return (
            xmldb:copy($source, $target, $resource),
            let $mime := xmldb:get-mime-type($targetPath)
            let $perms :=
                if ($mime eq "application/xquery") then
                    xmldb:string-to-permissions(deploy:set-execute-bit($targetPath))
                else $permissions
            return
                xmldb:set-resource-permissions($target, $resource, $userData[1], $userData[2], $perms)
        ),
        for $childColl in xmldb:get-child-collections($source)
        return
            deploy:copy-templates(concat($target, "/", $childColl), concat($source, "/", $childColl), $userData, $permissions)
    )
};

declare function deploy:store-templates-from-db($target as xs:string, $base as xs:string, $userData as xs:string+, $permissions as xs:int) {
    let $template := request:get-parameter("template", "basic")
    let $templateColl := concat($base, "/templates/", $template)
    return
        deploy:copy-templates($target, $templateColl, $userData, $permissions)
};

declare function deploy:chmod($collection as xs:string, $userData as xs:string+, $permissions as xs:int) {
    (
        xmldb:set-collection-permissions($collection, $userData[1], $userData[2], $permissions),
        for $resource in xmldb:get-child-resources($collection)
        let $path := concat($collection, "/", $resource)
        let $mime := xmldb:get-mime-type($path)
        let $perms :=
            if ($mime eq "application/xquery") then
                xmldb:string-to-permissions(deploy:set-execute-bit($path))
            else $permissions
        return
            xmldb:set-resource-permissions($collection, $resource, $userData[1], $userData[2], $perms),
        for $child in xmldb:get-child-collections($collection)
        return
            deploy:chmod(concat($collection, "/", $child), $userData, $permissions)
    )
};

declare function deploy:store-ant($target as xs:string, $permissions as xs:int) {
    let $abbrev := request:get-parameter("abbrev", "")
    let $version := request:get-parameter("version", "1.0")
    let $parameters :=
        <parameters>
            <param name="app" value="{$abbrev}"/>
            <param name="version" value="{$version}"/>
        </parameters>
    let $antXML := tmpl:expand-template($deploy:ANT_FILE, $parameters)
    return
        xmldb:store($target, "build.xml", $antXML)
};

declare function deploy:store-templates-from-fs($target as xs:string, $base as xs:string, $userData as xs:string+, $permissions as xs:int) {
    let $pathSep := util:system-property("file.separator")
    let $template := request:get-parameter("template", "basic")
    let $templatesDir := concat($base, $pathSep, "templates", $pathSep, $template)
    return (
        xmldb:store-files-from-pattern($target, $templatesDir, "**/*", (), true(), "**/.svn/**"),
        deploy:chmod($target, $userData, $permissions)
    )
};

declare function deploy:store-templates($target as xs:string, $userData as xs:string+, $permissions as xs:int) {
    let $base := substring-before(system:get-module-load-path(), "/modules")
    return
        if (starts-with($base, "xmldb:exist://")) then
            deploy:store-templates-from-db($target, $base, $userData, $permissions)
        else
            deploy:store-templates-from-fs($target, $base, $userData, $permissions)
};

declare function deploy:store($collection as xs:string?, $expathConf as element()?) {
    let $repoConf := deploy:repo-descriptor()
    let $permissions := deploy:target-permissions($repoConf)
    let $userData := deploy:check-user($repoConf)
    return
        if (not($collection)) then
            error(QName("http://exist-db.org/xquery/sandbox", "missing-collection"), "collection parameter missing")
        else
            let $create := deploy:create-collection($collection, $userData, $permissions)
            let $null := (
                deploy:store-expath($collection, $userData, $permissions),
                deploy:store-repo($repoConf, $collection, $userData, $permissions),
                if (empty($expathConf)) then (
                    deploy:store-templates($collection, $userData, $permissions),
                    deploy:store-ant($collection, $permissions)
                ) else
                    ()
            )
            return
                <ok/>
};

declare function deploy:view($collection as xs:string?, $expathConf as element()?, $repoConf as element()?) {
    let $null := util:declare-option("exist:serialize", "method=html media-type=text/html")
    return
        <form>
            {
                if ($collection) then (
                    <input type="hidden" name="collection" value="{$collection}"/>,

App collection: {$collection}

                ) else
                    ()
            }
            <fieldset>
                <legend>Application Properties</legend>

                    {
                        if (empty($repoConf)) then

The template to use for generating the basic app structure.

                                <select name="template">
                                    <option value="templating" selected="selected">HTML Templates</option>
                                    <option value="basic">Basic</option>
                                </select>
                                Template:

                        else
                            ()
                    }

The collection where the app will be installed. Should normally be different from
                        the source collection.

                        <input type="text" name="target" value="{$repoConf/repo:target}"
                            placeholder="/db/yourapp" size="40" required="required"/>
                        Target collection:

The name of the package. This must be a URI.

                        <input type="url" name="name" placeholder="http://exist-db.org/apps/yourapp" required="required"
                            value="{if ($expathConf) then $expathConf/@name else ''}" size="40"/>
                        Name:

A short name for the app. This will be the name of the collection into which
                        the app is installed.

                        <input type="text" name="abbrev" placeholder="Short name"
                            value="{$expathConf/@abbrev}" size="25" required="required"/>
                        Abbreviation:

A descriptive title for the application.

                        <input type="text" name="title" value="{$expathConf/expath:title}" size="40" required="required"/>
                        Title:

                        <input type="text" name="version" value="{if ($expathConf) then $expathConf/@version else '0.1'}"
                            size="10" required="required"/>
                        Version:

                    {
                        let $status := $repoConf/repo:status/string()
                        return
                            <select name="status">
                                { deploy:select-option("alpha", $status, "Alpha") }
                                { deploy:select-option("beta", $status, "Beta") }
                                { deploy:select-option("stable", $status, "Stable") }
                            </select>
                    }
                        Status:

Optional: name of an XQuery script which will be run before the
                        application is installed. Use this to create users, index configurations and the like.

                        <input type="text" name="prepare" value="{if ($repoConf) then $repoConf/repo:prepare else 'pre-install.xql'}"
                            placeholder="pre-install.xql" size="40"/>
                        Pre-install XQuery:

Optional: name of an XQuery script which will be run after the
                        application was installed.

                        <input type="text" name="finish" value="{$repoConf/repo:finish}" size="40"
                            placeholder="post-install.xql"/>
                        Post-install XQuery:

            </fieldset>
            <fieldset>
                <legend>Description</legend>

The author(s) of the application.

                        Author:

                        {
                            if (empty($repoConf)) then

<input type="text" name="author" size="25"/>

                            else
                                for $author in $repoConf/repo:author
                                return

<input type="text" name="author" value="{$author}" size="25"/>

                        }

<button id="author-add-trigger">Add</button><button id="author-remove-trigger">Remove</button>

A longer description of the application.

                        <textarea name="description" cols="40">{$repoConf/repo:description/text()}</textarea>
                        Description:

Link to the author's website.

                        <input type="url" name="website" value="{$repoConf/repo:website}" size="40"/>
                        Website:

            </fieldset>
            <fieldset>
                <legend>Default Permissions</legend>

Default permissions applied to all resources uploaded into the database. To set
                non-default permissions on particular resources, use a post-install script.

                {
                    let $owner := $repoConf/repo:permissions/@user
                    let $password := $repoConf/repo:permissions/@password
                    let $group := $repoConf/repo:permissions/@group
                    let $mode := $repoConf/repo:permissions/@mode
                    return

                                <input type="text" name="owner" value="{$owner}" size="20"/>
                                Owner:

                                <input type="password" name="password" value="{$password}" size="20"/>
                                Password:

                                <input type="text" name="group" value="{$group}" size="20"/>
                                Group:

                                <input type="text" name="mode" value="{if ($mode) then $mode else '0744'}" size="4"/>
                                Mode:

                }
            </fieldset>
        </form>
};

declare function deploy:package($collection as xs:string, $expathConf as element()) {
    let $name := concat($expathConf/@abbrev, "-", $expathConf/@version, ".xar")
    let $xar := compression:zip(xs:anyURI($collection), true(), $collection)
    let $mkcol := deploy:mkcol("/db/system/repo", (), ())
    return
        xmldb:store("/db/system/repo", $name, $xar, "application/zip")
};

declare function deploy:download($collection as xs:string, $expathConf as element()) {
    let $name := concat($expathConf/@abbrev, "-", $expathConf/@version, ".xar")
    let $xar := compression:zip(xs:anyURI($collection), true(), $collection)
    return (
        response:set-header("Content-Disposition", concat("attachment; filename=", $name)),
        response:stream-binary($xar, "application/zip", $name)
    )
};

declare function deploy:deploy($collection as xs:string, $target as xs:string, $expathConf as element(),
    $repoConf as element()) {
    let $null := util:declare-option("exist:serialize", "method=json media-type=application/json")
    let $port := request:get-server-port()
    let $pkg := deploy:package($collection, $expathConf)
    let $url := concat('http://localhost:',$port,'/exist/rest',$pkg)
    let $null := (
        repo:remove($expathConf/@name),
        repo:install($url),
        repo:deploy($expathConf/@name, $target)
    )
    return
        <info>{substring-after($target, "/db/")}</info>
};

declare function deploy:get-info-from-descriptor($collection as xs:string) {
    let $expathConf := doc(concat($collection, "/expath-pkg.xml"))/expath:package
    let $repoConf := doc(concat($collection, "/repo.xml"))/repo:meta
    let $user := xmldb:get-current-user()
    let $auth := if ($user) then xmldb:is-admin-user($user) else false()
    return
        <info xmlns:json="http://json.org" root="{$collection}" abbrev="{$expathConf/@abbrev}">
            <target>{$repoConf/repo:target/string()}</target>
            <deployed>{$repoConf/repo:deployed/string()}</deployed>
            <isAdmin json:literal="true">{$auth}</isAdmin>
        </info>
};

declare function deploy:get-info($collection as xs:string) {
    let $null := util:declare-option("exist:serialize", "method=json media-type=application/json")
    let $root := deploy:get-app-root($collection)
    return
        if ($root) then
            deploy:get-info-from-descriptor($root)
        else
            <info/>
};

let $target := request:get-parameter("target", ())
let $collectionParam := request:get-parameter("collection", ())
let $collection :=
    if ($collectionParam) then
        let $root := deploy:get-app-root($collectionParam)
        return
            if ($root) then $root else $collectionParam
    else
        $target
let $info := request:get-parameter("info", ())
let $deploy := request:get-parameter("deploy", ())
let $download := request:get-parameter("download", ())
let $expathConf := if ($collection) then xmldb:xcollection($collection)/expath:package else ()
let $repoConf := if ($collection) then xmldb:xcollection($collection)/repo:meta else ()
let $abbrev := request:get-parameter("abbrev", ())
return
    try {
        if ($download) then
            deploy:download($collection, $expathConf)
        else if ($info) then
            deploy:get-info($info)
        else if ($deploy) then
            deploy:deploy($collection, $target, $expathConf, $repoConf)
        else if ($abbrev) then
            deploy:store($collection, $expathConf)
        else
            deploy:view($collection, $expathConf, $repoConf)
    } catch exerr:EXXQDY0003 {
        response:set-status-code(403),
        You don't have permissions to access or write the application archive.
            Please correct the location or log in as a different user.
    } catch exerr:EXREPOINSTALL001 {
        response:set-status-code(404),

Failed to install application.

    }

(:
 :  eXide - web-based XQuery IDE
 :
 :  Copyright (C) 2011 Wolfgang Meier
 :
 :  This program is free software: you can redistribute it and/or modify
 :  it under the terms of the GNU General Public License as published by
 :  the Free Software Foundation, either version 3 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 General Public License for more details.
 :
 :  You should have received a copy of the GNU General Public License
 :  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 :)
xquery version "3.0";

import module namespace tmpl="http://exist-db.org/xquery/template" at "tmpl.xql";

(:~
    Edit the expath and repo app descriptors.
    Functions to read, update the descriptors and deploy an app.
:)
declare namespace deploy="http://exist-db.org/eXide/deploy";
declare namespace expath="http://expath.org/ns/pkg";
declare namespace repo="http://exist-db.org/xquery/repo";

declare variable $app-root := request:get-attribute("app-root");

declare variable $deploy:ANT_FILE :=
    <project default="xar" name="$$app$$">
        <property name="project.version" value="$$version$$"/>
        <property name="project.app" value="$$app$$"/>
        <property name="build.dir" value="build"/>
        <target name="xar">
            <mkdir dir="${{build.dir}}"/>
            <zip basedir="." destfile="${{build.dir}}/${{project.app}}-${{project.version}}.xar"
                excludes="${{build.dir}}/*"/>
        </target>
    </project>;

declare function deploy:select-option($value as xs:string, $current as xs:string?, $label as xs:string) {
    <option value="{$value}">
    { if (exists($current) and $value eq $current) then attribute selected { "selected" } else (), $label }
    </option>
};

declare function deploy:get-app-root($collection as xs:string) {
    if (doc(concat($collection, "/expath-pkg.xml"))) then
        $collection
    else if ($collection ne "/db") then
        let $parent := replace($collection, "^(.*)/[^/]+$", "$1")
        return
            deploy:get-app-root($parent)
    else
        ()
};

declare function deploy:store-expath($collection as xs:string?, $userData as xs:string*, $permissions as xs:int?) {
    let $descriptor :=
        <package xmlns="http://expath.org/ns/pkg"
            name="{request:get-parameter('name', ())}" abbrev="{request:get-parameter('abbrev', ())}"
            version="{request:get-parameter('version', ())}" spec="1.0">
            <title>{request:get-parameter("title", ())}</title>
        </package>
    return (
        xmldb:store($collection, "expath-pkg.xml", $descriptor, "text/xml"),
        xmldb:set-resource-permissions($collection, "expath-pkg.xml", $userData[1], $userData[2], $permissions)
    )
};

declare function deploy:repo-descriptor() {
    <meta xmlns="http://exist-db.org/xquery/repo">
        <description>
        {
            let $desc := request:get-parameter("description", ())
            return
                if ($desc) then $desc else request:get-parameter("title", ())
        }
        </description>
        {
            for $author in request:get-parameter("author", ())
            return
                <author>{$author}</author>
        }
        <website>{request:get-parameter("website", ())}</website>
        <status>{request:get-parameter("status", ())}</status>
        <license>GNU-LGPL</license>
        <copyright>true</copyright>
        <type>application</type>
        <target>{request:get-parameter("target", ())}</target>
        <prepare>{request:get-parameter("prepare", ())}</prepare>
        <finish>{request:get-parameter("finish", ())}</finish>
        {
            if (request:get-parameter("owner", ())) then
                <permissions user="{request:get-parameter('owner', ())}"
                    password="{request:get-parameter('password', ())}"
                    group="{request:get-parameter('group', ())}"
                    mode="{request:get-parameter('mode', ())}"/>
            else
                ()
        }
    </meta>
};

declare function deploy:store-repo($descriptor as element(), $collection as xs:string?, $userData as xs:string*, $permissions as xs:int?) {
    (
        xmldb:store($collection, "repo.xml", $descriptor, "text/xml"),
        xmldb:set-resource-permissions($collection, "repo.xml", $userData[1], $userData[2], $permissions)
    )
};

declare function deploy:mkcol-recursive($collection, $components, $userData as xs:string*, $permissions as xs:int?) {
    if (exists($components)) then
        let $newColl := concat($collection, "/", $components[1])
        return (
            xmldb:create-collection($collection, $components[1]),
            if (exists($userData)) then
                xmldb:set-collection-permissions($newColl, $userData[1], $userData[2], $permissions)
            else
                (),
            deploy:mkcol-recursive($newColl, subsequence($components, 2), $userData, $permissions)
        )
    else
        ()
};

declare function deploy:mkcol($path, $userData as xs:string*, $permissions as xs:int?) {
    let $path := if (starts-with($path, "/db/")) then substring-after($path, "/db/") else $path
    return
        deploy:mkcol-recursive("/db", tokenize($path, "/"), $userData, $permissions)
};

declare function deploy:create-collection($collection as xs:string, $userData as xs:string+, $permissions as xs:int) {
    let $target := collection($collection)
    return
        if ($target) then
            $target
        else
            deploy:mkcol($collection, $userData, $permissions)
};

declare function deploy:check-group($group as xs:string) {
    if (xmldb:group-exists($group)) then
        ()
    else
        xmldb:create-group($group)
};

declare function deploy:check-user($repoConf as element()) as xs:string+ {
    let $perms := $repoConf/repo:permissions
    let $user := if ($perms/@user) then $perms/@user/string() else xmldb:get-current-user()
    let $group := if ($perms/@group) then $perms/@group/string() else xmldb:get-user-groups($user)[1]
    let $create :=
        if (xmldb:exists-user($user)) then
            if (index-of(xmldb:get-user-groups($user), $group)) then
                ()
            else (
                deploy:check-group($group),
                xmldb:add-user-to-group($user, $group)
            )
        else (
            deploy:check-group($group),
            xmldb:create-user($user, $perms/@password, $group, ())
        )
    return
        ($user, $group)
};

declare function deploy:target-permissions($repoConf as element()) as xs:int {
    let $permissions := $repoConf/repo:permissions/@mode/string()
    return
        if ($permissions) then
            util:base-to-integer(xs:int($permissions), 8)
        else
            util:base-to-integer(0775, 8)
};

declare function deploy:set-execute-bit($resource as xs:string) {
    let $mode :=
        sm:get-permissions($resource)/sm:permission/@mode
    return
        replace($mode, "(..).(..).(..).", "$1x$2x$3x")
};

declare function deploy:copy-templates($target as xs:string, $source as xs:string, $userData as xs:string+, $permissions as xs:int) {
    let $null := deploy:mkcol($target, $userData, $permissions)
    return (
        for $resource in xmldb:get-child-resources($source)
        let $targetPath := xs:anyURI(concat($target, "/", $resource))
        return (
            xmldb:copy($source, $target, $resource),
            let $mime := xmldb:get-mime-type($targetPath)
            let $perms :=
                if ($mime eq "application/xquery") then
                    xmldb:string-to-permissions(deploy:set-execute-bit($targetPath))
                else $permissions
            return
                xmldb:set-resource-permissions($target, $resource, $userData[1], $userData[2], $perms)
        ),
        for $childColl in xmldb:get-child-collections($source)
        return
            deploy:copy-templates(concat($target, "/", $childColl), concat($source, "/", $childColl), $userData, $permissions)
    )
};

declare function deploy:store-templates-from-db($target as xs:string, $base as xs:string, $userData as xs:string+, $permissions as xs:int) {
    let $template := request:get-parameter("template", "basic")
    let $templateColl := concat($base, "/templates/", $template)
    return
        deploy:copy-templates($target, $templateColl, $userData, $permissions)
};

declare function deploy:chmod($collection as xs:string, $userData as xs:string+, $permissions as xs:int) {
    (
        xmldb:set-collection-permissions($collection, $userData[1], $userData[2], $permissions),
        for $resource in xmldb:get-child-resources($collection)
        let $path := concat($collection, "/", $resource)
        let $mime := xmldb:get-mime-type($path)
        let $perms :=
            if ($mime eq "application/xquery") then
                xmldb:string-to-permissions(deploy:set-execute-bit($path))
            else $permissions
        return
            xmldb:set-resource-permissions($collection, $resource, $userData[1], $userData[2], $perms),
        for $child in xmldb:get-child-collections($collection)
        return
            deploy:chmod(concat($collection, "/", $child), $userData, $permissions)
    )
};

declare function deploy:store-ant($target as xs:string, $permissions as xs:int) {
    let $abbrev := request:get-parameter("abbrev", "")
    let $version := request:get-parameter("version", "1.0")
    let $parameters :=
        <parameters>
            <param name="app" value="{$abbrev}"/>
            <param name="version" value="{$version}"/>
        </parameters>
    let $antXML := tmpl:expand-template($deploy:ANT_FILE, $parameters)
    return
        xmldb:store($target, "build.xml", $antXML)
};

declare function deploy:store-templates-from-fs($target as xs:string, $base as xs:string, $userData as xs:string+, $permissions as xs:int) {
    let $pathSep := util:system-property("file.separator")
    let $template := request:get-parameter("template", "basic")
    let $templatesDir := concat($base, $pathSep, "templates", $pathSep, $template)
    return (
        xmldb:store-files-from-pattern($target, $templatesDir, "**/*", (), true(), "**/.svn/**"),
        deploy:chmod($target, $userData, $permissions)
    )
};

declare function deploy:store-templates($target as xs:string, $userData as xs:string+, $permissions as xs:int) {
    let $base := substring-before(system:get-module-load-path(), "/modules")
    return
        if (starts-with($base, "xmldb:exist://")) then
            deploy:store-templates-from-db($target, $base, $userData, $permissions)
        else
            deploy:store-templates-from-fs($target, $base, $userData, $permissions)
};

declare function deploy:store($collection as xs:string?, $expathConf as element()?) {
    let $repoConf := deploy:repo-descriptor()
    let $permissions := deploy:target-permissions($repoConf)
    let $userData := deploy:check-user($repoConf)
    return
        if (not($collection)) then
            error(QName("http://exist-db.org/xquery/sandbox", "missing-collection"), "collection parameter missing")
        else
            let $create := deploy:create-collection($collection, $userData, $permissions)
            let $null := (
                deploy:store-expath($collection, $userData, $permissions),
                deploy:store-repo($repoConf, $collection, $userData, $permissions),
                if (empty($expathConf)) then (
                    deploy:store-templates($collection, $userData, $permissions),
                    deploy:store-ant($collection, $permissions)
                ) else
                    ()
            )
            return
                <ok/>
};

declare function deploy:view($collection as xs:string?, $expathConf as element()?, $repoConf as element()?) {
    let $null := util:declare-option("exist:serialize", "method=html media-type=text/html")
    return
        <form>
            {
                if ($collection) then (
                    <input type="hidden" name="collection" value="{$collection}"/>,

App collection: {$collection}

                ) else
                    ()
            }
            <fieldset>
                <legend>Application Properties</legend>

                    {
                        if (empty($repoConf)) then

The template to use for generating the basic app structure.

                                <select name="template">
                                    <option value="templating" selected="selected">HTML Templates</option>
                                    <option value="basic">Basic</option>
                                </select>
                                Template:

                        else
                            ()
                    }

The collection where the app will be installed. Should normally be different from
                        the source collection.

                        <input type="text" name="target" value="{$repoConf/repo:target}"
                            placeholder="/db/yourapp" size="40" required="required"/>
                        Target collection:

The name of the package. This must be a URI.

                        <input type="url" name="name" placeholder="http://exist-db.org/apps/yourapp" required="required"
                            value="{if ($expathConf) then $expathConf/@name else ''}" size="40"/>
                        Name:

A short name for the app. This will be the name of the collection into which
                        the app is installed.

                        <input type="text" name="abbrev" placeholder="Short name"
                            value="{$expathConf/@abbrev}" size="25" required="required"/>
                        Abbreviation:

A descriptive title for the application.

                        <input type="text" name="title" value="{$expathConf/expath:title}" size="40" required="required"/>
                        Title:

                        <input type="text" name="version" value="{if ($expathConf) then $expathConf/@version else '0.1'}"
                            size="10" required="required"/>
                        Version:

                    {
                        let $status := $repoConf/repo:status/string()
                        return
                            <select name="status">
                                { deploy:select-option("alpha", $status, "Alpha") }
                                { deploy:select-option("beta", $status, "Beta") }
                                { deploy:select-option("stable", $status, "Stable") }
                            </select>
                    }
                        Status:

Optional: name of an XQuery script which will be run before the
                        application is installed. Use this to create users, index configurations and the like.

                        <input type="text" name="prepare" value="{if ($repoConf) then $repoConf/repo:prepare else 'pre-install.xql'}"
                            placeholder="pre-install.xql" size="40"/>
                        Pre-install XQuery:

Optional: name of an XQuery script which will be run after the
                        application was installed.

                        <input type="text" name="finish" value="{$repoConf/repo:finish}" size="40"
                            placeholder="post-install.xql"/>
                        Post-install XQuery:

            </fieldset>
            <fieldset>
                <legend>Description</legend>

The author(s) of the application.

                        Author:

                        {
                            if (empty($repoConf)) then

<input type="text" name="author" size="25"/>

                            else
                                for $author in $repoConf/repo:author
                                return

<input type="text" name="author" value="{$author}" size="25"/>

                        }

<button id="author-add-trigger">Add</button><button id="author-remove-trigger">Remove</button>

A longer description of the application.

                        <textarea name="description" cols="40">{$repoConf/repo:description/text()}</textarea>
                        Description:

Link to the author's website.

                        <input type="url" name="website" value="{$repoConf/repo:website}" size="40"/>
                        Website:

            </fieldset>
            <fieldset>
                <legend>Default Permissions</legend>

Default permissions applied to all resources uploaded into the database. To set
                non-default permissions on particular resources, use a post-install script.

                {
                    let $owner := $repoConf/repo:permissions/@user
                    let $password := $repoConf/repo:permissions/@password
                    let $group := $repoConf/repo:permissions/@group
                    let $mode := $repoConf/repo:permissions/@mode
                    return

                                <input type="text" name="owner" value="{$owner}" size="20"/>
                                Owner:

                                <input type="password" name="password" value="{$password}" size="20"/>
                                Password:

                                <input type="text" name="group" value="{$group}" size="20"/>
                                Group:

                                <input type="text" name="mode" value="{if ($mode) then $mode else '0744'}" size="4"/>
                                Mode:

                }
            </fieldset>
        </form>
};

declare function deploy:package($collection as xs:string, $expathConf as element()) {
    let $name := concat($expathConf/@abbrev, "-", $expathConf/@version, ".xar")
    let $xar := compression:zip(xs:anyURI($collection), true(), $collection)
    let $mkcol := deploy:mkcol("/db/system/repo", (), ())
    return
        xmldb:store("/db/system/repo", $name, $xar, "application/zip")
};

declare function deploy:download($collection as xs:string, $expathConf as element()) {
    let $name := concat($expathConf/@abbrev, "-", $expathConf/@version, ".xar")
    let $xar := compression:zip(xs:anyURI($collection), true(), $collection)
    return (
        response:set-header("Content-Disposition", concat("attachment; filename=", $name)),
        response:stream-binary($xar, "application/zip", $name)
    )
};

declare function deploy:deploy($collection as xs:string, $target as xs:string, $expathConf as element(),
    $repoConf as element()) {
    let $null := util:declare-option("exist:serialize", "method=json media-type=application/json")
    let $port := request:get-server-port()
    let $pkg := deploy:package($collection, $expathConf)
    let $url := concat('http://localhost:',$port,'/exist/rest',$pkg)
    let $null := (
        repo:remove($expathConf/@name),
        repo:install($url),
        repo:deploy($expathConf/@name, $target)
    )
    return
        <info>{substring-after($target, "/db/")}</info>
};

declare function deploy:get-info-from-descriptor($collection as xs:string) {
    let $expathConf := doc(concat($collection, "/expath-pkg.xml"))/expath:package
    let $repoConf := doc(concat($collection, "/repo.xml"))/repo:meta
    let $user := xmldb:get-current-user()
    let $auth := if ($user) then xmldb:is-admin-user($user) else false()
    return
        <info xmlns:json="http://json.org" root="{$collection}" abbrev="{$expathConf/@abbrev}">
            <target>{$repoConf/repo:target/string()}</target>
            <deployed>{$repoConf/repo:deployed/string()}</deployed>
            <isAdmin json:literal="true">{$auth}</isAdmin>
        </info>
};

declare function deploy:get-info($collection as xs:string) {
    let $null := util:declare-option("exist:serialize", "method=json media-type=application/json")
    let $root := deploy:get-app-root($collection)
    return
        if ($root) then
            deploy:get-info-from-descriptor($root)
        else
            <info/>
};

let $target := request:get-parameter("target", ())
let $collectionParam := request:get-parameter("collection", ())
let $collection :=
    if ($collectionParam) then
        let $root := deploy:get-app-root($collectionParam)
        return
            if ($root) then $root else $collectionParam
    else
        $target
let $info := request:get-parameter("info", ())
let $deploy := request:get-parameter("deploy", ())
let $download := request:get-parameter("download", ())
let $expathConf := if ($collection) then xcollection($collection)/expath:package else ()
let $repoConf := if ($collection) then xcollection($collection)/repo:meta else ()
let $abbrev := request:get-parameter("abbrev", ())
return
    try {
        if ($download) then
            deploy:download($collection, $expathConf)
        else if ($info) then
            deploy:get-info($info)
        else if ($deploy) then
            deploy:deploy($collection, $target, $expathConf, $repoConf)
        else if ($abbrev) then
            deploy:store($collection, $expathConf)
        else
            deploy:view($collection, $expathConf, $repoConf)
    } catch exerr:EXXQDY0003 {
        response:set-status-code(403),
        You don't have permissions to access or write the application archive.
            Please correct the location or log in as a different user.
    } catch exerr:EXREPOINSTALL001 {
        response:set-status-code(404),

Failed to install application.

    }


Fix in reporting.

Fix in reporting.

(:
 : Copyright 2006-2011 The FLWOR Foundation.
 :
 : 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.
 :)

(:~
 : Zorba FOTS driver reporting
 : @author Sorin Nasoi
 :)

module namespace reporting =
  "http://www.zorba-xquery.com/fots-driver/reporting";

import module namespace file =
  "http://expath.org/ns/file";

import module namespace driver =
  "http://www.zorba-xquery.com/fots-driver" at "fots-driver.xq";
import module namespace util =
  "http://www.zorba-xquery.com/fots-driver/util" at "util.xq";
import module namespace fots-err =
  "http://www.zorba-xquery.com/fots-driver/errors" at "errors.xq";
import module namespace functx =
  "http://www.functx.com/";

declare namespace err =
  "http://www.w3.org/2005/xqt-errors";
declare namespace fots =
  "http://www.w3.org/2010/09/qt-fots-catalog";
declare namespace results =
  "http://www.w3.org/2012/08/qt-fots-results";

declare default element namespace
  "http://www.w3.org/2012/08/qt-fots-results";

declare namespace ann =
  "http://www.zorba-xquery.com/annotations";

declare namespace op = "http://www.zorba-xquery.com/options/features";
declare namespace f = "http://www.zorba-xquery.com/features";
declare option op:disable "f:trace";

(:~
 : Loops through the test-sets, executes them and reports results.
 : @param $FOTSCatalogFilePath path to the FOTS catalog file.
 : @param $FOTSZorbaManifestPath path to the FOTS Zorba manifest file.
 : @param $exceptedTestCases lists of test cases that are not run( empty
 : sequence means all test cases will be run).
 : @param $exceptedTestSets lists of test sets that are not run(empty sequence
 : means all test sets will be run).
 : @return a report of tests that were executed.
 :)
declare %ann:sequential function reporting:run-and-report(
  $FOTSCatalogFilePath    as xs:string,
  $FOTSZorbaManifestPath  as xs:string,
  $exceptedTestCases      as xs:string*,
  $exceptedTestSets       as xs:string*
) as document-node()
{
  try
  {
    {
      variable $FOTSCatalog := doc(trace(resolve-uri($FOTSCatalogFilePath),
                                  "Path to FOTS catalog.xml set to: "));

      variable $catalogBaseURI := resolve-uri(util:parent-folder($FOTSCatalogFilePath));

      variable $FOTSZorbaManifest := doc(trace(resolve-uri($FOTSZorbaManifestPath),
                                        "Path to FOTSZorbaManifest set to:"));

      variable $results := driver:run-fots($FOTSCatalogFilePath,
                                           $FOTSZorbaManifestPath,
                                           (),
                                           $exceptedTestSets,
                                           (),
                                           $exceptedTestCases,
                                           '',
                                           (),
                                           fn:false(),
                                           '',
                                           'run-test-sets');

      file:write("results.xml",
                 $results,
                 $util:writeXML);

      reporting:W3C-reporting($results,
                              $FOTSZorbaManifestPath)
    }
  }
  catch *
  {
    error($err:code,
          $err:description,
          concat("
Please make sure the passed 'fotsPath' points to the ",
                 "exact location of the FOTS catalog.xml:
",
                 resolve-uri($FOTSCatalogFilePath),
                 "
and that the passed 'fotsZorbaManifestPath' points to",
                 " a file in the same folder as cli.xq:
",
                 resolve-uri($FOTSZorbaManifestPath)))
  }
};

(:~
 : Loops through the test sets, executes them and reports results.
 : @param $FOTSZorbaManifestPath path to the FOTS Zorba manifest file.
 : @param $resultsFilePath path to the FOTS results file.
 : @return The W3C conformance submission file.
 :)
declare %ann:sequential function reporting:report(
  $FOTSZorbaManifestPath  as xs:string,
  $resultsFilePath        as xs:string
) as document-node()
{
  try
  {
    {
      reporting:W3C-reporting(parse-xml(file:read-text($resultsFilePath))/fots:test-cases,
                              $FOTSZorbaManifestPath)
    }
  }
  catch *
  {
    error($err:code, $err:description)
  }
};

(:~
 : Format the W3C conformance report.
 : @param $results FOTS results file.
 : @param $FOTSZorbaManifestPath  path to the FOTS Zorba manifest file.
 : @return The W3C conformance submission file.
 :)
declare %ann:sequential function reporting:W3C-reporting(
  $results                as element(fots:test-cases)?,
  $FOTSZorbaManifestPath  as xs:string
) as document-node()
{
  try
  {
    {
      if (not(file:is-file(resolve-uri($FOTSZorbaManifestPath))))
      then
      {
        error($fots-err:errNA,
              "The 'FOTSZorbaManifest.xml' was not found.");
      }
      else ();

      variable $FOTSZorbaManifest := parse-xml(file:read-text(resolve-uri($FOTSZorbaManifestPath)));

      variable $CLIBaseURI := resolve-uri(util:parent-folder($FOTSZorbaManifestPath));

      variable $W3CTemplatePath := resolve-uri("W3C_submission_template.xml", $CLIBaseURI);

      if (not(file:is-file($W3CTemplatePath)))
      then
      {
        error($fots-err:errNA,
              "'W3C_submission_template.xml' file was not found.");
      }
      else ();

      variable $W3CTemplate := parse-xml(file:read-text($W3CTemplatePath));

      (: add dependecies:)
     (insert nodes
      for $dependency in $FOTSZorbaManifest/fots:test-suite-result/fots:dependency
      return <dependency type="{$dependency/@type}"
                         value="{$dependency/@value}"
                         satisfied="{$dependency/@satisfied}"/>
      as last into $W3CTemplate/results:test-suite-result/results:product,

      (: add test set results:)
      insert nodes
      for $testSet in $results/fots:test-set
      return
      <test-set name="{$testSet/@name}">
        {
          for $testCase in $testSet/fots:test-case
          return
          if(exists($testCase/@comment))
          then
            <test-case name="{$testCase/@name}"
                       result="{$testCase/@result}"
                       comment="{$testCase/@comment}" />
          else
            <test-case name="{$testCase/@name}"
                       result="{$testCase/@result}" />
        }
      </test-set>
      as last into $W3CTemplate/results:test-suite-result);

      $W3CTemplate
    }
  }
  catch *
  {
    error($err:code,
          $err:description,
          concat("
Please make sure there is a 'W3C_submission_template.xml'",
                 " file in the same folder as cli.xq"))
  }
};

(:~
 : Loops through the test-sets and creates statistics.
 : @param $FOTSCatalogFilePath  Path to the FOTS catalog file.
 : @param $failures Path to the results fo the FOTS.
 : @return a report of tests run.
 :)
declare %ann:nondeterministic function reporting:do-reporting(
  $FOTSCatalogFilePath  as xs:string,
  $resultsFilePath      as xs:string
) as element(fots:report)
{
try
{
  {
    variable $FOTSCatalog := doc(trace(resolve-uri($FOTSCatalogFilePath),
                                "Path to FOTS catalog.xml set to: "));

    variable $catalogBaseURI := resolve-uri(util:parent-folder($FOTSCatalogFilePath));

    variable $results := parse-xml(file:read-text($resultsFilePath));

  <fots:report>
  {
    let $totalNoTests := count($results//fots:test-set//fots:test-case),
        $totalPass := sum(for $testSet in $results//fots:test-set
                          return count($testSet//fots:test-case[@result ='pass'])),
        $totalFail := sum(for $testSet in $results//fots:test-set
                          return count($testSet//fots:test-case[@result ='fail'])),
        $totalNotApplicable := sum(for $testSet in $results//fots:test-set
                                   return count($testSet//fots:test-case[@result ='n/a'])),
        $totalNotRun := sum(for $testSet in $results//fots:test-set
                            return count($testSet//fots:test-case[@result ='notRun']))
    return
    <fots:brief totalTests="{$totalNoTests}"
                totalPass="{$totalPass}"
                totalFail="{$totalFail}"
                totalNotApplicable="{$totalNotApplicable}"
                totalNotRun="{$totalNotRun}"/>
  }
  {
    for $testSetFile in $FOTSCatalog//fots:test-set
    let $testSetURI := resolve-uri($testSetFile/@file,
                                   $catalogBaseURI),
        $testSetDoc := doc($testSetURI),
        $testSetName := data($testSetDoc/fots:test-set/@name),
        $totalNoTestCases := count($testSetDoc//fots:test-case),
        $totalFailures := for $testCase in $results//fots:test-set[@name = $testSetName]//fots:test-case[@result ="fail"]
                          return $testCase,
        $percent := round((1 - (count($totalFailures) div $totalNoTestCases))*100,2),
        $executionTime := sum(for $testCase in $results//fots:test-set[@name = $testSetName]//fots:test-case
                              return xs:dayTimeDuration($testCase/@executionTime))
    where count($totalFailures) gt 0
    order by count($totalFailures) descending
    return
    <fots:test-set  name="{$testSetName}"
                    noFailures="{count($totalFailures)}"
                    noTestCases="{$totalNoTestCases}"
                    percent="{$percent}"
                  failedTestNames="{string-join(for $failure in $totalFailures
                                                order by data($failure/@name)
                                                return data($failure/@name)
                                              ,",")}">
    </fots:test-set>
   }
  </fots:report>

  }
}
catch *
{
  error($err:code,
        $err:description,
        concat("
Please make sure the passed 'fotsPath' points to the ",
               "exact location of the FOTS catalog.xml:
",
               resolve-uri($FOTSCatalogFilePath)))
}
};

(:~
 : Loops through the results and creates ExpectedFailures.xml.
 : @param $pathResults path to the FOTS results.
 : @return ExpectedFailures.xml.
 :)
declare %ann:nondeterministic function reporting:generate-expected-failures(
  $pathResults  as xs:string
)
{
  try
  {
    {
      if (not(file:is-file($pathResults)))
      then
      {
        error($fots-err:errNA,
              "The file results file was not found. Suggestion: use driver:run-fots to generate it.");
      }
      else ();

      variable $results := parse-xml(file:read-text($pathResults));

      {
        for $testSet in $results//fots:test-set
        let $countFailures := count($testSet//fots:test-case[@result ="fail"])
        let $testSetName := xs:string($testSet/@name)
        where $countFailures gt xs:integer(0)
        return
        for $testCase in $testSet//fots:test-case[@result ="fail"]
        return
          concat('EXPECTED_FOTS_FAILURE (',
                $testSetName,
                ' ',
                $testCase/@name,
                ' 0)
')
      }
    }
  }
  catch *
  {
    error($err:code, $err:description)
  }
};

declare function reporting:regressions(
) as xs:string*
{
  let $old_report:=fn:parse-xml(file:read-text('/home/spungi/work/zorba/repo/fots-ctest/build/bin/report_04_Dec.xml'))
  let $new_report:=fn:parse-xml(file:read-text('/home/spungi/work/zorba/repo/fots-ctest/build/bin/report_18_Dec.xml'))

  for $testSetOld in $old_report/*:report/*:test-set
  let $testSetNew := $new_report/*:report/*:test-set[@name = data($testSetOld/@name)]
  let $regression := if (exists($testSetNew))
                     then xs:decimal(data($testSetOld/@noFailures)) - xs:decimal(data($testSetNew/@noFailures))
                     else xs:decimal(0)
  let $testsOld as xs:string* := tokenize(data($testSetOld/@failedTestNames),",")
  let $testsNew as xs:string* := tokenize(data($testSetNew/@failedTestNames),",")
  where $regression < xs:decimal(0)
  order by $regression ascending
  return
    concat(data($testSetOld/@name),
           " ",
           $regression,
           " ",
           string-join((functx:value-except($testsNew, $testsOld)),","),
           "
")
};

(:
 : Copyright 2006-2011 The FLWOR Foundation.
 :
 : 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.
 :)

(:~
 : Zorba FOTS driver reporting
 : @author Sorin Nasoi
 :)

module namespace reporting =
  "http://www.zorba-xquery.com/fots-driver/reporting";

import module namespace file =
  "http://expath.org/ns/file";

import module namespace driver =
  "http://www.zorba-xquery.com/fots-driver" at "fots-driver.xq";
import module namespace util =
  "http://www.zorba-xquery.com/fots-driver/util" at "util.xq";
import module namespace fots-err =
  "http://www.zorba-xquery.com/fots-driver/errors" at "errors.xq";
import module namespace functx =
  "http://www.functx.com/";

declare namespace err =
  "http://www.w3.org/2005/xqt-errors";
declare namespace fots =
  "http://www.w3.org/2010/09/qt-fots-catalog";
declare namespace results =
  "http://www.w3.org/2012/08/qt-fots-results";

declare default element namespace
  "http://www.w3.org/2012/08/qt-fots-results";

declare namespace ann =
  "http://www.zorba-xquery.com/annotations";

declare namespace op = "http://www.zorba-xquery.com/options/features";
declare namespace f = "http://www.zorba-xquery.com/features";
declare option op:disable "f:trace";

(:~
 : Loops through the test-sets, executes them and reports results.
 : @param $FOTSCatalogFilePath path to the FOTS catalog file.
 : @param $FOTSZorbaManifestPath path to the FOTS Zorba manifest file.
 : @param $exceptedTestCases lists of test cases that are not run( empty
 : sequence means all test cases will be run).
 : @param $exceptedTestSets lists of test sets that are not run(empty sequence
 : means all test sets will be run).
 : @return a report of tests that were executed.
 :)
declare %ann:sequential function reporting:run-and-report(
  $FOTSCatalogFilePath    as xs:string,
  $FOTSZorbaManifestPath  as xs:string,
  $exceptedTestCases      as xs:string*,
  $exceptedTestSets       as xs:string*
) as document-node()
{
  try
  {
    {
      variable $FOTSCatalog := doc(trace(resolve-uri($FOTSCatalogFilePath),
                                  "Path to FOTS catalog.xml set to: "));

      variable $catalogBaseURI := resolve-uri(util:parent-folder($FOTSCatalogFilePath));

      variable $FOTSZorbaManifest := doc(trace(resolve-uri($FOTSZorbaManifestPath),
                                        "Path to FOTSZorbaManifest set to:"));

      variable $results := driver:run-fots($FOTSCatalogFilePath,
                                           $FOTSZorbaManifestPath,
                                           (),
                                           $exceptedTestSets,
                                           (),
                                           $exceptedTestCases,
                                           '',
                                           (),
                                           fn:false(),
                                           '',
                                           'run-test-sets');

      file:write("results.xml",
                 $results,
                 $util:writeXML);

      reporting:W3C-reporting($results,
                              $FOTSZorbaManifestPath)
    }
  }
  catch *
  {
    error($err:code,
          $err:description,
          concat("
Please make sure the passed 'fotsPath' points to the ",
                 "exact location of the FOTS catalog.xml:
",
                 resolve-uri($FOTSCatalogFilePath),
                 "
and that the passed 'fotsZorbaManifestPath' points to",
                 " a file in the same folder as cli.xq:
",
                 resolve-uri($FOTSZorbaManifestPath)))
  }
};

(:~
 : Loops through the test sets, executes them and reports results.
 : @param $FOTSZorbaManifestPath path to the FOTS Zorba manifest file.
 : @param $resultsFilePath path to the FOTS results file.
 : @return The W3C conformance submission file.
 :)
declare %ann:sequential function reporting:report(
  $FOTSZorbaManifestPath  as xs:string,
  $resultsFilePath        as xs:string
) as document-node()
{
  try
  {
    {
      reporting:W3C-reporting(parse-xml(file:read-text($resultsFilePath))/fots:test-cases,
                              $FOTSZorbaManifestPath)
    }
  }
  catch *
  {
    error($err:code, $err:description)
  }
};

(:~
 : Format the W3C conformance report.
 : @param $results FOTS results file.
 : @param $FOTSZorbaManifestPath  path to the FOTS Zorba manifest file.
 : @return The W3C conformance submission file.
 :)
declare %ann:sequential function reporting:W3C-reporting(
  $results                as element(fots:test-cases)?,
  $FOTSZorbaManifestPath  as xs:string
) as document-node()
{
  try
  {
    {
      if (not(file:is-file(resolve-uri($FOTSZorbaManifestPath))))
      then
      {
        error($fots-err:errNA,
              "The 'FOTSZorbaManifest.xml' was not found.");
      }
      else ();

      variable $FOTSZorbaManifest := parse-xml(file:read-text(resolve-uri($FOTSZorbaManifestPath)));

      variable $CLIBaseURI := resolve-uri(util:parent-folder($FOTSZorbaManifestPath));

      variable $W3CTemplatePath := resolve-uri("W3C_submission_template.xml", $CLIBaseURI);

      if (not(file:is-file($W3CTemplatePath)))
      then
      {
        error($fots-err:errNA,
              "'W3C_submission_template.xml' file was not found.");
      }
      else ();

      variable $W3CTemplate := parse-xml(file:read-text($W3CTemplatePath));

      (: add dependecies:)
     (insert nodes
      for $dependency in $FOTSZorbaManifest/fots:test-suite-result/fots:dependency
      return <dependency type="{$dependency/@type}"
                         value="{$dependency/@value}"
                         satisfied="{$dependency/@satisfied}"/>
      as last into $W3CTemplate/results:test-suite-result/results:product,

      (: add test set results:)
      insert nodes
      for $testSet in $results/fots:test-set
      return
      <test-set name="{$testSet/@name}">
        {
          for $testCase in $testSet/fots:test-case
          return
          if(exists($testCase/@comment))
          then
            <test-case name="{$testCase/@name}"
                       result="{$testCase/@result}"
                       comment="{$testCase/@comment}" />
          else
            <test-case name="{$testCase/@name}"
                       result="{$testCase/@result}" />
        }
      </test-set>
      as last into $W3CTemplate/results:test-suite-result);

      $W3CTemplate
    }
  }
  catch *
  {
    error($err:code,
          $err:description,
          concat("
Please make sure there is a 'W3C_submission_template.xml'",
                 " file in the same folder as cli.xq"))
  }
};

(:~
 : Loops through the test-sets and creates statistics.
 : @param $FOTSCatalogFilePath  Path to the FOTS catalog file.
 : @param $failures Path to the results fo the FOTS.
 : @return a report of tests run.
 :)
declare %ann:nondeterministic function reporting:do-reporting(
  $FOTSCatalogFilePath  as xs:string,
  $resultsFilePath      as xs:string
) as element(fots:report)
{
try
{
  {
    variable $FOTSCatalog := doc(trace(resolve-uri($FOTSCatalogFilePath),
                                "Path to FOTS catalog.xml set to: "));

    variable $catalogBaseURI := resolve-uri(util:parent-folder($FOTSCatalogFilePath));

    variable $results := parse-xml(file:read-text($resultsFilePath));

  <fots:report>
  {
    let $totalNoTests := count($results//fots:test-set//fots:test-case),
        $totalPass := sum(for $testSet in $results//fots:test-set
                          return count($testSet//fots:test-case[@result ='pass'])),
        $totalFail := sum(for $testSet in $results//fots:test-set
                          return count($testSet//fots:test-case[@result ='fail'])),
        $totalNotApplicable := sum(for $testSet in $results//fots:test-set
                                   return count($testSet//fots:test-case[@result ='not applicable'])),
        $totalNotRun := sum(for $testSet in $results//fots:test-set
                            return count($testSet//fots:test-case[@result ='notRun']))
    return
    <fots:brief totalTests="{$totalNoTests}"
                totalPass="{$totalPass}"
                totalFail="{$totalFail}"
                totalNotApplicable="{$totalNotApplicable}"
                totalNotRun="{$totalNotRun}"/>
  }
  {
    for $testSetFile in $FOTSCatalog//fots:test-set
    let $testSetURI := resolve-uri($testSetFile/@file,
                                   $catalogBaseURI),
        $testSetDoc := doc($testSetURI),
        $testSetName := data($testSetDoc/fots:test-set/@name),
        $totalNoTestCases := count($testSetDoc//fots:test-case),
        $totalFailures := for $testCase in $results//fots:test-set[@name = $testSetName]//fots:test-case[@result ="fail"]
                          return $testCase,
        $percent := round((1 - (count($totalFailures) div $totalNoTestCases))*100,2),
        $executionTime := sum(for $testCase in $results//fots:test-set[@name = $testSetName]//fots:test-case
                              return xs:dayTimeDuration($testCase/@executionTime))
    where count($totalFailures) gt 0
    order by count($totalFailures) descending
    return
    <fots:test-set  name="{$testSetName}"
                    noFailures="{count($totalFailures)}"
                    noTestCases="{$totalNoTestCases}"
                    percent="{$percent}"
                  failedTestNames="{string-join(for $failure in $totalFailures
                                                order by data($failure/@name)
                                                return data($failure/@name)
                                              ,",")}">
    </fots:test-set>
   }
  </fots:report>

  }
}
catch *
{
  error($err:code,
        $err:description,
        concat("
Please make sure the passed 'fotsPath' points to the ",
               "exact location of the FOTS catalog.xml:
",
               resolve-uri($FOTSCatalogFilePath)))
}
};

(:~
 : Loops through the results and creates ExpectedFailures.xml.
 : @param $pathResults path to the FOTS results.
 : @return ExpectedFailures.xml.
 :)
declare %ann:nondeterministic function reporting:generate-expected-failures(
  $pathResults  as xs:string
)
{
  try
  {
    {
      if (not(file:is-file($pathResults)))
      then
      {
        error($fots-err:errNA,
              "The file results file was not found. Suggestion: use driver:run-fots to generate it.");
      }
      else ();

      variable $results := parse-xml(file:read-text($pathResults));

      {
        for $testSet in $results//fots:test-set
        let $countFailures := count($testSet//fots:test-case[@result ="fail"])
        let $testSetName := xs:string($testSet/@name)
        where $countFailures gt xs:integer(0)
        return
        for $testCase in $testSet//fots:test-case[@result ="fail"]
        return
          concat('EXPECTED_FOTS_FAILURE (',
                $testSetName,
                ' ',
                $testCase/@name,
                ' 0)
')
      }
    }
  }
  catch *
  {
    error($err:code, $err:description)
  }
};

declare function reporting:regressions(
) as xs:string*
{
  let $old_report:=fn:parse-xml(file:read-text('/home/spungi/work/zorba/repo/fots-ctest/build/bin/report_04_Dec.xml'))
  let $new_report:=fn:parse-xml(file:read-text('/home/spungi/work/zorba/repo/fots-ctest/build/bin/report_18_Dec.xml'))

  for $testSetOld in $old_report/*:report/*:test-set
  let $testSetNew := $new_report/*:report/*:test-set[@name = data($testSetOld/@name)]
  let $regression := if (exists($testSetNew))
                     then xs:decimal(data($testSetOld/@noFailures)) - xs:decimal(data($testSetNew/@noFailures))
                     else xs:decimal(0)
  let $testsOld as xs:string* := tokenize(data($testSetOld/@failedTestNames),",")
  let $testsNew as xs:string* := tokenize(data($testSetNew/@failedTestNames),",")
  where $regression < xs:decimal(0)
  order by $regression ascending
  return
    concat(data($testSetOld/@name),
           " ",
           $regression,
           " ",
           string-join((functx:value-except($testsNew, $testsOld)),","),
           "
")
};


odified the path for provider facilities

import module namespace csd = "urn:ihe:iti:csd:2013" at "../repo/csd_base_library.xqm";
declare default element  namespace   "urn:ihe:iti:csd:2013";
declare variable $careServicesRequest as item() external;

(:
   The query will be executed against the root element of the CSD document.

   The dynamic context of this query has $careServicesRequest set to contain any of the search
   and limit paramaters as sent by the Service Finder
:)

<CSD xmlns:csd="urn:ihe:iti:csd:2013"  >
  <organizationDirectory/>
  <serviceDirectory/>
  <facilityDirectory/>
  <providerDirectory>
    {
      let $facility_oid := $careServicesRequest/facility[1]/@oid
      let $service_oid := $careServicesRequest/facility[1]/service[1]/@oid

      (: if no provider id was provided, then this is invalid. :)
      let $provs0 := if (exists($careServicesRequest/id/@oid))
	then csd:filter_by_primary_id(/CSD/providerDirectory/*,$careServicesRequest/id)
      else ()

      let $provs1 := if (exists($facility_oid) and count($provs0) = 1)
	then
	   if (count ($provs0[1]/facilities/facility[@oid = $facility_oid]) > 0) then $provs0 else ()
	else $provs0

      let $provs2 := if (exists($service_oid) and count($provs1) = 1)
	then
	   if (count ($provs1[1]/facilities/facility[@oid = $facility_oid]/service[@oid = $service_oid]) > 0) then $provs1 else ()
	else $provs1

      return if (count($provs2) = 1) then
	<provider oid='{$provs2[1]/@oid}'/>
      else
	 ()
    }
  </providerDirectory>
</CSD>

import module namespace csd = "urn:ihe:iti:csd:2013" at "../repo/csd_base_library.xqm";
declare default element  namespace   "urn:ihe:iti:csd:2013";
declare variable $careServicesRequest as item() external;

(:
   The query will be executed against the root element of the CSD document.

   The dynamic context of this query has $careServicesRequest set to contain any of the search
   and limit paramaters as sent by the Service Finder
:)

<CSD xmlns:csd="urn:ihe:iti:csd:2013"  >
  <organizationDirectory/>
  <serviceDirectory/>
  <facilityDirectory/>
  <providerDirectory>
    {
      let $facility_oid := $careServicesRequest/facility[1]/@oid
      let $service_oid := $careServicesRequest/facility[1]/service[1]/@oid

      (: if no provider id was provided, then this is invalid. :)
      let $provs0 := if (exists($careServicesRequest/id/@oid))
	then csd:filter_by_primary_id(/CSD/providerDirectory/*,$careServicesRequest/id)
      else ()

      let $provs1 := if (exists($facility_oid) and count($provs0) = 1)
	then
	   if (count ($provs0[1]/facility[@oid = $facility_oid]) > 0) then $provs0 else ()
	else $provs0

      let $provs2 := if (exists($service_oid) and count($provs1) = 1)
	then
	   if (count ($provs1[1]/facility[@oid = $facility_oid]/service[@oid = $service_oid]) > 0) then $provs1 else ()
	else $provs1

      return if (count($provs2) = 1) then
	<provider oid='{$provs2[1]/@oid}'/>
      else
	 ()
    }
  </providerDirectory>
</CSD>