/*
 *  $Id: io.js,v 1.16 2009/10/29 19:17:08 ghard Exp $
 *
 *  This file is part of the OpenLink Software Ajax Toolkit (OAT) project.
 *
 *  Copyright (C) 2009 OpenLink Software
 *
 *  See LICENSE file for details.
 *
 * dataObj 
 * 		   -> data: query data/results if any
 * 		   -> query: query text
 * 		   -> endpointOpts: data endpoint options object
 * 		   -> defaultGraph: default graph to select from
 * 		   -> schemas: schema list
 * 		   -> pragmas: object with current virtuoso pragmas
 * 		   -> canvas: current canvas state
 *		   -> metaDataOpts: creator, title, description (,etc.)
 */


iSPARQL.IO = {
    /* serialize current query to plain string
     * format is"
     * # pragma { name } = { value }
     * # endpoint
     * # graph
     * query text
     */
    serializeRq:function(dataObj) {
		var str = "";
	
		/* serialize pragmas, inserted as sparql comments */
		if (dataObj.endpointOpts.pragmas)
	    	for (var i=0;i<dataObj.endpointOpts.pragmas.length;i++) {
				var pragma = dataObj.endpointOpts.pragmas[i];
				var name = pragma[0];
				var values = pragma[1];
				for(var j=0;j<values.length;j++) { str += '# {pragma} {'+name+'} = {'+values[j]+'}\n'; }
	    	}
	
		/* endpoint */

		if (dataObj.endpointOpts.endpointPath) {	
	    	str += '# {endpoint} {'+dataObj.endpointOpts.endpointPath+'}\n';	
		}
	
		/* graph */
		if (dataObj.defaultGraph) { str += '# {graph} {'+dataObj.defaultGraph+'}\n'; }
	
		/* named graph */
		for (var i=0;i<dataObj.namedGraphs.length;i++) {
	    	str += '# {named graph} {' + dataObj.namedGraphs[i] + '}\n';
		}

		if (dataObj.maxrows && dataObj.maxrows != 0) {
            str += '# {maxrows} {' + dataObj.maxrows + '}\n';
		}

		str += dataObj.query;
		return str;
    },

    serializeLdr:function(dataObj) {
		var xslt = iSPARQL.Preferences.xslt + 'dynamic-page.xsl';
		var iNS = "urn:schemas-openlink-com:isparql";
		var xmlTemplate = '<?xml version="1.0" encoding="UTF-8"?>\n'+
		'<?xml-stylesheet type="text/xsl" href="' + xslt + '"?>\n'+
		'<iSPARQL xmlns="' + iNS + '"\n' +
		'         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"\n'+
		'         xmlns:dc="http://purl.org/dc/elements/1.1/"\n'+
		'         xmlns:ex="http://example.org/stuff/1.0/">\n'+
		'<rdf:Description about="#this">\n'+
		'  <dc:title></dc:title>\n'+
		'  <dc:creator></dc:creator>\n'+
		'  <dc:description></dc:description>\n'+
		'</rdf:Description>\n'+
		'<ISparqlDynamicPage>\n'+
		'</ISparqlDynamicPage>\n'+
		'</iSPARQL>';
		var xml = OAT.Xml.createXmlDoc(xmlTemplate);
		var page = xml.getElementsByTagName("ISparqlDynamicPage")[0];
		var isparql = xml.getElementsByTagName("iSPARQL")[0];
		var title = xml.getElementsByTagName("dc:title")[0];
		var creator = xml.getElementsByTagName("dc:creator")[0];
		var description = xml.getElementsByTagName("dc:description")[0];
	
		var addNode = function(p,ns,name,text,nenc) {
	    	var node = xml.createElementNS(ns,name);
	    	var t = text || "";
	    	if (nenc) {
				node.textContent = t;
            }
            else {
				node.textContent = OAT.Dom.toSafeXML(t);
            }
	    	p.appendChild(node);
	    	return node;
		}

		if (dataObj.defaultGraph) { addNode(page,iNS,"graph",dataObj.defaultGraph); }
		if (dataObj.useProxy) { addNode(page,iNS,"proxy",dataObj.useProxy); }
	
        var qn;

		if (dataObj.query) {
			qn = addNode(page,iNS,"query",dataObj.query,true); 
 	      	if (dataObj.maxrows) { qn.setAttributeNS (iNS, 'maxrows', dataObj.maxrows.toString()); }
        }
		if (dataObj.prefixes) {
	    	var schemas = addNode(page, iNS, "schemas");
	    	for(var i=0;i<dataObj.prefixes.length;i++) {
				var schemaNode = dataObj.prefixes[i];
				addNode(schemas,iNS,"schema",schemaNode);
	    	}
		}

		if(dataObj.namedGraphs) {
	    	var namedgraphs = addNode(page,iNS,"namedgraphs");
	    	for(var i=0;i<dataObj.namedGraphs.length;i++) {
				var graphNode = dataObj.namedGraphs[i];
				addNode(namedgraphs,iNS,"namedgraph",graphNode);
	    	}
		}

		if(dataObj.endpointOpts.pragmas) {
	    	var pragmas = addNode(isparql,iNS,"pragmas");
	    	for(var i=0;i<dataObj.endpointOpts.pragmas.length;i++) {
				var pragma = dataObj.endpointOpts.pragmas[i];
				var name = pragma[0];
				var values = pragma[1];
				var pragmaNode = addNode(pragmas,iNS,"pragma");
				addNode(pragmaNode,iNS,"name",name);
				for(var j=0;j<values.length;j++) { 
		    		addNode(pragmaNode,iNS,"value",values[j]); 
				}
	    	}
		}

		if (dataObj.endpointOpts.endpointPath) { 
	    	addNode(isparql,iNS,"endpoint",dataObj.endpointOpts.endpointPath); 
		}

		if (dataObj.canvas) { addNode(isparql,iNS,"canvas",dataObj.canvas); }
	
		if (dataObj.metaDataOpts) {
	    	title.textContent = OAT.Dom.toSafeXML(dataObj.metaDataOpts.metadata.title);
	    	creator.textContent = OAT.Dom.toSafeXML(dataObj.metaDataOpts.metadata.creator);
	    	description.textContent = OAT.Dom.toSafeXML(dataObj.metaDataOpts.metadata.description);
		}	
	
		return OAT.Xml.serializeXmlDoc(xml);
    },

    serializeXml:function(dataObj) {
		var xmlTemplate = '<?xml version="1.0" encoding="UTF-8"?>\n'+
		'<root xmlns:sql="urn:schemas-openlink-com:xml-sql">\n'+
		'<sql:sparql></sql:sparql>\n'+
		'</root>';
		var xml = OAT.Xml.createXmlDoc(xmlTemplate);
	
		var root = xml.getElementsByTagName("root")[0];
	
		if (dataObj.defaultGraph)
	    	root.setAttribute('sql:default-graph-uri',OAT.Dom.toSafeXML(dataObj.defaultGraph));
	
		var sql = xml.getElementsByTagName("sparql")[0];
		sql.textContent = OAT.Dom.toSafeXML(dataObj.query);
	
		return OAT.Xml.serializeXmlDoc(xml);
    },

    serializeRdf:function(dataObj) {
		return OAT.Xml.serializeXmlDoc(dataObj.data);	
    },

    unserializeRq:function(str) {
		var dataObj = {
	    	endpoint:"",
	    	defaultGraph:"",
	    	namedGraphs:[],
	    	query:"",
	    	maxrows:0,
	    	pragmas:[]
		};
			
		var getEndpoint = function(str) {
	    	var m = str.match(/^\s*#\s*{endpoint}\s*{(.*?)}/);
	    	return (m)? m[1] : false;
		}
	
		var getPragma = function(str) {
	    	var m = str.match(/^\s*#\s*{pragma}\s*{(.*?)}\s*=\s*{(.*?)}/);
	    	return (m) ? m : false;
		}
		
		var getGraph = function(str) {
	    	var m = str.match(/^\s*#\s*{graph}\s*{(.*?)}/);
	    	return (m)? m[1] : false;
		}

		var getNamedGraph = function(str) {
	    	var m = str.match(/^\s*#\s*{named graph}\s*{(.*?)}/);
	    	return (m)? m[1] : false;
		}

        var getMaxRows = function (str) {
	    	var m = str.match(/^\s*#\s*{maxrows}\s*{(.*?)}/);
            return (m)? m[1] : false;
        }


		var isComment = function(str) {
	    	return str.match(/^\s*#/);
		}

		var isBlank = function(str) {
	    	return str.match(/^\s*$/);
		}

		var lines = str.split(/\n/);
		for (var i=0;i<lines.length;i++) {
	    	var line = lines[i];
	    
	    var p = getPragma(line);
	    if (p) {
		var index = -1;
		for(var j=0;j<dataObj.pragmas.length;j++) {
		    if(dataObj.pragmas[j][0] == p[0]) { index = j; break; }
		}
		if (index == -1) { dataObj.pragmas.push(p); }
		else { dataObj.pragmas[index][1].push(p[1]); }
		continue;
	    }

	    p = getEndpoint(line);
	    if (p) {
		dataObj.endpoint = p;
		continue;
	    }
	    
	    p = getGraph(line);
	    if (p) {
		dataObj.defaultGraph = p;
		continue;
	    }
	    
	    p = getNamedGraph(line);
	    if (p) {
		dataObj.namedGraphs.push(p);
		continue;
	    }

	    p = getMaxRows(line);

	    if (p) {
		data.maxrows = parseInt(p);
		continue;
            }

	    if(!isBlank(line) && !isComment(line)) {
		dataObj.query += line + '\n';
	    }
	}
	return dataObj;
    },

    unserializeXml:function(str) {
	var dataObj = { defaultGraph:"", query:"" };

	var xml = OAT.Xml.createXmlDoc(str);
	var q = xml.getElementsByTagName("sparql")[0];
	var r = xml.getElementsByTagName("root")[0];

	if(q) { dataObj.query = OAT.Dom.fromSafeXML(q.textContent) || ""; }
	if(r) { dataObj.defaultGraph = r.getAttribute('sql:default-graph-uri') || false; }

	return dataObj;
    },

    unserializeLdr:function(str) {
	var dataObj = {
	    defaultGraph:"",
	    graph:false,
	    schemas:[],
	    pragmas:[],
	    prefixes:[],
	    namedGraphs:[],
	    endpoint:"/sparql",
	    query:false,
	    useProxy:false,
	    metaDataOpts:{}
	};

	var getNodeValue = function(node,name) {
	    var n = node.getElementsByTagName(name)[0];
	    return (n)? OAT.Dom.fromSafeXML(n.textContent) : "";
	}
	
	var xml = OAT.Xml.createXmlDoc(str);
	
	dataObj.defaultGraph = getNodeValue(xml,"graph");
	if (!dataObj.defaultGraph) dataObj.defaultGraph = '';
	
	dataObj.endpoint = getNodeValue(xml,"endpoint");
	if (!dataObj.endpoint) dataObj.endpoint = "/sparql";

	dataObj.useProxy = getNodeValue(xml,"proxy");
	
	dataObj.query = getNodeValue(xml,"query");

	dataObj.maxrows = xml.getElementsByTagName ("query").getAttribute("maxrows");

	var schemas = xml.getElementsByTagName("schemas");

	for (var i=0;i<schemas.length;i++) {
	    var schema = OAT.Dom.fromSafeXML(schemas[i]);
	    dataObj.prefixes.push(schema);
	}

	var namedgraphs = xml.getElementsByTagName("namedgraph");
	for (var i = 0; i < namedgraphs.length; i++) {
	    var graphnode = OAT.Dom.fromSafeXML(namedgraphs[i].firstChild.nodeValue);
	    dataObj.namedGraphs.push(graphnode);
	}

	var pragmas = xml.getElementsByTagName("pragma");
	for (var i=0;i<pragmas.length;i++) {
	    var pnode = pragmas[i];
	    var p = getNodeValue(pnode,"name");
	    var v = pnode.getElementsByTagName("value");

	    var index = -1;
	    for(var j=0;j<dataObj.pragmas.length;j++) {
		if(dataObj.pragmas[j][0] == p) { index = j; break; }
	    }
	    
	    if (index == -1) { dataObj.pragmas.push([p,v]); }
	    else { for(var j=0;j<v.length;j++) { dataObj.pragmas[index][1].push(v[j]); } }
	}

	var rdf_desc = xml.getElementsByTagName("rdf:Description")[0];
	dataObj.metaDataOpts.title = getNodeValue(rdf_desc,"dc:title");
	dataObj.metaDataOpts.description = getNodeValue(rdf_desc,"dc:description");
	dataObj.metaDataOpts.creator = getNodeValue(rdf_desc,"dc:creator");
		
	return dataObj;
    },

    serialize:function(dataObj,type) {
	switch(type) {
	    default:
	    case "rq":
	    return this.serializeRq(dataObj);
	    break;
	    
	    case "xml":
	    return this.serializeXml(dataObj);
	    break;
	    
	    case "ldr":
	    case "isparql":
	    return this.serializeLdr(dataObj);
	    break;

	    case "rdf":
	    return this.serializeRdf(dataObj);
	    break;
	}
    },

    unserialize:function(str,type) {
	switch(type) {
	    default:
	    case "rq":
	    return this.unserializeRq(str);
	    break;
	    
	    case "xml":
	    return this.unserializeXml(str);
	    break;
	    
	    case "ldr":
	    case "isparql":
	    return this.unserializeLdr(str);
	    break;
	}
    },

    save:function(dataObj) {
	var options = {
	    extensionFilters:[
			      ['rq','rq','SPARQL Definitions','text/plain'],
			      ['isparql','isparql','Dynamic Linked Data Page','text/xml'],
			      ['ldr','ldr','Dynamic Linked Data Resource','text/xml'],
			      ['rdf','rdf','RDF Data','application/xml'],
			      ['xml','xml','XML Server Page','text/xml']
			      ],
	    callback:function(){},
	    dataCallback:function(file,ext) {
		return iSPARQL.IO.serialize(dataObj,ext);
	    }
	}
	
	OAT.WebDav.saveDialog(options);
    },
    
    load:function(callback) {
	var options = {
	    extensionFilters:[
			      ['rq','rq','SPARQL Definitions','text/plain'],
			      ['isparql','isparql','Dynamic Linked Data Page','text/xml'],
			      ['ldr','ldr','Dynamic Linked Data Resource','text/xml'],
			      ['xml','xml','XML Server Page','text/xml'],
			      ['','*','All files','']
			      ],
	    dataCallback:function(){},
	    callback:function(path,file,data) {
		var m = file.match(/\.(\w+)$/);
		var ext = (m)? m[1] : "xml";
		var o = iSPARQL.IO.unserialize(data,ext);
		if (callback) { callback(path,file,o) };
	    }
	}
	
	OAT.WebDav.openDialog(options);
    }
}
