[ignore] small update for the examples installer

svn path=/stable/eXist-1.4.x/; revision=15011

xquery version "1.0";
(: $Id$ :)
(:
    Module: examples setup
:)

module namespace setup="http://exist-db.org/xquery/admin-interface/setup";

declare namespace xdb="http://exist-db.org/xquery/xmldb";
declare namespace request="http://exist-db.org/xquery/request";
declare namespace session="http://exist-db.org/xquery/session";
declare namespace util="http://exist-db.org/xquery/util";
declare namespace system="http://exist-db.org/xquery/system";
declare namespace file="http://exist-db.org/xquery/file";

declare function setup:main() as element()
{

Examples Setup

        {
let $action := request:get-parameter("action", ()) return
		if($action) then
		                (
		                    if($action eq "Import Example Data") then
		                    (
		                        setup:importLocal()
		                    )
		                    else if($action eq "Import Files") then
		                    (
		                        setup:importFromURLs()
		                    )
		                    else
		                    (
		                        setup:report()
		                    )
		                )
		                else
		                (
		                    setup:select()
		                )

        }

};

declare function setup:importLocal() as element()+
{
    let $home := system:get-exist-home(),
    $pathSep := util:system-property("file.separator"),
    $dir := if (doc-available(concat("file:///", $home, "/exist-samples/examples.xml"))) then
        (
            concat($home, $pathSep, "exist-samples")
        )
        else if(ends-with($home, "WEB-INF")) then
        (
            concat(substring-before($home, "WEB-INF"), "samples")
        )
        else
        (
            concat($home, $pathSep, "samples")
        ),
    $webapp := if (doc-available(concat("file:///", $home, "/webapp/index.xml"))) then
        (
            concat($home, $pathSep, "webapp")
        )
        else if(ends-with($home, "WEB-INF")) then
        (
            substring-before($home, "WEB-INF")
        )
        else
        (
            concat($home, $pathSep, "webapp")
		),

    $betterform-xrx := concat($home, "/extensions/betterform/src/main/xrx/timetracker/"),
    $betterform-xforms := concat($home, "/extensions/betterform/src/main/xforms")

    return (
                setup:create-collection("/db/system/config", "db"),
                setup:create-collection("/db/system/config/db", "shakespeare"),
                setup:store-files("/db/system/config/db/shakespeare", $dir,
                    "shakespeare/collection.xconf", "text/xml"),
                setup:create-collection("/db", "shakespeare"),
                setup:create-collection("/db/shakespeare", "plays"),
                setup:store-files("/db/shakespeare/plays", $dir,  "shakespeare/*.xml", "text/xml"),
                setup:store-files("/db/shakespeare/plays", $dir, "shakespeare/*.xsl", "text/xml"),
                setup:store-files("/db/shakespeare/plays", $dir, "shakespeare/*.css", "text/css"),
                setup:create-collection("/db", "xinclude"),
                setup:create-collection("/db/xinclude", "styles"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.xsl", "text/xml"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.xml", "text/xml"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.xq", "application/xquery"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.jpg", "image/jpeg"),
                setup:store-files("/db/xinclude/styles", $dir, "xinclude/styles/*", "text/css"),
                setup:create-collection("/db/xinclude", "scripts"),
                setup:create-collection("/db/xinclude/scripts", "syntax"),
                setup:store-files("/db/xinclude/scripts/syntax", $dir, "xinclude/scripts/syntax/*.js", "application/x-javascript"),
                setup:create-collection("/db", "library"),
                setup:store-files("/db/library", $dir, "*.rdf", "text/xml"),
                setup:create-collection("/db/system/config/db", "mods"),
                setup:store-files("/db/system/config/db/mods", $dir, "mods/collection.xconf", "text/xml"),
                setup:create-collection("/db", "mods"),
                setup:store-files("/db/mods", $dir, "mods/*.xml", "text/xml"),
                setup:store-files("/db", $dir, "*.xml", "text/xml"),
                setup:create-collection("/db/system/config/db", "mondial"),
                setup:store-files("/db/system/config/db/mondial", $dir, "mondial.xconf", "text/xml"),
                setup:create-collection("/db/system/config/db", "xmlad"),
                setup:store-files("/db/system/config/db/xmlad", $dir, "acronyms.xconf", "text/xml"),
                setup:create-collection("/db", "xproc"),
                setup:create-collection("/db/xproc", "unit-test"),
                setup:create-collection("/db/xproc", "xml"),
                setup:create-collection("/db/xproc", "xslt"),
                setup:create-collection("/db/xproc", "result"),
                setup:create-collection("/db/xproc", "examples"),
                setup:create-collection("/db/xproc", "pipelines"),
                setup:store-files("/db/xproc/unit-test", $webapp, "xproc/unit-test/*.xml", "text/xml"),
                setup:store-files("/db/xproc/unit-test", $webapp, "xproc/unit-test/*.xql", "application/xquery"),
                setup:store-files("/db/xproc/unit-test", $webapp, "xproc/unit-test/*.xsl", "text/xml"),

                setup:store-files("/db/xproc/pipelines", $webapp, "xproc/pipelines/*.xml", "text/xml"),
                setup:store-files("/db/xproc/xml", $webapp, "xproc/xml/*.xml", "text/xml"),
                setup:store-files("/db/xproc/xslt", $webapp, "xproc/xml/*.xsl", "text/xml"),

                setup:store-files("/db/xproc/examples", $webapp, "xproc/examples/*.xproc", "application/xml+xproc"),
                setup:store-files("/db/xproc/examples", $webapp, "xproc/examples/*.xml", "text/xml"),

                setup:store-files("/db/xproc/examples", $webapp, "xproc/examples/*.xql", "application/xquery"),
                setup:store-files("/db/xproc", $webapp, "xproc/*.xml", "text/xml"),
                setup:store-files("/db/xproc", $webapp, "xproc/*.xql", "application/xquery"),

                (: Storing XForms in the db won't work right now :)
                (:
                setup:create-collection("/db", "xforms"),
                setup:store-files("/db/xforms", $webapp, "xforms/*.xml", "text/html"),
                setup:store-files("/db/xforms", $webapp, "xforms/*.xq*", "application/xquery"),
                setup:create-collection("/db/xforms", "xsltforms"),
                setup:create-collection("/db/xforms", "data"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.properties", "text/plain"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.png", "image/png"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.gif", "image/gif"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.xsl","text/xml"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.js","application/x-javascript"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.css","text/css")
                :)

				(: Storing betterFORM XRX sample application :)

				setup:create-collection("/db", "betterform"),
				setup:create-collection("/db/betterform", "apps"),
				setup:create-collection("/db/betterform/apps", "timetracker"),
				setup:store-files("/db/betterform/apps/timetracker", $betterform-xrx, "*.xql","application/xquery"),
				setup:store-files("/db/betterform/apps/timetracker", $betterform-xrx, "*.html","text/html"),
				setup:store-files("/db/betterform/apps/timetracker", $betterform-xrx, "*.xml","application/xml"),
				setup:create-collection("/db/betterform/apps/timetracker", "data"),
				setup:store-files("/db/betterform/apps/timetracker/data", $betterform-xrx, "data/*.xml", "application/xml"),
				setup:create-collection("/db/betterform/apps/timetracker/data", "task"),
				setup:store-files("/db/betterform/apps/timetracker/data/task", $betterform-xrx, "data/task/*.xml","application/xml"),
				setup:create-collection("/db/betterform/apps/timetracker/", "edit"),
				setup:store-files("/db/betterform/apps/timetracker/edit", $betterform-xrx, "edit/*.xql","application/xquery"),
				setup:create-collection("/db/betterform/apps/timetracker/", "lucene"),
				setup:store-files("/db/betterform/apps/timetracker/lucene", $betterform-xrx, "lucene/*.xconf","application/xml"),
				setup:create-collection("/db/betterform/apps/timetracker/", "reports"),
				setup:store-files("/db/betterform/apps/timetracker/reports", $betterform-xrx, "reports/*.xql","application/xquery"),
				setup:create-collection("/db/betterform/apps/timetracker/", "resources"),
				setup:store-files("/db/betterform/apps/timetracker/resources", $betterform-xrx, "resources/*.css","text/css"),
				setup:create-collection("/db/betterform/apps/timetracker/resources", "images"),
				setup:store-files("/db/betterform/apps/timetracker/resources/images", $betterform-xrx, "resources/images/*.gif","image/gif"),
				setup:store-files("/db/betterform/apps/timetracker/resources/images", $betterform-xrx, "resources/images/*.png","image/png"),
				setup:store-files("/db/betterform/apps/timetracker/resources/images", $betterform-xrx, "resources/images/*.jpg","image/jpeg"),
				setup:create-collection("/db/betterform/apps/timetracker/", "search"),
				setup:store-files("/db/betterform/apps/timetracker/search", $betterform-xrx, "search/*.xql","application/xquery"),
				setup:store-files("/db/betterform/apps/timetracker/search", $betterform-xrx, "search/*.html","text/html"),
				setup:create-collection("/db/betterform/apps/timetracker/", "update"),
				setup:store-files("/db/betterform/apps/timetracker/update", $betterform-xrx, "update/*.xql","application/xquery"),
				setup:create-collection("/db/betterform/apps/timetracker/", "views"),
				setup:store-files("/db/betterform/apps/timetracker/views", $betterform-xrx, "views/*.xql","application/xquery"),
				setup:store-files("/db/betterform/apps/timetracker/views", $betterform-xrx, "views/*.html","text/html"),
				setup:store-files("/db/betterform/apps/timetracker/views", $betterform-xrx, "views/*.xsl","application/xml"),

				(: Storing betterFORM dashboard :)
				setup:create-collection("/db/betterform", "utils"),
				setup:store-files("/db/betterform/utils", $betterform-xforms, "utils/*.xql","application/xquery"),

				(: Storing betterFORM XForms reference forms :)
				setup:store-files("/db/betterform", $betterform-xforms, "*.xhtml","application/xhtml+xml"),
				setup:create-collection("/db/betterform", "forms"),
				setup:create-collection("/db/betterform/forms", "reference"),
				setup:store-files("/db/betterform/forms/reference", $betterform-xforms, "reference/*.xhtml","application/xhtml+xml"),
				setup:store-files("/db/betterform/forms/reference", $betterform-xforms, "reference/*.css","text/css"),
				setup:store-files("/db/betterform/forms/reference", $betterform-xforms, "reference/*.html","text/html"),
				setup:create-collection("/db/betterform/forms/reference", "images"),
				setup:store-files("/db/betterform/forms/reference/images", $betterform-xforms, "reference/images/*.png","image/png"),
				setup:store-files("/db/betterform/forms/reference/images", $betterform-xforms, "reference/images/*.gif","image/gif"),
				setup:create-collection("/db/betterform/forms/reference", "resources"),
				setup:store-files("/db/betterform/forms/reference/resources", $betterform-xforms, "reference/resources/*.xhtml","application/xhtml+xml"),
				setup:store-files("/db/betterform/forms/reference/resources", $betterform-xforms, "reference/resources/*.html","text/html"),
				setup:store-files("/db/betterform/forms/reference/resources", $betterform-xforms, "reference/resources/*.css","text/css"),
				setup:store-files("/db/betterform/forms/reference/resources", $betterform-xforms, "reference/resources/*.js","application/x-javascript"),
				setup:store-files("/db/betterform/forms/reference/resources", $betterform-xforms, "reference/resources/*.jpg","image/jpeg"),
				setup:create-collection("/db/betterform/forms", "demo"),
				setup:store-files("/db/betterform/forms/demo", $betterform-xforms, "demo/*.xhtml","application/xhtml+xml"),
				setup:create-collection("/db/betterform/forms/demo", "styles"),
				setup:store-files("/db/betterform/forms/demo/styles", $betterform-xforms, "demo/styles/*.css","text/css"),
				setup:store-files("/db/betterform/forms/demo", $betterform-xforms, "demo/*.xml","application/xml")
    )
};

declare function setup:importFromURLs() as element()+
{
    (
        setup:report(),

Actions:

            {
                let $includeXmlad := request:get-parameter("xmlad", ()),
                $includeMondial := request:get-parameter("mondial", ()),
 				$includeLocal := request:get-parameter("local", ()) return
                (
					if($includeLocal) then
					( setup:importLocal()
					)
					else (),
                    if($includeXmlad) then
                    (
                        setup:create-collection("/db", "xmlad"),
                        setup:load-URL("/db/xmlad", xs:anyURI("http://surfnet.dl.sourceforge.net/sourceforge/xmlad/xmlad.xml"), "xmlad.xml")
                    )else (),
                    if($includeMondial) then
                    (
                        setup:create-collection("/db", "mondial"),
                        setup:load-URL("/db/mondial", xs:anyURI("http://www.dbis.informatik.uni-goettingen.de/Mondial/mondial-europe.xml"), "mondial.xml")
                    )else ()
                )
            }

    )
};

declare function setup:load-URL($collection as xs:string, $url as xs:anyURI, $docName as xs:string) as element()
{
    let $x := xdb:store($collection, $docName, $url) return

File {$docName} imported from url: {$url}

};

declare function setup:store-files($collection as xs:string, $home as xs:string, $patterns as xs:string, $mimeType as xs:string) as element()*
{
    let $stored := xdb:store-files-from-pattern($collection, $home, $patterns, $mimeType)
    for $doc in $stored return

Uploaded: {$doc}

};

declare function setup:create-collection($parent as xs:string, $name as xs:string) as element()
{
    let $col := xdb:create-collection($parent, $name) return

Created collection: {$col}

};

declare function setup:select() as element()
{
    <form action="{session:encode-url(request:get-uri())}" method="post">

eXist ships with a number of XQuery examples, which almost all
        require certain documents to be stored in the database. Some XQuery examples require
		XML data not included with the distribution which can be downloaded by selecting
		the checkboxes below.

		<input type="checkbox" name="local" checked="true"/>
		eXist-db shipped files (*)

        <input type="checkbox" name="xmlad"/>
        The XML Acronym Demystifier
        (approx. 384K)

        <input type="checkbox" name="mondial"/>
        The Mondial Database (Europe)
        (approx. 410K)

<input type="submit" name="action" value="Import Files"/>
        <input type="submit" name="action" value="Skip"/>

        <input type="hidden" name="panel" value="setup"/>

(*) Contains data for the betterFORM, shakespeare, xinclude, library, mods and xproc examples.
            It also contains the index configuration definitions for the mondial and acronym examples.

    </form>
};

declare function setup:report() as element()
{

Files have been loaded. You can now go to the
    examples page.

};

xquery version "1.0";
(: $Id$ :)
(:
    Module: examples setup
:)

module namespace setup="http://exist-db.org/xquery/admin-interface/setup";

declare namespace xdb="http://exist-db.org/xquery/xmldb";
declare namespace request="http://exist-db.org/xquery/request";
declare namespace session="http://exist-db.org/xquery/session";
declare namespace util="http://exist-db.org/xquery/util";
declare namespace system="http://exist-db.org/xquery/system";
declare namespace file="http://exist-db.org/xquery/file";

declare function setup:main() as element()
{

Examples Setup

        {
let $action := request:get-parameter("action", ()) return
		if($action) then
		                (
		                    if($action eq "Import Example Data") then
		                    (
		                        setup:importLocal()
		                    )
		                    else if($action eq "Import Files") then
		                    (
		                        setup:importFromURLs()
		                    )
		                    else
		                    (
		                        setup:report()
		                    )
		                )
		                else
		                (
		                    setup:select()
		                )

        }

};

declare function setup:importLocal() as element()+
{
    let $home := system:get-exist-home(),
    $pathSep := util:system-property("file.separator"),
    $dir := if (doc-available(concat("file:///", $home, "/exist-samples/examples.xml"))) then
        (
            concat($home, $pathSep, "exist-samples")
        )
        else if(ends-with($home, "WEB-INF")) then
        (
            concat(substring-before($home, "WEB-INF"), "samples")
        )
        else
        (
            concat($home, $pathSep, "samples")
        ),
    $webapp := if (doc-available(concat("file:///", $home, "/webapp/index.xml"))) then
        (
            concat($home, $pathSep, "webapp")
        )
        else if(ends-with($home, "WEB-INF")) then
        (
            substring-before($home, "WEB-INF")
        )
        else
        (
            concat($home, $pathSep, "webapp")
		),

    $betterform-xrx := concat($home, "/extensions/betterform/src/main/xrx/timetracker/"),
    $betterform-xforms := concat($home, "/extensions/betterform/src/main/xforms")

    return (
                setup:create-collection("/db/system/config", "db"),
                setup:create-collection("/db/system/config/db", "shakespeare"),
                setup:store-files("/db/system/config/db/shakespeare", $dir,
                    "shakespeare/collection.xconf", "text/xml"),
                setup:create-collection("/db", "shakespeare"),
                setup:create-collection("/db/shakespeare", "plays"),
                setup:store-files("/db/shakespeare/plays", $dir,  "shakespeare/*.xml", "text/xml"),
                setup:store-files("/db/shakespeare/plays", $dir, "shakespeare/*.xsl", "text/xml"),
                setup:store-files("/db/shakespeare/plays", $dir, "shakespeare/*.css", "text/css"),
                setup:create-collection("/db", "xinclude"),
                setup:create-collection("/db/xinclude", "styles"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.xsl", "text/xml"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.xml", "text/xml"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.xq", "application/xquery"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.jpg", "image/jpeg"),
                setup:store-files("/db/xinclude/styles", $dir, "xinclude/styles/*", "text/css"),
                setup:create-collection("/db/xinclude", "scripts"),
                setup:create-collection("/db/xinclude/scripts", "syntax"),
                setup:store-files("/db/xinclude/scripts/syntax", $dir, "xinclude/scripts/syntax/*.js", "application/x-javascript"),
                setup:create-collection("/db", "library"),
                setup:store-files("/db/library", $dir, "*.rdf", "text/xml"),
                setup:create-collection("/db/system/config/db", "mods"),
                setup:store-files("/db/system/config/db/mods", $dir, "mods/collection.xconf", "text/xml"),
                setup:create-collection("/db", "mods"),
                setup:store-files("/db/mods", $dir, "mods/*.xml", "text/xml"),
                setup:store-files("/db", $dir, "*.xml", "text/xml"),
                setup:create-collection("/db/system/config/db", "mondial"),
                setup:store-files("/db/system/config/db/mondial", $dir, "mondial.xconf", "text/xml"),
                setup:create-collection("/db/system/config/db", "xmlad"),
                setup:store-files("/db/system/config/db/xmlad", $dir, "acronyms.xconf", "text/xml"),
                setup:create-collection("/db", "xproc"),
                setup:create-collection("/db/xproc", "unit-test"),
                setup:create-collection("/db/xproc", "xml"),
                setup:create-collection("/db/xproc", "xslt"),
                setup:create-collection("/db/xproc", "result"),
                setup:create-collection("/db/xproc", "examples"),
                setup:create-collection("/db/xproc", "pipelines"),
                setup:store-files("/db/xproc/unit-test", $webapp, "xproc/unit-test/*.xml", "text/xml"),
                setup:store-files("/db/xproc/unit-test", $webapp, "xproc/unit-test/*.xql", "application/xquery"),
                setup:store-files("/db/xproc/unit-test", $webapp, "xproc/unit-test/*.xsl", "text/xml"),

                setup:store-files("/db/xproc/pipelines", $webapp, "xproc/pipelines/*.xml", "text/xml"),
                setup:store-files("/db/xproc/xml", $webapp, "xproc/xml/*.xml", "text/xml"),
                setup:store-files("/db/xproc/xslt", $webapp, "xproc/xml/*.xsl", "text/xml"),

                setup:store-files("/db/xproc/examples", $webapp, "xproc/examples/*.xproc", "application/xml+xproc"),
                setup:store-files("/db/xproc/examples", $webapp, "xproc/examples/*.xml", "text/xml"),

                setup:store-files("/db/xproc/examples", $webapp, "xproc/examples/*.xql", "application/xquery"),
                setup:store-files("/db/xproc", $webapp, "xproc/*.xml", "text/xml"),
                setup:store-files("/db/xproc", $webapp, "xproc/*.xql", "application/xquery"),

                (: Storing XForms in the db won't work right now :)
                (:
                setup:create-collection("/db", "xforms"),
                setup:store-files("/db/xforms", $webapp, "xforms/*.xml", "text/html"),
                setup:store-files("/db/xforms", $webapp, "xforms/*.xq*", "application/xquery"),
                setup:create-collection("/db/xforms", "xsltforms"),
                setup:create-collection("/db/xforms", "data"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.properties", "text/plain"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.png", "image/png"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.gif", "image/gif"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.xsl","text/xml"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.js","application/x-javascript"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.css","text/css")
                :)

				(: Storing betterFORM XRX sample application :)

				setup:create-collection("/db", "betterform"),
				setup:create-collection("/db/betterform", "apps"),
				setup:create-collection("/db/betterform/apps", "timetracker"),
				setup:store-files("/db/betterform/apps/timetracker", $betterform-xrx, "*.xql","application/xquery"),
				setup:store-files("/db/betterform/apps/timetracker", $betterform-xrx, "*.html","text/html"),
				setup:store-files("/db/betterform/apps/timetracker", $betterform-xrx, "*.xml","application/xml"),
				setup:create-collection("/db/betterform/apps/timetracker", "data"),
				setup:store-files("/db/betterform/apps/timetracker/data", $betterform-xrx, "data/*.xml", "application/xml"),
				setup:create-collection("/db/betterform/apps/timetracker/data", "task"),
				setup:store-files("/db/betterform/apps/timetracker/data/task", $betterform-xrx, "data/task/*.xml","application/xml"),
				setup:create-collection("/db/betterform/apps/timetracker/", "edit"),
				setup:store-files("/db/betterform/apps/timetracker/edit", $betterform-xrx, "edit/*.xql","application/xquery"),
				setup:create-collection("/db/betterform/apps/timetracker/", "lucene"),
				setup:store-files("/db/betterform/apps/timetracker/lucene", $betterform-xrx, "lucene/*.xconf","application/xml"),
				setup:create-collection("/db/betterform/apps/timetracker/", "reports"),
				setup:store-files("/db/betterform/apps/timetracker/reports", $betterform-xrx, "reports/*.xql","application/xquery"),
				setup:create-collection("/db/betterform/apps/timetracker/", "resources"),
				setup:store-files("/db/betterform/apps/timetracker/resources", $betterform-xrx, "resources/*.css","text/css"),
				setup:create-collection("/db/betterform/apps/timetracker/resources", "images"),
				setup:store-files("/db/betterform/apps/timetracker/resources/images", $betterform-xrx, "resources/images/*.gif","image/gif"),
				setup:store-files("/db/betterform/apps/timetracker/resources/images", $betterform-xrx, "resources/images/*.png","image/png"),
				setup:store-files("/db/betterform/apps/timetracker/resources/images", $betterform-xrx, "resources/images/*.jpg","image/jpeg"),
				setup:create-collection("/db/betterform/apps/timetracker/", "search"),
				setup:store-files("/db/betterform/apps/timetracker/search", $betterform-xrx, "search/*.xql","application/xquery"),
				setup:store-files("/db/betterform/apps/timetracker/search", $betterform-xrx, "search/*.html","text/html"),
				setup:create-collection("/db/betterform/apps/timetracker/", "update"),
				setup:store-files("/db/betterform/apps/timetracker/update", $betterform-xrx, "update/*.xql","application/xquery"),
				setup:create-collection("/db/betterform/apps/timetracker/", "views"),
				setup:store-files("/db/betterform/apps/timetracker/views", $betterform-xrx, "views/*.xql","application/xquery"),
				setup:store-files("/db/betterform/apps/timetracker/views", $betterform-xrx, "views/*.html","text/html"),
				setup:store-files("/db/betterform/apps/timetracker/views", $betterform-xrx, "views/*.xsl","application/xml"),

				(: Storing betterFORM dashboard :)
				setup:create-collection("/db/betterform", "utils"),
				setup:store-files("/db/betterform/utils", $betterform-xforms, "utils/*.xql","application/xquery"),

				(: Storing betterFORM XForms reference forms :)
				setup:store-files("/db/betterform", $betterform-xforms, "*.xhtml","application/xhtml+xml"),
				setup:create-collection("/db/betterform", "forms"),
				setup:create-collection("/db/betterform/forms", "reference"),
				setup:store-files("/db/betterform/forms/reference", $betterform-xforms, "reference/*.xhtml","application/xhtml+xml"),
				setup:store-files("/db/betterform/forms/reference", $betterform-xforms, "reference/*.css","text/css"),
				setup:store-files("/db/betterform/forms/reference", $betterform-xforms, "reference/*.html","text/html"),
				setup:create-collection("/db/betterform/forms/reference", "images"),
				setup:store-files("/db/betterform/forms/reference/images", $betterform-xforms, "reference/images/*.png","image/png"),
				setup:store-files("/db/betterform/forms/reference/images", $betterform-xforms, "reference/images/*.gif","image/gif"),
				setup:create-collection("/db/betterform/forms/reference", "resources"),
				setup:store-files("/db/betterform/forms/reference/resources", $betterform-xforms, "reference/resources/*.xhtml","application/xhtml+xml"),
				setup:store-files("/db/betterform/forms/reference/resources", $betterform-xforms, "reference/resources/*.html","text/html"),
				setup:store-files("/db/betterform/forms/reference/resources", $betterform-xforms, "reference/resources/*.css","text/css"),
				setup:store-files("/db/betterform/forms/reference/resources", $betterform-xforms, "reference/resources/*.js","application/x-javascript"),
				setup:store-files("/db/betterform/forms/reference/resources", $betterform-xforms, "reference/resources/*.jpg","image/jpeg"),
				setup:create-collection("/db/betterform/forms", "demo"),
				setup:store-files("/db/betterform/forms/demo", $betterform-xforms, "demo/*.xhtml","application/xhtml+xml"),
				setup:create-collection("/db/betterform/forms/demo", "styles"),
				setup:store-files("/db/betterform/forms/demo/styles", $betterform-xforms, "demo/styles/*.css","text/css"),
				setup:store-files("/db/betterform/forms/demo", $betterform-xforms, "demo/*.xml","application/xml")
    )
};

declare function setup:importFromURLs() as element()+
{
    (
        setup:report(),

Actions:

            {
                let $includeXmlad := request:get-parameter("xmlad", ()),
                $includeMondial := request:get-parameter("mondial", ()),
 				$includeLocal := request:get-parameter("local", ()) return
                (
					if($includeLocal) then
					( setup:importLocal()
					)
					else (),
                    if($includeXmlad) then
                    (
                        setup:create-collection("/db", "xmlad"),
                        setup:load-URL("/db/xmlad", xs:anyURI("http://surfnet.dl.sourceforge.net/sourceforge/xmlad/xmlad.xml"), "xmlad.xml")
                    )else (),
                    if($includeMondial) then
                    (
                        setup:create-collection("/db", "mondial"),
                        setup:load-URL("/db/mondial", xs:anyURI("http://www.dbis.informatik.uni-goettingen.de/Mondial/mondial-europe.xml"), "mondial.xml")
                    )else ()
                )
            }

    )
};

declare function setup:load-URL($collection as xs:string, $url as xs:anyURI, $docName as xs:string) as element()
{
    let $x := xdb:store($collection, $docName, $url) return

File {$docName} imported from url: {$url}

};

declare function setup:store-files($collection as xs:string, $home as xs:string, $patterns as xs:string, $mimeType as xs:string) as element()*
{
    let $stored := xdb:store-files-from-pattern($collection, $home, $patterns, $mimeType)
    for $doc in $stored return

Uploaded: {$doc}

};

declare function setup:create-collection($parent as xs:string, $name as xs:string) as element()
{
    let $col := xdb:create-collection($parent, $name) return

Created collection: {$col}

};

declare function setup:select() as element()
{
    <form action="{session:encode-url(request:get-uri())}" method="post">

eXist ships with a number of XQuery examples. Some of these
        require certain documents to be stored in the database. The XQuery examples also use some
		XML data not included with the distribution which can be downloaded by selecting
		the checkboxes below.

		<input type="checkbox" name="local" checked="true"/>
		eXist-db shipped files

        <input type="checkbox" name="xmlad"/>
        The XML Acronym Demystifier
        (approx. 384K)

        <input type="checkbox" name="mondial"/>
        The Mondial Database (Europe)
        (approx. 410K)

<input type="submit" name="action" value="Import Files"/>
        <input type="submit" name="action" value="Skip"/>

        <input type="hidden" name="panel" value="setup"/>
    </form>
};

declare function setup:report() as element()
{

Files have been loaded. You can now go to the
    examples page.

};


Queries on more fields in Advanced Search.

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

xquery version "1.0";

(:~
    The core XQuery script for the bibliographic demo. It receives a template XML document
    from the controller and expands it. If a search was trigger by the user, the script
    proceeds as follows:

the input form parameters are transformed into a simple XML structure
            to describe the query

an XPath string is generated from the XML query structure

the XPath is executed and the sort criteria applied

query results, XML query and sort criteria are stored into the HTTP session

the template is expanded, forms are regenerated to match the query

    To apply a filter to an existing query, we just extend the XML representation
    of the query.
:)
import module namespace jquery="http://exist-db.org/xquery/jquery" at "jquery.xql";

declare namespace biblio="http:/exist-db.org/xquery/biblio";

import module namespace mods="http://www.loc.gov/mods/v3" at "retrieve-mods.xql";
import module namespace sort="http://exist-db.org/xquery/sort"
	at "java:org.exist.xquery.modules.sort.SortModule";

declare option exist:serialize "media-type=text/xml omit-xml-declaration=no";

declare variable $biblio:CREDENTIALS := ("biblio", "mods");

declare variable $biblio:COLLECTION := "collection('/db')//";

(:~
    Simple mapping from field names to an XPath expression
:)
declare variable $biblio:FIELDS :=
	<fields>
		<field name="Title">(
		mods:mods[ft:query(mods:titleInfo, '$q', $options)]
		      union
		mods:mods[ft:query(mods:relatedItem/mods:titleInfo, '$q', $options)]
		)</field>
		<field name="Name">(
		mods:mods[ft:query(mods:name, '$q', $options)]
		      union
		mods:mods[ft:query(mods:relatedItem/mods:name, '$q', $options)]
		)</field>
		<field name="Date">(
		mods:mods[ft:query(mods:originInfo/mods:dateCreated, '$q', $options)]
		      union
		mods:mods[ft:query(mods:originInfo/mods:dateIssued, '$q', $options)]
		      union
		mods:mods[ft:query(mods:originInfo/mods:dateCaptured, '$q', $options)]
		      union
		mods:mods[ft:query(mods:originInfo/mods:copyrightDate, '$q', $options)]
		      union
		mods:mods[ft:query(mods:relatedItem/mods:originInfo/mods:dateCreated, '$q', $options)]
		      union
		mods:mods[ft:query(mods:relatedItem/mods:originInfo/mods:dateIssued, '$q', $options)]
		      union
		mods:mods[ft:query(mods:relatedItem/mods:originInfo/mods:dateCaptured, '$q', $options)]
		      union
		mods:mods[ft:query(mods:relatedItem/mods:originInfo/mods:copyrightDate, '$q', $options)]
		)</field>
		<field name="Abstract">mods:mods[ft:query(mods:abstract, '$q', $options)]</field>
        <field name="Note">mods:mods[ft:query(mods:note, '$q', $options)]</field>
        <field name="Subject">mods:mods[ft:query(mods:subject, '$q', $options)]</field>
        <field name="All Except Date">(
        mods:mods[ft:query(mods:titleInfo, '$q', $options)]
                union
        mods:mods[ft:query(mods:relatedItem/mods:titleInfo, '$q', $options)]
                union
		mods:mods[ft:query(mods:name, '$q', $options)]
                union
		mods:mods[ft:query(mods:relatedItem/mods:name, '$q', $options)]
		        union
		mods:mods[ft:query(mods:abstract, '$q', $options)]
		        union
		mods:mods[ft:query(mods:note, '$q', $options)]
		        union
		mods:mods[ft:query(mods:subject, '$q', $options)]
		)</field>

	</fields>;

(:
    Default template to be used for form generation if no
    query was specified
:)
declare variable $biblio:TEMPLATE_QUERY :=
    <query>
        <and>
            <field m="1" name="All"></field>
        </and>
    </query>;

(:~
    Regenerate the HTML form to match the query, e.g. after adding more filter
    clauses.
:)
declare function biblio:form-from-query($query as element()) as element()+ {
    let $log := util:log("DEBUG", ("Query: ", $query))
    for $field at $pos in $query//field
    return

            {
                let $operator :=
                    if ($field/preceding-sibling::*) then
                        $field/../local-name(.)
                    else
                        ()
                return
                    <select name="operator{$pos}">
                    { if (empty($operator)) then attribute style { "display: none;" } else () }
                    {
                        for $opt in ("and", "or", "not")
                        return
                            <option>
                            {
                                if ($opt eq $operator) then
                                    attribute selected { "selected" }
                                else
                                    ()
                            }
                            { $opt }
                            </option>
                    }
                    </select>
            }

                <select name="field{$pos}">
                {
                    for $f in $biblio:FIELDS/field
                    return
                        <option>
                            { if ($f/@name eq $field/@name) then attribute selected { "selected" } else () }
                            {$f/@name/string()}
                        </option>
                }
                </select>

                <jquery:input name="input{$pos}" value="{$field/string()}">
                    <jquery:autocomplete url="autocomplete.xql"
                        width="300" multiple="false"
                        matchContains="false"
                        paramsCallback="autocompleteCallback">
                    </jquery:autocomplete>
                </jquery:input>

};

(:~
    Generate an XPath query string from the given XML representation
    of the query.
:)
declare function biblio:generate-query($xml as element()) as xs:string* {
    typeswitch ($xml)
        case element(query) return
            biblio:generate-query($xml/*[1])
        case element(and) return
            (
                biblio:generate-query($xml/*[1]),
                " intersect ",
                biblio:generate-query($xml/*[2])
            )
        case element(or) return
            (
                biblio:generate-query($xml/*[1]),
                " union ",
                biblio:generate-query($xml/*[2])
            )
        case element(not) return
            (
                biblio:generate-query($xml/*[1]),
                " except ",
                biblio:generate-query($xml/*[2])
            )
        case element(field) return
            let $expr0 := $biblio:FIELDS/field[@name = $xml/@name]
            let $expr := if ($expr0) then $expr0 else $biblio:FIELDS/field[last()]
            return
                ($biblio:COLLECTION, replace($expr, '\$q', $xml/string()))
        default return
            ()
};

(:~
    Transform the XML representation of the query into a simple string
    for display to the user in the query history.
:)
declare function biblio:xml-query-to-string($xml as element()) as xs:string* {
    typeswitch ($xml)
        case element(query) return
            biblio:xml-query-to-string($xml/*[1])
        case element(and) return
            (
                biblio:xml-query-to-string($xml/*[1]),
                " AND ",
                biblio:xml-query-to-string($xml/*[2])
            )
        case element(or) return
            (
                biblio:xml-query-to-string($xml/*[1]),
                " OR ",
                biblio:xml-query-to-string($xml/*[2])
            )
        case element(not) return
            (
                biblio:xml-query-to-string($xml/*[1]),
                " NOT ",
                biblio:xml-query-to-string($xml/*[2])
            )
        case element(field) return
            concat($xml/@name, ':', $xml/string())
        default return
            ()
};

(:~
    Process single form parameter. Called from biblio:process-form().
:)
declare function biblio:process-form-parameters($params as xs:string*) as element() {
    let $param := $params[1]
    let $n := substring-after($param, 'input')
    let $value := request:get-parameter($param, "")
    let $field := request:get-parameter(concat("field", $n), 'all')
    let $operator := request:get-parameter(concat("operator", $n), "and")
    return
        if (count($params) eq 1) then
            <field m="{$n}" name="{$field}">{$value}</field>
        else
            element { xs:QName($operator) } {
                biblio:process-form-parameters(subsequence($params, 2)),
                <field m="{$n}" name="{$field}">{$value}</field>
            }
};

(:~
    Process the received form parameters and create an XML representation of
    the query. Filter out empty parameters and take care of boolean operators.
:)
declare function biblio:process-form() as element(query)? {
    let $fields :=
        (:  Get a list of all input parameters which are not empty,
            ordered by input name. :)
        for $param in request:get-parameter-names()[starts-with(., 'input')]
        let $value := request:get-parameter($param, ())
        where string-length($value) gt 0
        order by $param descending
        return
            $param
    return
        if (exists($fields)) then
            (:  process-form recursively calls itself for every parameter and
                generates and XML representation of the query. :)
            <query>
            { biblio:process-form-parameters($fields) }
            </query>
        else
            ()
};

(:~
    Helper function used to sort by name within the "order by"
    clause of the query.
:)
declare function biblio:orderByName($m as element()) as xs:string?
{
    for $name in $m/mods:name[1]
    return
        mods:retrieve-name($name, 1)
};

(: Map order parameter to xpath for order by clause :)
declare function biblio:orderExpr($field as xs:string) as xs:string
{
    if (sort:has-index('mods:name')) then
        if ($field eq "Score") then
            "ft:score($hit) descending"
        else if ($field = "Author") then
            "sort:index('mods:name', $hit)"
        else if ($field = "Title") then
            "sort:index('mods:title', $hit)"
        else
            "sort:index('mods:date', $hit)"
    else
        if ($field eq "Score") then
            "ft:score($hit) descending"
        else if ($field = "Author") then
            "biblio:orderByName($hit)"
        else if ($field = "Title") then
            "$hit/mods:titleInfo[1]/mods:title[1]"
        else
            "$hit/mods:originInfo/mods:dateCreated[1] descending"
};

(:~
    Evaluate the actual XPath query and order the results
:)
declare function biblio:evaluate-query($query as xs:string, $sort as xs:string) {
    let $sortExpr := biblio:orderExpr($sort)
    let $orderedQuery :=
            concat("for $hit in ", $query, " order by ", $sortExpr, " return $hit")
    let $options :=
        <options>
            <default-operator>and</default-operator>
        </options>
    return
        util:eval($orderedQuery)
};

(:~
    Add a query to the user's query history. We store the XML representation
    of the query.
:)
declare function biblio:add-to-history($queryAsXML as element()) {
    let $oldHistory := session:get-attribute('history')
    let $newHistory :=
        let $n := if ($oldHistory) then max(for $n in $oldHistory/query/@n return xs:int($n)) + 1 else 1
        return
            <history>
                <query id="q{$n}" n="{$n}">
                    { $queryAsXML/* }
                </query>
                { $oldHistory/query }
            </history>
    return
        session:set-attribute('history', $newHistory)
};

(:~
    Retrieve a query from the query history
:)
declare function biblio:query-from-history($id as xs:string) {
    let $history := session:get-attribute('history')
    return
        $history/query[@id = $id]
};

(:~
    Returns the query history as a HTML list. The queries are
    transformed into a simple string representation.
:)
declare function biblio:query-history() {

    {
        let $history := session:get-attribute('history')
        for $query at $pos in $history/query
        return

{biblio:xml-query-to-string($query)}

    }

};

(:~
    Evaluate the query given as XML and store its results into the HTTP session
    for later reference.
:)
declare function biblio:eval-query($queryAsXML as element()?) {
    if ($queryAsXML) then
        let $query := string-join(biblio:generate-query($queryAsXML), '')
        let $log := util:log("DEBUG", ("Query: ", $queryAsXML))
        let $sort0 := request:get-parameter("sort", ())
        let $sort := if ($sort0) then $sort0 else session:get-attribute("sort")
        let $results := biblio:evaluate-query($query, $sort)
        (:~ Take the query results and store them into the HTTP session. :)
        let $null := session:set-attribute('mods:cached', $results)
        let $null := session:set-attribute('query', $queryAsXML)
        let $null := session:set-attribute('sort', $queryAsXML)
        let $null := biblio:add-to-history($queryAsXML)
        return
            count($results)
    else
        0
};

(:~
    Clear the last query result.
:)
declare function biblio:clear() {
    let $null := session:remove-attribute('mods:cached')
    let $null := session:remove-attribute('query')
    let $null := session:remove-attribute('sort')
    return
        ()
};

(:~
    Scan the input HTML template and expand the biblio:* tags
    found therein.
:)
declare function biblio:process-templates($query as element(), $hitCount as xs:integer, $node as node()) {
    typeswitch ($node)
        case element(biblio:form-from-query) return
            biblio:form-from-query($query)
        case element(biblio:result-count) return
            text { $hitCount }
        case element(biblio:query-history) return
            biblio:query-history()
        case element() return
            element { node-name($node) } {
                $node/@*,
                for $child in $node/node()
                return
                    biblio:process-templates($query, $hitCount, $child)
            }
        default return
            $node
};

(:~
    Filter an existing result set by applying an additional
    clause with "and".
:)
declare function biblio:apply-filter() {
    let $prevQuery := session:get-attribute("query")
    let $filter := request:get-parameter("filter", ())
    let $value := request:get-parameter("value", ())
    return
        if ($filter = ('All', 'Title') and count($prevQuery/field) eq 1) then
            <query>
                <field>{$prevQuery/field/@name,
                    normalize-space(concat($prevQuery/field/string(), ' ', $value))
                }</field>
            </query>
        else
            <query>
                <and>
                { $prevQuery/* }
                { <field name="{$filter}">{$value}</field> }
                </and>
            </query>
};

session:create(),
(: We receive an HTML template as input :)
let $input := request:get-data()
let $filter := request:get-parameter("filter", ())
let $history := request:get-parameter("history", ())
let $clear := request:get-parameter("clear", ())
let $mylist := request:get-parameter("mylist", ())

(: Process request parameters and generate an XML representation of the query :)
let $queryAsXML :=
    if ($history) then
        biblio:query-from-history($history)
    else if ($clear) then
        biblio:clear()
    else if ($filter) then
        biblio:apply-filter()
    else if ($mylist eq 'display') then
        ()
    else
        biblio:process-form()
(: Evaluate the query :)
let $results :=
    if ($mylist) then (
        if ($mylist eq 'clear') then
            session:set-attribute("personal-list", ())
        else
            (),
        let $list := session:get-attribute("personal-list")
        let $items :=
            for $item in $list/listitem
            return
                util:node-by-id(doc(substring-before($item/@id, '#')), substring-after($item/@id, '#'))
        let $null := session:set-attribute('mods:cached', $items)
        return
            count($items)
    ) else
        biblio:eval-query($queryAsXML)
(:  Process the HTML template received as input :)
let $output :=
    jquery:process-templates(
        biblio:process-templates(if ($queryAsXML) then $queryAsXML else $biblio:TEMPLATE_QUERY, $results, $input)
    )
return
    $output

xquery version "1.0";

(:~
    The core XQuery script for the bibliographic demo. It receives a template XML document
    from the controller and expands it. If a search was trigger by the user, the script
    proceeds as follows:

the input form parameters are transformed into a simple XML structure
            to describe the query

an XPath string is generated from the XML query structure

the XPath is executed and the sort criteria applied

query results, XML query and sort criteria are stored into the HTTP session

the template is expanded, forms are regenerated to match the query

    To apply a filter to an existing query, we just extend the XML representation
    of the query.
:)
import module namespace jquery="http://exist-db.org/xquery/jquery" at "jquery.xql";

declare namespace biblio="http:/exist-db.org/xquery/biblio";

import module namespace mods="http://www.loc.gov/mods/v3" at "retrieve-mods.xql";
import module namespace sort="http://exist-db.org/xquery/sort"
	at "java:org.exist.xquery.modules.sort.SortModule";

declare option exist:serialize "media-type=text/xml omit-xml-declaration=no";

declare variable $biblio:CREDENTIALS := ("biblio", "mods");

declare variable $biblio:COLLECTION := "collection('/db')//";

(:~
    Simple mapping from field names to an XPath expression
:)
declare variable $biblio:FIELDS :=
	<fields>
		<field name="Title">mods:mods[ft:query(mods:titleInfo, '$q', $options)]</field>
		<field name="Author">mods:mods[ft:query(mods:name, '$q', $options)]</field>
		<field name="Date">(mods:mods[ft:query(mods:originInfo/mods:dateCreated, '$q', $options)] union
		  mods:mods[ft:query(mods:originInfo/mods:dateIssued, '$q', $options)])</field>
		<field name="All">(mods:mods[ft:query(mods:titleInfo, '$q', $options)] union
		  mods:mods[ft:query(mods:name, '$q', $options)])
        </field>
	</fields>;

(:
    Default template to be used for form generation if no
    query was specified
:)
declare variable $biblio:TEMPLATE_QUERY :=
    <query>
        <and>
            <field m="1" name="All"></field>
        </and>
    </query>;

(:~
    Regenerate the HTML form to match the query, e.g. after adding more filter
    clauses.
:)
declare function biblio:form-from-query($query as element()) as element()+ {
    let $log := util:log("DEBUG", ("Query: ", $query))
    for $field at $pos in $query//field
    return

            {
                let $operator :=
                    if ($field/preceding-sibling::*) then
                        $field/../local-name(.)
                    else
                        ()
                return
                    <select name="operator{$pos}">
                    { if (empty($operator)) then attribute style { "display: none;" } else () }
                    {
                        for $opt in ("and", "or", "not")
                        return
                            <option>
                            {
                                if ($opt eq $operator) then
                                    attribute selected { "selected" }
                                else
                                    ()
                            }
                            { $opt }
                            </option>
                    }
                    </select>
            }

                <select name="field{$pos}">
                {
                    for $f in $biblio:FIELDS/field
                    return
                        <option>
                            { if ($f/@name eq $field/@name) then attribute selected { "selected" } else () }
                            {$f/@name/string()}
                        </option>
                }
                </select>

                <jquery:input name="input{$pos}" value="{$field/string()}">
                    <jquery:autocomplete url="autocomplete.xql"
                        width="300" multiple="false"
                        matchContains="false"
                        paramsCallback="autocompleteCallback">
                    </jquery:autocomplete>
                </jquery:input>

};

(:~
    Generate an XPath query string from the given XML representation
    of the query.
:)
declare function biblio:generate-query($xml as element()) as xs:string* {
    typeswitch ($xml)
        case element(query) return
            biblio:generate-query($xml/*[1])
        case element(and) return
            (
                biblio:generate-query($xml/*[1]),
                " intersect ",
                biblio:generate-query($xml/*[2])
            )
        case element(or) return
            (
                biblio:generate-query($xml/*[1]),
                " union ",
                biblio:generate-query($xml/*[2])
            )
        case element(not) return
            (
                biblio:generate-query($xml/*[1]),
                " except ",
                biblio:generate-query($xml/*[2])
            )
        case element(field) return
            let $expr0 := $biblio:FIELDS/field[@name = $xml/@name]
            let $expr := if ($expr0) then $expr0 else $biblio:FIELDS/field[last()]
            return
                ($biblio:COLLECTION, replace($expr, '\$q', $xml/string()))
        default return
            ()
};

(:~
    Transform the XML representation of the query into a simple string
    for display to the user in the query history.
:)
declare function biblio:xml-query-to-string($xml as element()) as xs:string* {
    typeswitch ($xml)
        case element(query) return
            biblio:xml-query-to-string($xml/*[1])
        case element(and) return
            (
                biblio:xml-query-to-string($xml/*[1]),
                " AND ",
                biblio:xml-query-to-string($xml/*[2])
            )
        case element(or) return
            (
                biblio:xml-query-to-string($xml/*[1]),
                " OR ",
                biblio:xml-query-to-string($xml/*[2])
            )
        case element(not) return
            (
                biblio:xml-query-to-string($xml/*[1]),
                " NOT ",
                biblio:xml-query-to-string($xml/*[2])
            )
        case element(field) return
            concat($xml/@name, ':', $xml/string())
        default return
            ()
};

(:~
    Process single form parameter. Called from biblio:process-form().
:)
declare function biblio:process-form-parameters($params as xs:string*) as element() {
    let $param := $params[1]
    let $n := substring-after($param, 'input')
    let $value := request:get-parameter($param, "")
    let $field := request:get-parameter(concat("field", $n), 'all')
    let $operator := request:get-parameter(concat("operator", $n), "and")
    return
        if (count($params) eq 1) then
            <field m="{$n}" name="{$field}">{$value}</field>
        else
            element { xs:QName($operator) } {
                biblio:process-form-parameters(subsequence($params, 2)),
                <field m="{$n}" name="{$field}">{$value}</field>
            }
};

(:~
    Process the received form parameters and create an XML representation of
    the query. Filter out empty parameters and take care of boolean operators.
:)
declare function biblio:process-form() as element(query)? {
    let $fields :=
        (:  Get a list of all input parameters which are not empty,
            ordered by input name. :)
        for $param in request:get-parameter-names()[starts-with(., 'input')]
        let $value := request:get-parameter($param, ())
        where string-length($value) gt 0
        order by $param descending
        return
            $param
    return
        if (exists($fields)) then
            (:  process-form recursively calls itself for every parameter and
                generates and XML representation of the query. :)
            <query>
            { biblio:process-form-parameters($fields) }
            </query>
        else
            ()
};

(:~
    Helper function used to sort by name within the "order by"
    clause of the query.
:)
declare function biblio:orderByName($m as element()) as xs:string?
{
    for $name in $m/mods:name[1]
    return
        mods:retrieve-name($name, 1)
};

(: Map order parameter to xpath for order by clause :)
declare function biblio:orderExpr($field as xs:string) as xs:string
{
    if (sort:has-index('mods:name')) then
        if ($field eq "Score") then
            "ft:score($hit) descending"
        else if ($field = "Author") then
            "sort:index('mods:name', $hit)"
        else if ($field = "Title") then
            "sort:index('mods:title', $hit)"
        else
            "sort:index('mods:date', $hit)"
    else
        if ($field eq "Score") then
            "ft:score($hit) descending"
        else if ($field = "Author") then
            "biblio:orderByName($hit)"
        else if ($field = "Title") then
            "$hit/mods:titleInfo[1]/mods:title[1]"
        else
            "$hit/mods:originInfo/mods:dateCreated[1] descending"
};

(:~
    Evaluate the actual XPath query and order the results
:)
declare function biblio:evaluate-query($query as xs:string, $sort as xs:string) {
    let $sortExpr := biblio:orderExpr($sort)
    let $orderedQuery :=
            concat("for $hit in ", $query, " order by ", $sortExpr, " return $hit")
    let $options :=
        <options>
            <default-operator>and</default-operator>
        </options>
    return
        util:eval($orderedQuery)
};

(:~
    Add a query to the user's query history. We store the XML representation
    of the query.
:)
declare function biblio:add-to-history($queryAsXML as element()) {
    let $oldHistory := session:get-attribute('history')
    let $newHistory :=
        let $n := if ($oldHistory) then max(for $n in $oldHistory/query/@n return xs:int($n)) + 1 else 1
        return
            <history>
                <query id="q{$n}" n="{$n}">
                    { $queryAsXML/* }
                </query>
                { $oldHistory/query }
            </history>
    return
        session:set-attribute('history', $newHistory)
};

(:~
    Retrieve a query from the query history
:)
declare function biblio:query-from-history($id as xs:string) {
    let $history := session:get-attribute('history')
    return
        $history/query[@id = $id]
};

(:~
    Returns the query history as a HTML list. The queries are
    transformed into a simple string representation.
:)
declare function biblio:query-history() {

    {
        let $history := session:get-attribute('history')
        for $query at $pos in $history/query
        return

{biblio:xml-query-to-string($query)}

    }

};

(:~
    Evaluate the query given as XML and store its results into the HTTP session
    for later reference.
:)
declare function biblio:eval-query($queryAsXML as element()?) {
    if ($queryAsXML) then
        let $query := string-join(biblio:generate-query($queryAsXML), '')
        let $log := util:log("DEBUG", ("Query: ", $queryAsXML))
        let $sort0 := request:get-parameter("sort", ())
        let $sort := if ($sort0) then $sort0 else session:get-attribute("sort")
        let $results := biblio:evaluate-query($query, $sort)
        (:~ Take the query results and store them into the HTTP session. :)
        let $null := session:set-attribute('mods:cached', $results)
        let $null := session:set-attribute('query', $queryAsXML)
        let $null := session:set-attribute('sort', $queryAsXML)
        let $null := biblio:add-to-history($queryAsXML)
        return
            count($results)
    else
        0
};

(:~
    Clear the last query result.
:)
declare function biblio:clear() {
    let $null := session:remove-attribute('mods:cached')
    let $null := session:remove-attribute('query')
    let $null := session:remove-attribute('sort')
    return
        ()
};

(:~
    Scan the input HTML template and expand the biblio:* tags
    found therein.
:)
declare function biblio:process-templates($query as element(), $hitCount as xs:integer, $node as node()) {
    typeswitch ($node)
        case element(biblio:form-from-query) return
            biblio:form-from-query($query)
        case element(biblio:result-count) return
            text { $hitCount }
        case element(biblio:query-history) return
            biblio:query-history()
        case element() return
            element { node-name($node) } {
                $node/@*,
                for $child in $node/node()
                return
                    biblio:process-templates($query, $hitCount, $child)
            }
        default return
            $node
};

(:~
    Filter an existing result set by applying an additional
    clause with "and".
:)
declare function biblio:apply-filter() {
    let $prevQuery := session:get-attribute("query")
    let $filter := request:get-parameter("filter", ())
    let $value := request:get-parameter("value", ())
    return
        if ($filter = ('All', 'Title') and count($prevQuery/field) eq 1) then
            <query>
                <field>{$prevQuery/field/@name,
                    normalize-space(concat($prevQuery/field/string(), ' ', $value))
                }</field>
            </query>
        else
            <query>
                <and>
                { $prevQuery/* }
                { <field name="{$filter}">{$value}</field> }
                </and>
            </query>
};

session:create(),
(: We receive an HTML template as input :)
let $input := request:get-data()
let $filter := request:get-parameter("filter", ())
let $history := request:get-parameter("history", ())
let $clear := request:get-parameter("clear", ())
let $mylist := request:get-parameter("mylist", ())

(: Process request parameters and generate an XML representation of the query :)
let $queryAsXML :=
    if ($history) then
        biblio:query-from-history($history)
    else if ($clear) then
        biblio:clear()
    else if ($filter) then
        biblio:apply-filter()
    else if ($mylist eq 'display') then
        ()
    else
        biblio:process-form()
(: Evaluate the query :)
let $results :=
    if ($mylist) then (
        if ($mylist eq 'clear') then
            session:set-attribute("personal-list", ())
        else
            (),
        let $list := session:get-attribute("personal-list")
        let $items :=
            for $item in $list/listitem
            return
                util:node-by-id(doc(substring-before($item/@id, '#')), substring-after($item/@id, '#'))
        let $null := session:set-attribute('mods:cached', $items)
        return
            count($items)
    ) else
        biblio:eval-query($queryAsXML)
(:  Process the HTML template received as input :)
let $output :=
    jquery:process-templates(
        biblio:process-templates(if ($queryAsXML) then $queryAsXML else $biblio:TEMPLATE_QUERY, $results, $input)
    )
return
    $output


[FIX] DBA, Logs: send as html5

[FIX] DBA, Logs: send as html5

(:~
 : Logging page.
 :
 : @author Christian Grün, BaseX Team 2005-20, BSD License
 :)
module namespace dba = 'dba/logs';

import module namespace html = 'dba/html' at '../lib/html.xqm';
import module namespace options = 'dba/options' at '../lib/options.xqm';

(:~ Top category :)
declare variable $dba:CAT := 'logs';

(:~
 : Redirects to the URL that creates a log entry table for the specified timestamp.
 : @param  $name  name (date) of log file
 : @param  $time  timestamp to be found
 : @return redirection
 :)
declare
  %rest:GET
  %rest:path('/dba/logs-jump')
  %rest:query-param('name', '{$name}')
  %rest:query-param('time', '{$time}')
function dba:logs-jump(
  $name  as xs:string,
  $time  as xs:string
) as element(rest:response) {
  let $page := head((
    let $ignore-logs := options:get($options:IGNORE-LOGS)
    let $max := options:get($options:MAXROWS)
    for $log at $pos in reverse(
      admin:logs($name, true())[not($ignore-logs and matches(., $ignore-logs, 'i'))]
    )
    where $log/@time = $time
    return ($pos - 1) idiv $max + 1,
    1
  ))
  return web:redirect('/dba/logs', map { 'name': $name, 'page': $page, 'time': $time }) update {
    .//*:header/@value ! (replace value of node . with . || '#' || $time)
  }
};

(:~
 : Logging page.
 : @param  $input  search input
 : @param  $name   name (date) of log file
 : @param  $sort   table sort key
 : @param  $error  error string
 : @param  $info   info string
 : @param  $page   current page
 : @param  $time   timestamp to highlight
 : @return page
 :)
declare
  %rest:GET
  %rest:path('/dba/logs')
  %rest:query-param('input', '{$input}')
  %rest:query-param('name',  '{$name}')
  %rest:query-param('sort',  '{$sort}', '')
  %rest:query-param('error', '{$error}')
  %rest:query-param('info',  '{$info}')
  %rest:query-param('page',  '{$page}', '1')
  %rest:query-param('time',  '{$time}')
  %output:method('html')
function dba:logs(
  $input  as xs:string?,
  $name   as xs:string?,
  $sort   as xs:string,
  $error  as xs:string?,
  $info   as xs:string?,
  $page   as xs:string,
  $time   as xs:string?
) as element(html) {
  let $files := (
    for $file in admin:logs()
    order by $file descending
    return $file
  )
  let $name := if($name) then $name else string(head($files))
  return html:wrap(map { 'header': $dba:CAT, 'info': $info, 'error': $error },

{ html:link('Logs', $dba:CAT) }

        <form action='{ $dba:CAT }' method='post' class='update'>
          <input type='hidden' name='name' id='name' value='{ $name }'/>
          <input type='hidden' name='sort' id='sort' value='{ $sort }'/>
          <input type='hidden' name='page' id='page' value='{ $page }'/>
          <input type='hidden' name='time' id='time' value='{ $time }'/>

{
            let $buttons := html:button('log-delete', 'Delete', true())
            let $headers := (
              map { 'key': 'name', 'label': 'Name', 'type': 'dynamic' },
              map { 'key': 'size', 'label': 'Size', 'type': 'bytes' }
            )
            let $entries :=
              for $entry in reverse(sort($files))
              return map {
                'name': function() {
                  let $link := html:link(
                    $entry, $dba:CAT, (map { 'sort': $sort }, map { 'name': $entry })
                  ) update {
                    (: enrich link targets with current search string :)
                    insert node attribute onclick { 'addInput(this);' } into .
                  }
                  return if ($name = $entry) then element b { $link } else $link
                },
                'size': $entry/@size
              }
            return html:table($headers, $entries, $buttons, map { }, map { })
          }

        </form>

      {
        if($name) then (
          <form action='log-download' method='post' id='resources' autocomplete='off'>

{
              $name, ' ',
              <input type='hidden' name='name' value='{ $name }'/>,
              <input size='40' id='input' name='input' value='{ $input }'
                title='Enter regular expression'
                onkeydown='if(event.keyCode==13) {{logEntries(true,false);event.preventDefault();}}'
                onkeyup='logEntries(false, true);'/>,
              ' ',
              html:button('download', 'Download')
            }

          </form>,

,
          html:js('logEntries(true, false);')
        ) else (),
        html:focus('input')
      }

  )
};

(:~
 : Returns a log entry table.
 : @param  $input  search input
 : @param  $name   name of selected log files
 : @param  $sort   table sort key
 : @param  $page   current page
 : @param  $time   timestamp to highlight
 : @return html elements
 :)
declare
  %rest:POST('{$input}')
  %rest:path('/dba/log')
  %rest:query-param('name', '{$name}')
  %rest:query-param('sort', '{$sort}', 'time')
  %rest:query-param('page', '{$page}', '1')
  %rest:query-param('time', '{$time}')
  %output:method('html')
  %output:html-version('5.0')
  %output:indent('no')
  %rest:single
function dba:log(
  $input  as xs:string?,
  $name   as xs:string,
  $sort   as xs:string,
  $page   as xs:string,
  $time   as xs:string?
) as element()+ {
  let $headers := (
    map { 'key': 'time', 'label': 'Time', 'type': 'dynamic', 'order': 'desc' },
    map { 'key': 'address', 'label': 'Address' },
    map { 'key': 'user', 'label': 'User', 'type': 'dynamic' },
    map { 'key': 'type', 'label': 'Type', 'type': 'dynamic' },
    map { 'key': 'ms', 'label': 'ms', 'type': 'decimal', 'order': 'desc' },
    map { 'key': 'text', 'label': 'Text', 'type': 'dynamic' }
  )
  let $entries := (
    let $ignore-logs := options:get($options:IGNORE-LOGS)
    let $search := boolean($input)
    let $highlight := function($string) {
      for $match in analyze-string($string, $input, 'i')/*
      let $value := string($match)
      return if(local-name($match) = 'match') then element b { $value } else $value
    }

    for $log in reverse(admin:logs($name, true()))
    let $user := string($log/@user)
    let $type := string($log/@type)
    let $text := string($log)
    let $user-hit := $search and matches($user, $input, 'iq')
    let $type-hit := $search and not($user-hit) and matches($type, $input, 'iq')
    let $text-hit := $search and not($user-hit or $type-hit) and matches($text, $input, 'i')
    where (not($search) or $user-hit or $type-hit or $text-hit) and (
      not($ignore-logs and matches($text, $ignore-logs, 'i'))
    )
    let $id := string($log/@time)
    let $time := if($input or $sort != 'time') then (
      function() { html:link($id, $dba:CAT || '-jump', map { 'name': $name, 'time': $id }) }
    ) else if($id = $time) then (
      element b { $id }
    ) else (
      $id
    )
    return map {
      'id': $id,
      'time': $time,
      'address': string($log/@address),
      'user': if($user-hit) then function() { $highlight($user) } else $user,
      'type': if($type-hit) then function() { $highlight($type) } else $type,
      'ms': xs:decimal($log/@ms),
      'text': if($text-hit) then function() { $highlight($text) } else $text
    }
  )
  let $params := map { 'name': $name, 'input': $input }
  let $options := map { 'sort': $sort, 'presort': 'time', 'page': xs:integer($page) }
  return html:table($headers, $entries, (), $params, $options)
};

(:~
 : Redirects to the specified action.
 : @param  $action  action to perform
 : @param  $names   names of selected log files
 : @return redirection
 :)
declare
  %rest:POST
  %rest:path('/dba/logs')
  %rest:query-param('action', '{$action}')
  %rest:query-param('name',   '{$names}')
function dba:logs-redirect(
  $action  as xs:string,
  $names   as xs:string*
) as element(rest:response) {
  web:redirect($action, map { 'name': $names[.], 'redirect': $dba:CAT })
};

(:~
 : Logging page.
 :
 : @author Christian Grün, BaseX Team 2005-20, BSD License
 :)
module namespace dba = 'dba/logs';

import module namespace html = 'dba/html' at '../lib/html.xqm';
import module namespace options = 'dba/options' at '../lib/options.xqm';

(:~ Top category :)
declare variable $dba:CAT := 'logs';

(:~
 : Redirects to the URL that creates a log entry table for the specified timestamp.
 : @param  $name  name (date) of log file
 : @param  $time  timestamp to be found
 : @return redirection
 :)
declare
  %rest:GET
  %rest:path('/dba/logs-jump')
  %rest:query-param('name', '{$name}')
  %rest:query-param('time', '{$time}')
function dba:logs-jump(
  $name  as xs:string,
  $time  as xs:string
) as element(rest:response) {
  let $page := head((
    let $ignore-logs := options:get($options:IGNORE-LOGS)
    let $max := options:get($options:MAXROWS)
    for $log at $pos in reverse(
      admin:logs($name, true())[not($ignore-logs and matches(., $ignore-logs, 'i'))]
    )
    where $log/@time = $time
    return ($pos - 1) idiv $max + 1,
    1
  ))
  return web:redirect('/dba/logs', map { 'name': $name, 'page': $page, 'time': $time }) update {
    .//*:header/@value ! (replace value of node . with . || '#' || $time)
  }
};

(:~
 : Logging page.
 : @param  $input  search input
 : @param  $name   name (date) of log file
 : @param  $sort   table sort key
 : @param  $error  error string
 : @param  $info   info string
 : @param  $page   current page
 : @param  $time   timestamp to highlight
 : @return page
 :)
declare
  %rest:GET
  %rest:path('/dba/logs')
  %rest:query-param('input', '{$input}')
  %rest:query-param('name',  '{$name}')
  %rest:query-param('sort',  '{$sort}', '')
  %rest:query-param('error', '{$error}')
  %rest:query-param('info',  '{$info}')
  %rest:query-param('page',  '{$page}', '1')
  %rest:query-param('time',  '{$time}')
  %output:method('html')
function dba:logs(
  $input  as xs:string?,
  $name   as xs:string?,
  $sort   as xs:string,
  $error  as xs:string?,
  $info   as xs:string?,
  $page   as xs:string,
  $time   as xs:string?
) as element(html) {
  let $files := (
    for $file in admin:logs()
    order by $file descending
    return $file
  )
  let $name := if($name) then $name else string(head($files))
  return html:wrap(map { 'header': $dba:CAT, 'info': $info, 'error': $error },

{ html:link('Logs', $dba:CAT) }

        <form action='{ $dba:CAT }' method='post' class='update'>
          <input type='hidden' name='name' id='name' value='{ $name }'/>
          <input type='hidden' name='sort' id='sort' value='{ $sort }'/>
          <input type='hidden' name='page' id='page' value='{ $page }'/>
          <input type='hidden' name='time' id='time' value='{ $time }'/>

{
            let $buttons := html:button('log-delete', 'Delete', true())
            let $headers := (
              map { 'key': 'name', 'label': 'Name', 'type': 'dynamic' },
              map { 'key': 'size', 'label': 'Size', 'type': 'bytes' }
            )
            let $entries :=
              for $entry in reverse(sort($files))
              return map {
                'name': function() {
                  let $link := html:link(
                    $entry, $dba:CAT, (map { 'sort': $sort }, map { 'name': $entry })
                  ) update {
                    (: enrich link targets with current search string :)
                    insert node attribute onclick { 'addInput(this);' } into .
                  }
                  return if ($name = $entry) then element b { $link } else $link
                },
                'size': $entry/@size
              }
            return html:table($headers, $entries, $buttons, map { }, map { })
          }

        </form>

      {
        if($name) then (
          <form action='log-download' method='post' id='resources' autocomplete='off'>

{
              $name, ' ',
              <input type='hidden' name='name' value='{ $name }'/>,
              <input size='40' id='input' name='input' value='{ $input }'
                title='Enter regular expression'
                onkeydown='if(event.keyCode==13) {{logEntries(true,false);event.preventDefault();}}'
                onkeyup='logEntries(false, true);'/>,
              ' ',
              html:button('download', 'Download')
            }

          </form>,

,
          html:js('logEntries(true, false);')
        ) else (),
        html:focus('input')
      }

  )
};

(:~
 : Returns a log entry table.
 : @param  $input  search input
 : @param  $name   name of selected log files
 : @param  $sort   table sort key
 : @param  $page   current page
 : @param  $time   timestamp to highlight
 : @return html elements
 :)
declare
  %rest:POST('{$input}')
  %rest:path('/dba/log')
  %rest:query-param('name', '{$name}')
  %rest:query-param('sort', '{$sort}', 'time')
  %rest:query-param('page', '{$page}', '1')
  %rest:query-param('time', '{$time}')
  %output:method('html')
  %output:indent('no')
  %rest:single
function dba:log(
  $input  as xs:string?,
  $name   as xs:string,
  $sort   as xs:string,
  $page   as xs:string,
  $time   as xs:string?
) as element()+ {
  let $headers := (
    map { 'key': 'time', 'label': 'Time', 'type': 'dynamic', 'order': 'desc' },
    map { 'key': 'address', 'label': 'Address' },
    map { 'key': 'user', 'label': 'User', 'type': 'dynamic' },
    map { 'key': 'type', 'label': 'Type', 'type': 'dynamic' },
    map { 'key': 'ms', 'label': 'ms', 'type': 'decimal', 'order': 'desc' },
    map { 'key': 'text', 'label': 'Text', 'type': 'dynamic' }
  )
  let $entries := (
    let $ignore-logs := options:get($options:IGNORE-LOGS)
    let $search := boolean($input)
    let $highlight := function($string) {
      for $match in analyze-string($string, $input, 'i')/*
      let $value := string($match)
      return if(local-name($match) = 'match') then element b { $value } else $value
    }

    for $log in reverse(admin:logs($name, true()))
    let $user := string($log/@user)
    let $type := string($log/@type)
    let $text := string($log)
    let $user-hit := $search and matches($user, $input, 'iq')
    let $type-hit := $search and not($user-hit) and matches($type, $input, 'iq')
    let $text-hit := $search and not($user-hit or $type-hit) and matches($text, $input, 'i')
    where (not($search) or $user-hit or $type-hit or $text-hit) and (
      not($ignore-logs and matches($text, $ignore-logs, 'i'))
    )
    let $id := string($log/@time)
    let $time := if($input or $sort != 'time') then (
      function() { html:link($id, $dba:CAT || '-jump', map { 'name': $name, 'time': $id }) }
    ) else if($id = $time) then (
      element b { $id }
    ) else (
      $id
    )
    return map {
      'id': $id,
      'time': $time,
      'address': string($log/@address),
      'user': if($user-hit) then function() { $highlight($user) } else $user,
      'type': if($type-hit) then function() { $highlight($type) } else $type,
      'ms': xs:decimal($log/@ms),
      'text': if($text-hit) then function() { $highlight($text) } else $text
    }
  )
  let $params := map { 'name': $name, 'input': $input }
  let $options := map { 'sort': $sort, 'presort': 'time', 'page': xs:integer($page) }
  return html:table($headers, $entries, (), $params, $options)
};

(:~
 : Redirects to the specified action.
 : @param  $action  action to perform
 : @param  $names   names of selected log files
 : @return redirection
 :)
declare
  %rest:POST
  %rest:path('/dba/logs')
  %rest:query-param('action', '{$action}')
  %rest:query-param('name',   '{$names}')
function dba:logs-redirect(
  $action  as xs:string,
  $names   as xs:string*
) as element(rest:response) {
  web:redirect($action, map { 'name': $names[.], 'redirect': $dba:CAT })
};


Repaired html/admin/browse.....

Repaired html/admin/browse.....

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

(:
    Module: functions for formatting an xs:dateTime value.
:)
module namespace date="http://exist-db.org/xquery/admin-interface/date";

declare variable $date:months {
	("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
	"Nov", "Dec")
};

declare function date:format-date($date as xs:dateTime) as xs:string {
	string-join((
		item-at($date:months, month-from-date($date)),
		xs:string( day-from-date($date)  ),
		xs:string( year-from-date($date) ) ), " ")
};

declare function date:format-int($component as xs:integer) as xs:string {
	if($component lt 10) then
		concat("0", $component)
	else
		xs:string($component)
};

declare function date:format-time($time as xs:dateTime) as xs:string {
	concat(
		date:format-int(hours-from-dateTime($time)), ":",
		date:format-int(minutes-from-dateTime($time)), ":",
		date:format-int(xs:integer(seconds-from-dateTime($time)))
	)
};

declare function date:format-dateTime($dt as xs:dateTime) as xs:string {
    concat(date:format-date($dt), " ", date:format-time($dt))
};

(:
    Module: functions for formatting an xs:dateTime value.
:)
module namespace date="http://exist-db.org/xquery/admin-interface/date";

declare variable $date:months {
	("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
	"Nov", "Dec")
};

declare function date:format-date($date as xs:dateTime) as xs:string {
	string-join((
		item-at($date:months, month-from-date($date)),
		day-from-date($date),
		year-from-date($date)), " ")
};

declare function date:format-int($component as xs:integer) as xs:string {
	if($component lt 10) then
		concat("0", $component)
	else
		xs:string($component)
};

declare function date:format-time($time as xs:dateTime) as xs:string {
	concat(
		date:format-int(hours-from-dateTime($time)), ":",
		date:format-int(minutes-from-dateTime($time)), ":",
		date:format-int(xs:integer(seconds-from-dateTime($time)))
	)
};

declare function date:format-dateTime($dt as xs:dateTime) as xs:string {
    concat(date:format-date($dt), " ", date:format-time($dt))
};


Updated search

Updated search

xquery version "3.0";
(: module namespace :)
module namespace search="http://xqueryinstitute.org/search";

(: Templating modules :)
import module namespace templates="http://exist-db.org/xquery/templates" ;
import module namespace config="http://localhost:8080/exist/apps/xq-institute/config" at "config.xqm";
import module namespace facets="http://xqueryinstitute.org/facets" at "facets.xqm";
(: Import KWIC module for keyword in context display :)
import module namespace kwic="http://exist-db.org/xquery/kwic" at "resource:org/exist/xquery/lib/kwic.xql";
(: Namespaces used by query :)
declare namespace util="http://exist-db.org/xquery/util";
declare namespace tei="http://www.tei-c.org/ns/1.0";
declare namespace xqi="http://xqueryinstitute.org/ns";

(: Parameters :)
declare variable $search:term {request:get-parameter('term','') cast as xs:string};
declare variable $search:field {request:get-parameter('field','') cast as xs:string};
declare variable $search:start {request:get-parameter('start',1) cast as xs:integer};
declare variable $search:records {request:get-parameter('records',10) cast as xs:integer};
(: Facet parameters:)
declare variable $search:play {request:get-parameter('play','') cast as xs:string};
declare variable $search:speaker {request:get-parameter('speaker','') cast as xs:string};
declare variable $search:genre {request:get-parameter('genre','') cast as xs:string};
declare variable $search:performed {request:get-parameter('performed','') cast as xs:string};
declare variable $search:date {request:get-parameter('date','') cast as xs:string};

(:~
 : Construct search string for evaluation
 : NOTE retool to add query node
:)
declare function search:build-search-path(){
if($search:field != '') then
        if($search:field = 'title') then
            concat("//tei:titleStmt/tei:title[ft:query(.,'",$search:term,"')]")
        else if($search:field = 'sp') then
            concat("//tei:sp[ft:query(.,'",$search:term,"')]")
        else if($search:field = 'stage') then
            concat("//tei:stage[ft:query(.,'",$search:term,"')]")
        else ()
    else concat("//tei:body[ft:query(.,'",$search:term,"')]")
};

(:~
 : String for facet evaluation
 : not needed?
:)
declare function search:build-facet-path(){
    if($search:field != '') then
        if($search:field = 'title') then concat("ancestor::tei:TEI/tei:titleStmt/tei:title[ft:query(.,'",$search:term,"')]")
        else if($search:field = 'sp') then concat("ancestor::tei:sp[ft:query(.,'",$search:term,"')]")
        else if($search:field = 'stage') then concat("ancestor::tei:stage[ft:query(.,'",$search:term,"')]")
        else ()
    else concat("ancestor::tei:TEI//tei:body[ft:query(.,'",$search:term,"')]")
};

declare function search:add-facets() as xs:string*{
let $title-facet :=
    if($search:play) then
        concat("[ancestor::tei:TEI//tei:titleStmt/tei:title"," = '",$search:play,"']")
    else ()
let $speaker-facet :=
    if($search:speaker) then
        concat("[ancestor::tei:TEI//tei:speaker"," = '",$search:speaker,"']")
    else ()
let $genre-facet :=
    if($search:genre) then
        concat("[ancestor::tei:TEI//xqi:genre"," = '",$search:genre,"']")
    else ()
let $performed-facet :=
    if($search:performed) then
        concat("[ancestor::tei:TEI//xqi:performed"," = '",$search:performed,"']")
    else ()
let $date-facet :=
    if($search:date) then
        concat("[ancestor::tei:TEI//tei:date"," = '",$search:date,"']")
    else ()
return
    concat($title-facet,$speaker-facet,$genre-facet,$performed-facet,$date-facet)
};

declare function search:decode-facets(){
let $title-facet :=
    if($search:play) then
        concat("Title: ",$search:play," ")
    else ()
let $speaker-facet :=
    if($search:speaker) then
        concat("Speaker: ",$search:speaker," ")
    else ()
let $genre-facet :=
    if($search:genre) then
        concat("Genre: ",$search:genre," ")
    else ()
let $performed-facet :=
    if($search:performed) then
        concat("Performed: ",$search:performed," ")
    else ()
let $date-facet :=
    if($search:date) then
        concat("Date: ",$search:date," ")
    else ()
return
    concat($title-facet,$speaker-facet,$genre-facet,$performed-facet,$date-facet)
};

(:~
 : Helper function: create a lucene query from the user input
 : Tests for quotes in input to create phrase or near matches
:)
declare %private function search:create-query() {
    <query>
        {
            if (starts-with($search:term,'"')) then
                <phrase>{$search:term}</phrase>
            else
                <near>{$search:term}</near>
        }
    </query>
};

(:~
 : Function developed by @joewiz for faster rendering of KWIC
:)
declare function search:milestone-chunk(
     $ms1 as element(),
     $ms2 as element(),
     $node as node()*) as node()*
{
    typeswitch ($node)
    case element() return
        if ($node is $ms1) then
            $node
        else if ( some $n in $node/descendant::* satisfies ($n is $ms1 or $n is $ms2) ) then
            element { name($node) }
                {
                for $i in ( $node/node())
                return
                    search:milestone-chunk($ms1, $ms2, $i)
                }
        else if ( $node >> $ms1 and $node << $ms2 ) then
            $node
        else ()
    default return
        if ( $node >> $ms1 and $node << $ms2 ) then
            $node
        else ()
};

(:~
 : Function developed by @joewiz for faster rendering of KWIC
:)
declare function search:trim-matches($node, $keep) {
let $matches := $node//exist:match
return
    if (count($matches) le $keep) then
        $node
    else
        search:milestone-chunk(subsequence($matches, 1, 1), subsequence($matches, $keep, 1), $node)
};

(:~
 : Output search results using KWIC
:)
declare function search:simple() as node()*{
    let $path := concat("collection('/db/apps/xq-institute/data/indexed-plays')",search:build-search-path(),search:add-facets())
    let $query-string := search:build-facet-path()
    let $hits := util:eval($path)
    let $total-hits := count($hits)
    return

         {facets:facets($hits)}

                    {search:paging($hits, $total-hits)}
                    {search:decode-facets()}

                {
                 for $hit at $p in subsequence($hits, $search:start, $search:records)
                 let $uri := base-uri($hit)
                 let $title := $hit/ancestor::tei:TEI//tei:titleStmt/tei:title/text()
                 let $matches-to-highlight := 2
                 let $trimmed-hit := search:trim-matches(util:expand($hit),$matches-to-highlight)
                 let $summary := kwic:summarize($trimmed-hit, <config xmlns="" width="60"/>)
                 return

{$title}

{$summary}

                }

};

(:~
 : Build paging function for search results
 : @param $search:start passed from url
 : @param $hits passed from search:simple()
 : NOTE add test to deactive next and prev if at begining or end
:)
declare function search:paging($hits as node()*, $total-hits as xs:integer*) as node(){
(: get all parameters to pass to paging function, minus start param :)
let $url-params := replace(request:get-query-string(), '&start=\d+', '')
let $start := if($search:start) then $search:start else 1
let $next :=  Next
let $prev :=  Prev
let $end :=
    if ($total-hits lt $search:records) then
        $total-hits
    else
        if(($start + $search:records)  - 1 gt $total-hits) then $total-hits
        else ($start + $search:records)  - 1
let $field-name :=
    if($search:field = 'sp') then 'speech'
    else if($search:field = 'stage') then 'stage directions'
    else if($search:field = 'title') then 'title'
    else 'keywords'
return

{$total-hits} results for: {$search:term} {if($search:field) then concat(' in ',$field-name) else ''}

            {
                if(($start - $search:records) lt 1) then Prev
                else $prev
                }

{$search:start} to {$end} of {$total-hits}

            {
             if($start + $search:records lt $total-hits) then $next
                    else Next
            }

};

declare %templates:wrap function search:display-results($node as node(), $model as map(*)){
 if($search:term !='') then
    search:simple()
 else ()
};