<%
// Copyright (C) 2002-2008 Nokia. All rights reserved.
//
// This document may be copied, published, and distributed, without restriction
// of any kind, provided it is not modified in any way.
//
// THIS DOCUMENT IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, 
// EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT
// THE DOCUMENT IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE 
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND USABILITY OF THIS
// DOCUMENT IS WITH YOU. SHOULD THIS DOCUMENT PROVE DEFECTIVE IN ANY RESPECT, 
// YOU (NOT NOKIA, ITS LICENSORS OR AFFILIATES OR ANY OTHER CONTRIBUTOR) ASSUME
// THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION.
//
// Author: Patrick Stickler (patrick.stickler@nokia.com)
//
// Description: 
//
// Revisions:
//
//

Server.Security.impersonateUser("$PACKAGE_USER");

import "/uriqa/URIQA.rsa";
import "f_query.rsp";
import "/schemas/namespaces.rsa";
import "/schemas/rules.rsa";

USE URIQA;

//profile on;

var MAX_COMPLEXITY = 15000000;


Session.codepage = 65001;
Response.charset = "UTF-8";
Session.commandTimeout=1500;
Session.maxQueryComplexity=MAX_COMPLEXITY;
//Session.transactionTimeout=999;

var fnServerURL = "http://forum.nokia.com/info/";
var res_count = 0;

var query	= Request["rdfql"];
var limit	= Request["limit"];
var format	= Request["format"];
var inference	= Request["inference"];

var facets	= Request["facets"];
var mandatoryFacets = Request["mandatory-facets"];
var match_param	= Request["match"];
var sortBy	= Request["sortby"];
var q_index	= Request["index"];


var spacenames  = new Array();
for (var iter = new Enumerator(Session.namespaces); !iter.atEnd; iter.moveNext())
	spacenames[iter.item]=iter.key;

if ((limit==null)||(limit=="")||(limit==0))
	limit=50;                             //Default limit value

if ((format==null)||(format=="")||(format=="null"))
	format="application/rss";             //Definition of default format. The default format is application/rss

if (inference!="include")
	inference="exclude";                  //Definition of default inference value

if (q_index == null || q_index < 0)
	q_index = 0;

//query is either a facet query, a regular query, or not specified (in whihc case we show a form)
if ((!isEmpty(mandatoryFacets))||(!isEmpty(facets)))
	processFacetQuery();
else if ((query==null)||(query=="")||(query=="null"))
	import "/query/form.rsp";
else
    processQuery();



////////////////////////////////////////////////////////////////////////////////////////////////
//
//


function repall (s, pat, rep) 
{
   	var o=String(s);
   	while (o.match (pat) !=null) o=o.replace (pat,rep);
   		return (o);
}

function fixns (r) 
{
	var sc=uripart ('schema', resource(r));
   	if (sc != null) 
	{
		prefix=spacenames[sc]
	    if (prefix!=null) 
		{
			var part = uripart ('fragment', resource(r))
			if (part=="") 
			{
		    	var rex=new regexp ("/([^/]*$)", "gi");
		    	var a= rex.exec(String(r));
		    	part=a[1];
			}
		
			return (prefix+":"+part);
	    }
	    else return (r)
    }
    else return (r);
}

function lineout (s)            // leaving out the end of line characters
{
	return s.replace("\n", " ").replace("\r", " ")
}

function doWaitProcessing()     //Showing progressing page before display the results of request
{
    if ((format=="text/html")&&(request['redirected'] != "yes"))
	{
%>
		<html>
		<head>
		<META HTTP-EQUIV="Refresh"
      		CONTENT="0;URL=<%=(Request.serverVariables["REQUEST_PATH"] + "?" + Request.serverVariables["QUERY_STRING"].replace(new RegExp("&redirected=[A-Za-z0-9]*\\&?", "g"),"") + "&redirected=yes")%>">
		</head>
		<body><h1>Please wait for Forum Nokia to execute your search . . . </h1></body>
		<P>
If your browser doesn't support redirection use<A HREF="<%=(Request.serverVariables["REQUEST_PATH"] + "?" + Request.serverVariables["QUERY_STRING"]+"&redirected=yes")%>" > this link</A>.
		</html>
		<%
		response.end();
	}	
}

function writeHTMLDescribeList(listRscURI,inference, query)
{
    Response.write ("Your query: <b><p>");

	var s1=String(request['rdfql']);
	var s2=repall(s1, "\n", "<br>");
	s2=repall(s2, " ", "&nbsp;");
	if(isEmpty(s2))
		response.write (query);
	else
		response.write (s2);
    	response.write ("</b>");
	
	%><p><%

	if (limit==-1)
		response.write (listRscURI.count + " matches found; ");

	if ((listRscURI.count < limit)||(limit==-1)) 
		response.write (listRscURI.count);
	    else  
		response.write (limit);
	        response.write ( " displayed.");
	 
	%><p><%

	for (var i = 0; i < listRscURI.count; i++)
	{
		var description = getDescription(listRscURI[i], inference); 
		var title = getTitle(listRscURI[i], description);
		var textDesc = getTextDescription(listRscURI[i], description);
		var rsrcDate = getRsrcDate(listRscURI[i]);
		var rsrcLang = getRsrcLang(listRscURI[i]);
//		var rsrcType = getRsrcType(listRscURI[i]);
		var rsrcEncoding = getRsrcEncoding(listRscURI[i]);

		var date_re = new RegExp("([0-9-]*)[T]*", "gi");
		
		rsrcDate = date_re.exec(rsrcDate);

		if (rsrcDate != "---")
			rsrcDate = rsrcDate[1];
	
		var typeListString = "";

		var typeList= new Array();
			typeList=getRsrcType(listRscURI[i]);

		for (var n = 0; n < typeList.length; n++)
		{	typeListString = typeListString + " " + typeList[n];
			if (n<typeList.length-1)
			{
				typeListString=typeListString + ",";
			}
		}

		if (typeListString == "")
			typeListString="---";


		var topicsListString = "";

		var topicsList= new Array();
			topicsList=getTopics(listRscURI[i]);

		for (var n = 0; n < topicsList.length; n++)
		{	topicsListString = topicsListString + " " + topicsList[n];
			if (n<topicsList.length-1)
			{
				topicsListString=topicsListString + ",";
			}
		}

		if (topicsListString == "")
			topicsListString="---";
		
		
		var loc = new String(listRscURI[i]);
	
		var re= RegExp("^http://sw.nokia.com/id", "gi");

		var results = re.exec(loc);
		if (results!=null)
		{
			if (isWebPageRsrc(listRscURI[i]))
			{	//if type = WebPage or encoding = online_document_package href is the same as URI 

				Response.write("<p><b><a href=\"" + listRscURI[i] + "\">" + title + 
				   "</a></b><br/>" + textDesc + "<br/>" + typeListString + "; " + topicsListString + "; " + rsrcEncoding + "; " + rsrcLang + " </br><i>" + rsrcDate  + "</i></p><p></p>");
			}
			else
			{ //If fn:type is Terminal use developer and consumer link property
				if (isTerminal(listRscURI[i]))
				{
					Response.write("<p><b><a href=\"" + urlTerminal(listRscURI[i]) + "\">" + title + 
							"</a></b><br/>" + textDesc + "<br/>" + typeListString + "; " + topicsListString + "; " + rsrcEncoding + "; " + rsrcLang + " </br><i>" + rsrcDate  + "</i></p><p></p>");
				}
				else
				{
					Response.write("<p><b><a href=\"" + fnServerURL + loc.substring(7,loc.length) + ".html\" >" + title + 
						   "</a></b><br/>" + textDesc + "<br/>" + typeListString + "; " + topicsListString + "; " + rsrcEncoding + "; " + rsrcLang + " </br><i>" + rsrcDate  + "</i></p><p></p>");
				}
			}
		}	
		else
		//output with link to the infoPage http://forum.nokia.com+ uri + .html 
		{
			Response.write("<p><b><a href=\"" + fnServerURL + loc.substring(7,loc.length) + ".html\" >" + title + 
				   "</a></b><br/>" + textDesc + "<br/>" + typeListString + "; " + topicsListString + "; " + rsrcEncoding + "; " + rsrcLang + " </br><i>" + rsrcDate  + "</i></p><p></p>");
		}
//			Response.write("<p><b><a href=\"/uriqa?uri=" + listRscURI[i] + "&format=text/html\" >" + title + 
//			       "</a></b><br/>" + textDesc + "<br/>" + rsrcType + "; " + topicsListString + "; " + rsrcEncoding + "; " + rsrcLang + " </br><i>" + rsrcDate  + "</i></p><p></p>");
	}	
}

function urlTerminal(rsrcURI)
{
	var rsrc = new Resource (rsrcURI);

	var result = (SELECT ?link USING managedKB
		RULEBASE AllData
		WHERE {[http://sw.nokia.com/FN-1/type] #rsrc [http://sw.nokia.com/FN-1/Type/Terminal]}
		AND 
		( {[http://sw.nokia.com/DP-1/consumer_link] #rsrc ?con_link}
		AND ?link=?con_link
		)
		OR
		( {[http://sw.nokia.com/DP-1/developer_link] #rsrc ?dev_link}
		AND ?link=?dev_link
		)
	);

	return(result["link"]);

}	

function isTerminal(rsrcURI)
{
	var rsrc = new Resource (rsrcURI);
	var type = (SELECT ?eq USING managedKB
		RULEBASE AllData
		WHERE {[http://sw.nokia.com/FN-1/type] #rsrc ?type}
		AND strcmpi(?type, "http://sw.nokia.com/FN-1/Type/Terminal") = 0
		AND ?eq=0);
 
	if (type["eq"]=="0")
		return(true);
	else
		return(false);
}

function isWebPageRsrc(rsrcURI)
{
   var rsrc = new Resource (rsrcURI);
   var type = (SELECT ?eq
			USING  expandedKB
			RULEBASE  AllData
			WHERE {[fn:type] #rsrc [http://sw.nokia.com/FN-1/Type/Webpage]}
		 );			 
		 
	if (type.recordCount > 0) 
		return (true); 
	else
		return(false);
}

function writeCSV(q)
{
	var re 	= new RegExp("[?]([a-zA-Z0-9_-]*) ", "gi");
	var sre=new RegExp ("select *(.*) *using", "gi");
	var s = q.match (sre);
	s=String(s[1])+" ";

	eval ("var answer = ("+q+");");

	Response.contentType=format;
	Response.addHeader("Content-disposition","attachment; filename=\"results.csv\"");
	Response.charset="UTF-8";

   	var nvars=0;
	var headers=new Array();

	if (limit==-1)
		limit=answer.recordCount;

	for (var results = re.exec(s); results != null; results = re.exec(s))
	{
		headers[nvars]=xmlString(results[1]);
		nvars++;
	}

	Response.write(headers.join(",")+"\n");
	var rows=0;    
		
	while (!answer.EOF && rows<limit) 
	{
		var content=new Array();

		for (var i=0; i<nvars; i++)
		{
			var rex=new regexp ("\"", "gi");
			var value=new String(answer[i]);
			content[i]=xmlString(value.replace(rex,"\"\""));
		}
		Response.write("\""+content.join("\",\"")+"\"\n");
		
		rows++;	    
		answer.moveNext();
	}
}

function getVars(query)
{
	var re = new regexp("select(.*)using", "i");
	var res = re.exec(query);
	var vars = res[0];
	var reVars = new regexp("\\?([a-z]+)", "gi");
	var ary = new Array();

	for (res = reVars.exec(vars); res != null; res=reVars.exec(vars))
		ary[ary.length] = res[1];

	return ary;
}


//According to the specified DESCRIBE query, the list of resources should be extracted, which suites to this request. Instead of Producing the list of resources according to the specified query. Afterwords this list will be used by the 

function getURIList(form_query)
{
	var listURI	= new Array();
	var nvals	= 0;
	var q		= "";
	var re 		= new RegExp("[?]([a-zA-Z0-9_-]*) ", "gi");
	var sre		= new RegExp ("select *(.*) *using", "gi");
	var s 		= form_query.match(sre); 
	
	s = String(s[1]) + " ";

	var order_re = new RegExp("order by", "i");
	var order    = form_query.search(order_re);

	var rs;

	var sorted = null;

	if (!(order > -1))
	{
		var aryVars = getVars(form_query);
		var reusing	= new RegExp (".*(using.*)where", "gi");
		var res 	= reusing.exec(form_query);
		var sources = res[1];

		if (limit != -1 && aryVars.length == 1)
			session.maxQueryComplexity = 1500000;

		try
		{
			//first try to eval as written
			eval (form_query + " with stats");

			var stats = Error.lastError.description;
			rs = response.results;

			var reStats = new regexp("Complexity:([0-9]*)");
			var res = reStats.exec(stats);

			Response.appendToLog("Query Complexity: " + res[1]);
		}
		catch(e)
		{
			if (e.number != 205)
				throw e;

//			Response.appendToLog("Query Complexity Exceeeded: " + session.maxQueryComplexity + " (will retry querying recent items)");

			//set back to normla complexity
			Session.maxQueryComplexity=MAX_COMPLEXITY;


			//if the first was too complex, eval over recent items only
			sorted = evalOverRecentItems(form_query, aryVars[0], sources, limit + (q_index != -1?q_index:0));
		}
		
		if (sorted == null)	
		{
			var vars = "";
			for (var i=0; i<rs.ColumnCount; i++)
				vars += (i>0?", ":"") + "?" + rs.GetColumnName(i);

			
			//special case large describe resultsets
			if (rs.recordCount > 10000 && rs.ColumnCount == 1 && limit != -1)
			{
				sorted = getRecentItems(rs, sources, limit + (q_index != -1?q_index:0));
			}
			else
			{
				for (var i=0; i<rs.ColumnCount; i++)
				{
					if (typeof(rs[i]) == "resource")
					{
						q = "select " + vars + ", ?date_of_the_resource " + sources + " WHERE resultset(#rs, " + vars + ")";
						q +=" AND SWITCH(?" + rs.GetColumnName(i) + ")"+
							"(CASE {[fn:published] ?"+rs.GetColumnName(i)+" ?l}: ?date_of_the_resource=?l AND ?date_field_name='published'"+
							"CASE {[dcterms:issued] ?"+rs.GetColumnName(i)+" ?l}: ?date_of_the_resource=?l AND ?date_field_name='issued'"+
							"CASE {[dc:date] ?"+ rs.GetColumnName(i)+" ?l}: ?date_of_the_resource=?l AND ?date_field_name='date'"+
							"DEFAULT:  ?date_of_the_resource = ''"+
							") ORDER BY ?date_of_the_resource DESC, ?" + rs.GetColumnName(i);

						break;		
					}
				}
			}
		}
	}

	if (sorted == null)
	{
		if (q != "")
			eval ("sorted = ("+q+");");	
		else
			eval("sorted = (" + form_query + ");");
	}

	if (q_index > 0)
		sorted.move(q_index-1);

	var c=0;
	while (!sorted.EOF && (c < limit || limit==-1)) 
	{ 
		for (var vars = re.exec(s); vars != null; vars = re.exec(s)) 
		{ 
			try 
			{
				if ((typeof sorted[vars[1]])== "resource")
				{
					listURI[c] = sorted[vars[1]];
					c++;
				}
			} 
			catch (e)
			{
				response.write("Warning!" + e); // do nothing
			}
		}  

		sorted.moveNext();
	}

	return(listURI);
}


function evalOverRecentItems(query, svar, sources, limit)
{
	var ds = new datasource()

	var n = -1;

	query = query.replace(new regexp("\\?" + svar, "g"), "?item");

	var reCond	= new RegExp (".*where(.*)", "gi");
	var res = reCond.exec(query);
	query = res[1];

	var dtNow = new Date();
	var dtEnd = dtNow;


	//start with a small date window and expand until we have more than the desired number of resources
	while (n > -100)
	{
		var dtStart = dateadd('month', n, dtNow);
		var dtEnd = dateadd('month', 1, dtStart);

		eval("(insert {[fn:published] ?item ?l} into #ds " + sources + "
			WHERE unbound(?x) and between(?l, #dtStart, #dtEnd)
				and {?item [fn:published] ?item ?l}
				and " + query + ")");

		Response.appendToLog("(insert {[fn:published] ?item ?l} into #ds " + sources + "
			WHERE unbound(?x) and between(?l, #dtStart, #dtEnd)
				and {?item [fn:published] ?item ?l}
				and " + query + ")");

		eval("(insert {[dcterms:issued] ?item ?l} into #ds " + sources + "
			WHERE unbound(?x) and between(?l, #dtStart, #dtEnd)
				and {?item [dcterms:issued] ?item ?l}
				and " + query + ")");

		eval("(insert {[dc:date] ?item ?l} into #ds " + sources + "
			WHERE unbound(?x) and between(?l, #dtStart, #dtEnd)
				and {?item [dc:date] ?item ?l}
				and " + query + ")");

		n -= 1;

		var rsTest = (select ?s from #ds where {?p ?s ?o});
		if (rsTest.recordCount >= limit)
			break;
	}	

	return (select ?item, ?date_of_the_resource from #ds WHERE {?p ?item ?o}
		 AND SWITCH(?item)
			(CASE {[fn:published] ?item ?l}: ?date_of_the_resource=?l
			CASE {[dcterms:issued] ?item ?l}: ?date_of_the_resource=?l
			CASE {[dc:date] ?item ?l}: ?date_of_the_resource=?l
			DEFAULT:  ?date_of_the_resource = ''
			) ORDER BY ?date_of_the_resource DESC, ?item);
}




function getRecentItems(rs, sources, limit)
{
	var dtEnd = new Date();

	var ds = new datasource()

	var n = -1;

	//start with a small date window and expand until we have more than the desired number of resources
	while (n > -1000)
	{
		var dtStart = dateadd('month', n, dtEnd);

		eval("(insert {[fn:published] ?item ?l} into #ds " + sources + "
			WHERE resultset(#rs, ?item) 
				and {?c [fn:published] ?item ?l}
				and between(?l, #dtStart, #dtEnd))");
		
		eval("(insert {[dcterms:issued] ?item ?l} into #ds " + sources + "
			WHERE resultset(#rs, ?item) 
				and {?c [dcterms:issued] ?item ?l}
				and between(?l, #dtStart, #dtEnd))");

		eval("(insert {[dc:date] ?item ?l} into #ds " + sources + "
			WHERE resultset(#rs, ?item) 
				and {?c [dc:date] ?item ?l}
				and between(?l, #dtStart, #dtEnd))");

		n *= 2;

		var rsTest = (select ?s from #ds where {?p ?s ?o});
		if (rsTest.recordCount >= limit)
			break;
	}	

	return (select ?item, ?date_of_the_resource from #ds WHERE {?p ?item ?o}
		 AND SWITCH(?item)
			(CASE {[fn:published] ?item ?l}: ?date_of_the_resource=?l
			CASE {[dcterms:issued] ?item ?l}: ?date_of_the_resource=?l
			CASE {[dc:date] ?item ?l}: ?date_of_the_resource=?l
			DEFAULT:  ?date_of_the_resource = ''
			) ORDER BY ?date_of_the_resource DESC, ?item);
}



//
//Printout the results of query in HTML format
//
function writeHTML(q)
{
    response.write ("Your query: <b><p>");
	var s1=String(request['rdfql']);
	var s2=repall(s1, "\n", "<br>");
	s2=repall(s2, " ", "&nbsp;");
	response.write (s2);
    response.write ("</b>");

	var re 	= new RegExp("[?]([a-zA-Z0-9_-]*) ", "gi");
 	var sre=new RegExp ("select *(.*) *using", "gi");
    	var s = q.match (sre);
    	s=String(s[1])+" ";

	eval ("var answer = ("+q+");");

	if (q_index > 0)
		answer.move(q_index-1);

  	Response.contentType=format;

	%><p><%

	response.write (answer.recordcount + " matches found; ");

	if ((answer.recordcount < limit)||(limit==-1)) 
		response.write (answer.recordcount);
	else  
		response.write (limit);

	response.write ( " displayed.");

	%><p><%
	%><table border=1><tr><%

    var nvars=0;

	for (var results = re.exec(s); results != null; results = re.exec(s))
	{
		    Response.Write("<td><b>"+results[1]+"</b></td>");
		    nvars++;
	}

	%></tr><%
	var rows=0;    

	while (!answer.EOF && ((rows<limit)||(limit==-1))) 
	{
	%><tr><%
	    for (var i=0; i<nvars; i++)
		{
		    Response.write("<td>"  + fixns(answer[i]) + "</td>");
		}
	%></tr><%

		rows++;	    
		answer.moveNext();
	    }

   %></table><%
}

//
//Query processing function.
//
function processQuery()
{
	var listRscURI=new Array();

	var q=trim(compress(lineout(String(request['rdfql']))));

	var re = new RegExp("^describe", "i");

	var describe = q.search(re);

	if (describe > -1) 
	{
		//Processing DESCRIBE type of queries
		q = q.replace(re, "SELECT");
	
		if (format=="text/html")
		{
			doWaitProcessing();
			listRscURI=getURIList(q); 
 			writeHTMLDescribeList(listRscURI);
		}
		else
		{
			if (format=="application/rss")
			{
				listRscURI=getURIList(q); 

				//inference is taken care of in get descriptions, so say excluide here to avoid redoing it
 				writeRSSDescription(listRscURI,"exclude", getDescriptions(listRscURI, inference));
			}
			else
			{
				if (format=="application/atom+xml")
				{
					listRscURI=getURIList(q); 
 					writeAtomDescription(listRscURI, inference);
				}
				else
					Response.write("Sorry, but this format of output is not supported. For SELECT type of query you could use HTML or RSS format");
			}
		}
	}
	else
	{
		//Processing SELECT type of queries
		if (format=="text/html")
		{
			//Printout SELECT HTML response
			doWaitProcessing();
			writeHTML(q);
		}
		else
		{
			if (format=="text/csv")
				writeCSV(q);	//Printout results in CSV format
			else
				Response.write("Sorry, but this format of output is not supported. For SELECT type of query you could use HTML or CSV format");
		}
	}
}

function isEmpty(val)
{
	if ((val==null)||(val=="")||(val=="null"))
		return true;
	else
		return false;
}

//
// Get all descriptions (cbds) for the passed in list of resources
//













function getDescriptions(reslist, inference)
{
	var rs;
	var ds = new DataSource();

	if (inference == "include")
	{
		//rs = (select ?p ?s ?o using expandedKB rulebase uriqa, AllData where ?res=list_member(#reslist) and cbd(?p ?s ?o ?res));

		for (var i = 0; i < reslist.count; i++)
		{
			cr = getDescription(reslist[i], "include", null);
			ds.insert(cr);
		}
	}
	else
	{
		rs = (select ?p ?s ?o using managedKB rulebase uriqa, AllData where ?res=list_member(#reslist) and cbd(?p ?s ?o ?res));
		ds = datasource(rs);
	}

	return (ds);
}

//
// process facet query expressed in input params and output results
//

function processFacetQuery()
{
	var query = buildFacetQuery();

//	Response.write(query);	
//	return(null);

	if (format=="text/csv")
		writeCSV(query);
	else
	{
	var listRscURI;

		if (sortBy=="best")
			listRscURI = getUriListBestSort(query);
			
		else
			{
			listRscURI = getUriListFromFacetQuery(query);
			}	
		

		//listRscURI
		if (format=="text/html")
			writeHTMLDescribeList(listRscURI, null, query);
		else if ((format=="application/atom+xml")||(format=="atom"))
 			writeAtomDescription(listRscURI, inference);
		else if ((format=="application/rss")||(format=="rss"))
		{
			//inference is taken care of in get descriptions, so say exclude here to avoid redoing it
 			writeRSSDescription(listRscURI,"exclude", getDescriptions(listRscURI, inference), res_count);
		}
		else if (format=="text/list")
			writeList(listRscURI);
		else if (format== "facets")
			writeFacets(listRscURI, inference);	
	}
}

//
// build a rdfql query from facets passed as query vars (relies on functions in f_query.rsp)
//
function buildFacetQuery()
{
	var aryFacets = new Array();
	var aryOptFacets = new Array();

	facet_trfm_query = "SELECT ?item ?t ?date_of_the_resource USING expandedKB WHERE {?item [fn:type] ?item [fntype:Resource]} ";


   if (sortBy=="best")	
   {
		if (!isEmpty(mandatoryFacets))
		{
			var mandatoryFacetStr = new String(mandatoryFacets);
			var ary = mandatoryFacetStr.split(RegExp(" *[\n\r ]+ *", "gi")); 

			for (var i = 0; i < ary.length; i++) 
			{
				var query_element = transformFacetStmtToRDFQL(ary[i]);
			
				if (query_element!= null)
					aryFacets[aryFacets.length] = query_element;
			}
		}

		if (!isEmpty(facets))
		{
			var facetStr = new String(facets);
			var ary = facetStr.split(RegExp(" *[\n\r ]+ *", "gi")); 

			for (var i = 0; i < ary.length; i++) 
			{	
				var query_element = transformFacetStmtToRDFQL(ary[i]);

				if (query_element!= null)
					aryOptFacets[aryOptFacets.length] = query_element;

			}
		}
	
		var query = "SELECT ?item ?rank USING expandedKB RULEBASE facets WHERE {?item [fn:type] ?item [fntype:Resource]} AND ";

		//add on mandatory facets if there is some 
		if (aryFacets.length < 1)
			query += " opt(?item, ?cond) and groupby(?item)(?rank=count(?cond))";
		else
			query += aryFacets.join(" AND ") + " AND opt(?item, ?cond) and groupby(?item)(?rank=count(?cond))";

		//optional facets
		var rbase = "rulebase facets{\r\nINFER opt(?item, 0) FROM succeed();\r\n";

		for (var i=0; i<aryOptFacets.length; i++)
		rbase += "INFER opt(?item, " + (i + 1) + ") FROM {?item [fn:type] ?item [fntype:Resource]} AND " + aryOptFacets[i] + ";\r\n";
		rbase += "}\r\n";

	if(sortBy == "best") 
		query += " order by ?rank desc, ?item";

//	return rbase + query;
	return rbase + " var sorted = (" + query + " );";

   }
   else
      {
 	  if (!isEmpty(mandatoryFacets))
 	  {
		var mandatoryFacetStr = new String(mandatoryFacets);
		var ary = mandatoryFacetStr.split(RegExp(" *[\n\r ]+ *", "gi")); 
	
		for (var i = 0; i < ary.length; i++) 
		{
			var query_element = transformFacetStmtToRDFQL(ary[i]);
		
			if (query_element!= null)
				facet_trfm_query=facet_trfm_query + " AND " + query_element;
		}
 	  }

	  if ((!isEmpty(facets)) && (match_param == "one"))
 	  {
		var facetStr = new String(facets);
		var ary = facetStr.split(RegExp(" *[\n\r ]+ *", "gi")); 

		facet_trfm_query = facet_trfm_query + "AND (";

		for (var i = 0; i < ary.length; i++) 
		{	
			var query_element = transformFacetStmtToRDFQL(ary[i]);

			if (query_element!= null)
			{
				facet_trfm_query=facet_trfm_query + query_element;

				if (i<ary.length-1)
					facet_trfm_query = facet_trfm_query + " OR "
			}
		}
		facet_trfm_query = facet_trfm_query + ")";
 	 }

 	 if ((!isEmpty(facets)) && match_param=="all")
 	 {
		var facetStr = new String(facets);
		var ary = facetStr.split(RegExp(" *[\n\r ]+ *", "gi")); 
	
		for (var i = 0; i < ary.length; i++) 
		{
			var query_element = transformFacetStmtToRDFQL(ary[i]);

			if (query_element!= null)
				facet_trfm_query=facet_trfm_query + " AND " + query_element;
		}
 	 }

	}
		if (sortBy =="title")
		{
			facet_trfm_query = facet_trfm_query + " AND {?item [http://sw.nokia.com/MARS-3/title] ?item ?t} ORDER BY ?t";
		}
		else
		if (sortBy =="date")
		{
			facet_trfm_query = facet_trfm_query + " AND SWITCH (?item) "+
				 			"(CASE {?item [editor:description_modified] ?item ?l}: ?date_of_the_resource=?l AND ?date_field_name='description_modified'" +
							"CASE {?item [fn:updated] ?item ?l}: ?date_of_the_resource=?l AND ?date_field_name='updated'"+
							"CASE {?item [dcterms:modified] ?item ?l}: ?date_of_the_resource=?l AND ?date_field_name='term:modified'"+
							"CASE {?item [editor:description_created] ?item ?l}: ?date_of_the_resource=?l AND ?date_field_name='editor:description_created'"+
							"CASE {?item [fn:published] ?item ?l}: ?date_of_the_resource=?l AND ?date_field_name='published'"+
							"CASE {?item [dcterms:issued] ?item ?l}: ?date_of_the_resource=?l AND ?date_field_name='dcterms:issued'"+
							"CASE {?item [dc:date] ?item ?l}: ?date_of_the_resource=?l AND ?date_field_name='dc:date'"+
							"DEFAULT:  ?date_of_the_resource = ''" + 
							") ORDER BY ?date_of_the_resource DESC, ?item";

		}

	return(facet_trfm_query);

}


//
// evaluate a query and convert results into an array (expects query to be facet query of form select ?item ....)
//

function getUriListFromFacetQuery(query)
{
	var ary = new Array();

	eval(query);




	var rs = Response.results;
	res_count = rs.recordCount;
	//if an offset is passed in, advance to that offset
	if (q_index > 0)
		rs.move(q_index-1);

		var c=0;

		while (!rs.EOF && (c < limit || limit==-1)) 
		{ 

			try {

			ary[c] = rs["item"];
			c++;

			    } 
			catch (e)
				{
		    	 	Response.appendToLog("Warning!" + e); // do nothing
				}
    		 rs.moveNext();
		}
/*
	for (; !rs.EOF; rs.moveNext())

		ary[ary.length] = rs[0];
*/
	return ary;
}

function getUriListBestSort(form_query)
{
		var listURI=new Array();
		var nvals=0;

		eval(form_query);
		
	//if the index is specified then move to specific record

	res_count=sorted.recordCount;

	if (q_index > 0)
		sorted.move(q_index-1);

		var c=0;
			while (!sorted.EOF && (c < limit || limit==-1)) 
			{ 
					try {
						if ((typeof sorted["item"])== "resource")
						{
							listURI[c] = sorted["item"];
							c++;
						}

					} catch (e)
					{
		    			Response.write("Warning!" + e); // do nothing
					}
    			sorted.moveNext();
			}
	 return(listURI);
}
%>