function searchResult() {
	this.results = new Array();
}

function xmlObj( xml, xslt ) {
	err_msg = [ 'fout tijdens laden van xml' ];
	this.xmlDoc;
	this.xml = xml;
	this.xslt = xslt;
	
	this.loadXmlDoc = function(xml) {
		this.xml = xml;

		if( typeof window.ActiveXObject != 'undefined' ) {
			xdoc = new ActiveXObject("Msxml2.DOMDocument.3.0");
			try {
				xdoc.async = false;
				xdoc.load(xml);
				if( xdoc.parseError.errorCode != 0 ) {
					throw( "Bestand '"  +xdoc.parseError.url + '\' niet gevonden' );
				}
				xdoc.setProperty("SelectionLanguage", "XPath");
			}
			catch(err) {
				var msg = err_msg[0] +'\n' + err;
				alert( msg );
				if( window.console )
					console.log( msg );
				return false;
			}
		}
		else {
			xdoc = document.implementation.createDocument('','', null);
			try {
				xdoc.async = false;
				xdoc.load(xml);
			}
			catch(ex) {
				try {
					xdoc = new XMLHttpRequest();
					xdoc.open("GET", xml, false);
					xdoc.send();
					xdoc = xdoc.responseXML;
				}
				catch(ex2) {
					alert( err_msg[0] );
				}
			}
		}
		return xdoc;
	}
	this.getNodes = function(xpath, xml, isSingleNode) {
		isSingleNode = isSingleNode || false;

		xml = xml || this.xmlDoc || this.xml;
		if(window.ActiveXObject) {		// IE
			var nodes = {};
			try {
				nodes = xml.selectNodes(xpath);
				return nodes;
			 }
			catch(e) {
				if( window.console )
					console.log(e);
				return false;
			}
		}
		else {							// Firefox
		   var xpe = new XPathEvaluator();
		   try {
			   var nsResolver = xpe.createNSResolver( xml.ownerDocument == null ? xml.documentElement : xml.ownerDocument.documentElement);
			   var results = xpe.evaluate(xpath, xml, nsResolver, isSingleNode ? 8:0 , null);
		   }
		   catch(ex) {
				if( window.console )
					console.log(e);
				return false;
		   }
		   return results; 
		}
	}
}

function epaper(xml, xslt) {
	// ######## Public variables ########

	this.edition = {
		publication: 1,
		article: 1,
		alias: '',
		date: '',
		path: '',
		paper: 1,
		page: 1,
		totalPages: 1
	};
	
	this.searchResult = new searchResult();
	
	// set base constructor
	this.constructor( xml, xslt );
	
	// ######## Private variables ########
	
	// ######## Init ########
	if(xml) {
		this.xmlDoc = this.loadXmlDoc(arguments[0]);
		this.edition.path = xml.substr( 0, xml.lastIndexOf('/') ).replace('/xml', '')
	}
	if(xslt)
		this.xslt = this.loadXmlDoc(arguments[1]);
	
	this.imgWidth = 0;
	
	// ######## Public methods ########
	this.getPageImg = function( page, isSpread, returnObj ) {
		returnObj = returnObj || true;
		var img = {};
		page = (page && typeof page === 'number')?page:this.edition.page;
		var path = '';
		
		var xpath = '//Pages/Page[@pageNum=' + ( (page > 1 && page % 2) ? page -1 : page) +']/ImagePage[@file]';
		var n = this.getNodes(xpath, null, false);
		var file,w,h;
		
		if(window.ActiveXObject) {
			file = n[0].getAttribute('file');
			w = n[0].parentNode.getAttribute('width')*1;
			h = n[0].parentNode.getAttribute('height')*1;
		}
		else {
			n = n.iterateNext();
			if( n ) {
				file = n.getAttribute('file');
				w = n.parentNode.getAttribute('width')*1;
				h = n.parentNode.getAttribute('height')*1;
				img = { 'file' : file, 'width' : w, 'height' : h };
			}
		}
		if( file )
			path = (this.edition.path +'/img/page/' +file);
	
		img = { file: file, width: w, height: h };
		img['path'] = path;
		
		return img;
	}
	this.getPaperIndex = function( paper, pub ) {
		var index = [];
		paper = paper || 1;
		pub = pub || 1;
		
		xpath = '//Pages/Page/Article[@type]/Text/Paragraph[@type=\'title\']';

		var n = this.getNodes( 'Papers/Paper[@alias]', null, true );
		var items = this.getNodes( xpath, null, false );
		
		if( window.ActiveXObject ) {
			this.edition.alias = n[0].getAttribute('alias');
			var date = this.getNodes( '//Publication[@Date]', n[0], true );
			this.edition.date = date[0].getAttribute('Date');
			articles = [];
			var i = 0;
			var pages = [];
			
			if( items.length ) {
				for( var x=0, l2 = items.length; x<l2 ; x++ ) {
					p = items[x].selectNodes('../..')[0].getAttribute('pageNum');
					if( typeof pages[p]  === 'undefined' ) {
						pages[p] = 0;
					}
					var type = this.getNodes( '../..', items[x], true )[0].getAttribute('type');
					
					if( type === 'redactioneel' ) {
						if( typeof( index[p] ) === 'undefined' ) {
							index[p] = [];
							i = (( p > 1 && p%2 ) ? pages[p-1] : 0 ) +1;	// if even, set $i to '0'
						}
						index[p].push( { 'title' : (items[x].text || 'geen titel'), 'index' : i  } );
					}
					pages[p]++;
					i++;
				}
			}
		}
		else {
			this.edition.alias = n.singleNodeValue.getAttribute('alias');
			var date = this.getNodes( '//Publication[@Date]', n[0], true );
			this.edition.date = date.singleNodeValue.getAttribute('Date')
			
			articles = [];
			var i = 0;
			var pages = [];
			
			while( node = items.iterateNext() ) {
				p = this.getNodes( '../..', node, true ).singleNodeValue.getAttribute('pageNum');
				if( typeof pages[p]  === 'undefined' ) {
					pages[p] = 0;
				}
				var type = this.getNodes( '../..', node, true ).singleNodeValue.getAttribute('type');

				if( type === 'redactioneel' ) {
					if( typeof( index[p] ) === 'undefined' ) {
						index[p] = [];
						i = (( p > 1 && p%2 ) ? pages[p-1] : 0 ) +1;	// if even, set $i to '0'
					}
					index[p].push( { 'title' : (node.textContent || 'geen titel'), 'index' : i  } );
				}
				
				pages[p]++;
				i++;
			}
		}
		
		return index;
	}
	this.getPageMap = function( page, mapName, isSinglePage, returnObj ) {
		returnObj = returnObj || true;
		page = page || this.edition.page;
		
		if( page > 1 && !isSinglePage )
			page -= (page%2)?1:0;

		mapName = mapName || 'map';
		var xpath = '//Pages/Page[@pageNum=' + ( (page > 1 && page % 2) ? page -1 : page) +']/Article/ImageArticle[@Coordinates]';
		var area;
		var pMap = returnObj ? document.createElement('map') : '';
		
		if(maps = this.getNodes(xpath)) {
			if(window.ActiveXObject) {
				for( var x=0, l=maps.length; x<l; x++ ) {
					if( a=maps[x].getAttribute('Coordinates') ) {
						var type = maps[x].parentNode.attributes[0].value;
						if( returnObj ) {
							area = document.createElement('area');
							area.className = '{ type: "' +type + '"}';
							area.shape = 'polygon';
							area.coords = a;
							area.nohref = 'nohref';
							pMap.appendChild( area );
						}
						else
							area += '<area class=\'{ type: "' +type + '"}\' shape=\'polygon\' coords=\'' +a +'\' nohref=\'nohref\' />\n';
					}
				}
			}
			else {
				var x = 0;
				while( node = maps.iterateNext() ) {
					if(a = node.getAttribute('Coordinates')) {
						type = node.parentNode.attributes[0].value;
						if( returnObj ) {
							area = document.createElement('area');
							area.className = '{ type: "' +type + '"}';
							area.shape = 'polygon';
							area.coords = a;
							area.nohref = 'nohref';
							pMap.appendChild( area );
						}
						else
							area += '<area class=\'{ type: "' +type + '"}\' shape=\'polygon\' coords=\'' +a +'\' nohref=\'nohref\' />\n';
					}
					++x;
				}
			}
		}
		if( !returnObj && typeof( pMap ) !== 'object' )
			pMap = '<map name=\''+mapName +'\'>'+area+'</map>';
		else
			pMap.name = mapName;
		return pMap;
	}
	this.getArticle = function( art, page, onIndex ) {
		art = art || this.edition.article;
		onIndex = onIndex || false;
		page = page || this.edition.page;
		var xpath;
		if( onIndex )
			xpath = '//Pages/Page[@pageNum=' + ( (page > 1 && page % 2) ? page -1 : page) +']/Article[position()='+art +']/Text/Paragraph';
		else
			xpath = '//Pages/Page/Article[@pageNum=' +page +'][position()='+art +']/Text/Paragraph';
			
		var nodes = this.getNodes(xpath);
		var article = {};
		
		if(window.ActiveXObject) {
			if( nodes.length ) {
				var prev = nodes[0]?nodes[0].parentNode.previousSibling:null;
				var file = prev.attributes[0].value;
				article['imgArticle'] = file ? ( ep.edition.path +'/img/article/' +file ):'';
				
				for( var x=0;x<nodes.length;x++ ) {
					type = nodes[x].getAttribute('type');
					var text = nodes[x].text.replace(/\n/g, '');
					if(article[type] === undefined)
						article[type]=[];
					
					if( type == 'paragraph' )
						article[type].push(text);
					else if( type == 'image' ) {
						file = nodes[x].childNodes[0].text.replace(/\n/g, '');
						caption = nodes[x].childNodes[1].text.replace(/\n/g, '');
						if( file )
							article[type].push( { 'src' : this.edition.path +'/img/article/' +file, 'caption' : caption } );
					}
					else
						article[type] = text;
				}
				article['type'] = nodes[0].parentNode.parentNode.getAttribute('type');
			}
			else
				return null;
		}
		else {
			while( node = nodes.iterateNext() ) {
				if( !article.hasOwnProperty('imgArticle') ) {
					var file = node.parentNode.previousElementSibling.getAttribute('file');
					article['imgArticle'] = file ? ( ep.edition.path +'/img/article/' +file ):'';
				}

				type = node.getAttribute('type');
				var text = node.textContent.replace(/\n/g, '');
				if(article[type] === undefined)
					article[type]=[];
				
				if( type == 'paragraph' )
					article[type].push(text);
				else if( type == 'image' ) {
					file = node.firstElementChild.textContent.replace(/\n/g, '');
					caption = node.lastElementChild.textContent;
					
					if( file )
						article[type].push( { 'src' : this.edition.path +'/img/article/' +file, 'caption' : caption } );
				}
				else
					article[type] = text;
				article['type'] = node.parentNode.parentNode.getAttribute('type');
			}
		}
		if( article['paragraph'] ) {
			var content = article.paragraph.join();
			var i = content.indexOf('.', 50);
			article['short'] = content.slice(0, i+1) +(i>0?'...':'');
		}
		article['index'] = art;
		article['page'] = page;
		article['onIndex'] = onIndex;
		return article;
	}
	this.getThumbnails = function() {
		var tn = [];
		var xpath = '//Pages/Page/ThumbNail/@file';
		var thumbs = this.getNodes(xpath);

		if(window.ActiveXObject) {
			for(var x=0,l=thumbs.length;x<l;x++)
				tn.push( this.edition.path +'/img/thumb/' +thumbs[x].text);
		}
		else {
			while( node = thumbs.iterateNext() )
				tn.push( this.edition.path +'/img/thumb/' +node.textContent);
		}
		
		this.edition.totalPages = tn.length;
		return tn;
	}
	this.getPapers = function() {
		var papers = [];
		var xpath = 'Papers/Paper';
		var p = this.getNodes(xpath);
		xpath = 'Publications/Publication[@Date]';
		
		var pubs = [];
		if(window.ActiveXObject) {
			for(var x=0,l=p.length;x<l;x++) {
				var node = p[x];
				var p = node.selectNodes(xpath);
				for( var i=0, l2=p.length;i<l2;i++) {
					pubs.push(p[i].getAttribute('Date'));
				}
				papers.push({ alias: node.getAttribute('alias'), name: node.getAttribute('name'), publications: pubs });
			}
		}
		else {
			var xpe = new XPathEvaluator();
			while( node = p.iterateNext() ) {
				var d = xpe.evaluate( xpath, node, null, XPathResult.ANY_TYPE, null );
				while( node2 = d.iterateNext() )
					pubs.push(node2.getAttribute('Date'));
				papers.push({ alias: node.getAttribute('alias'), name: node.getAttribute('name'), publications: pubs });
			}
		}
		return papers;
	}
	this.search = function(str) {
		this.searchResult.results = [];
	    if (str) {
	        str = str.toLowerCase();
	        var summary = '';
	        
	        var xpath = '//Article/Text/Paragraph[@type][contains(translate(.,\'ABCDEFGHIJKLMNOPQRSTUVWXYZ\', \'abcdefghijklmnopqrstuvwxyz\'), \'' + str + '\')]';
	        var xmlDoc = this.xmlDoc;
	        var node, nodes, parent;
			var totalHits = 0;
	        
	        if (window.ActiveXObject) {
	            nodes = this.xmlDoc.selectNodes(xpath);

	            for (var i = 0, l = nodes.length; i < l; i++) {
					if( !nodes[i].parentNode !== parent ) {
	                    var curNode = nodes[i].selectSingleNode('self::node()[normalize-space(.)]').text; //.text.replace( /[\t\n]/g, '' );
	                    var i1 = curNode.indexOf(str);
	                    var i2 = curNode.indexOf('.', i1 + str.length); 		// index of first '.' after keyword
	                    var i3 = curNode.substr(0, i1).lastIndexOf('.'); 	// index of first '.' before keyword or -1
	                    summary = (curNode.substr(i3 > 0 ? i3 : 0, i2 + 1)).replace(str, '<strong>' + str + '</strong>');

	                    var pNode = nodes[i];
	                    var title = pNode.parentNode.childNodes[0].text || 'geen titel';

	                    do {
	                        pNode = pNode.parentNode;
	                    }
	                    while (pNode && !pNode.getAttribute('pageNum') );
	                    var page = pNode.getAttribute('pageNum');
	                    
						do {
	                        pNode = pNode.parentNode;
	                    }
	                    while (pNode && pNode.tagName != 'Publication');
						
	                    var d = pNode.getAttribute('Date').split('-');
	                    var date = new Date(Date.UTC(d[0], d[1] - 1, d[2]));
						var size = nodes[i].selectNodes('../../../Article').length;

						var n = nodes[i].selectNodes('parent::node()/parent::node()/preceding-sibling::*');
	                    var artIndex =  size - nodes[i].selectNodes('../../following-sibling::*').length;
						
						if (this.searchResult['results'][page] === undefined)
	                        this.searchResult['results'][page] = [];
						if( this.searchResult['results'][page][artIndex] === undefined )
							this.searchResult['results'][page][artIndex] = [];
	                    this.searchResult['results'][page][artIndex] = new Object({ 'summary': summary, 'title': title });
	                    ++totalHits;
	                }
					parent = nodes[i].parentNode;   
	            }
	        }
	        else {
				try {
					nodes = this.getNodes(xpath);
					
					var xpe = new XPathEvaluator();
					
					while( n = nodes.iterateNext() ) {
						if( !n.parentNode.isSameNode(parent) ) {
							var curNode = xpe.evaluate( 'normalize-space(self::node())', n, null, XPathResult.STRING, null ).stringValue;
							
							var i1 = curNode.indexOf(str);
							var i2 = curNode.indexOf('.', i1+str.length);			// index of first '.' after keyword
							var i3 = curNode.substr(0, i1).lastIndexOf('.');		// index of first '.' before keyword or -1
							summary = (curNode.substr(i3>0?i3:0, i2+1)).replace( str, '<strong>' +str +'</strong>');
							
							var title = n.parentNode.childNodes[1].textContent || 'geen titel';
							
							var pNode = n;
							do {
								pNode = pNode.parentNode;
							}
							while( pNode && !pNode.hasAttribute('pageNum') );
							var page = pNode.getAttribute('pageNum')*1;

							do {
								pNode = pNode.parentNode;
							}
							while(pNode && pNode.localName != 'Publication');
							
							var date = new Date(pNode.getAttribute('Date'));
							var artIndex = xpe.evaluate( 'count(parent::node()/parent::node()/preceding-sibling::*)', n, null, XPathResult.NUMBER, null ).numberValue;
							artIndex--;
							
							if (this.searchResult['results'][page] === undefined)
								this.searchResult['results'][page] = [];
							if( this.searchResult['results'][page][artIndex] === undefined )
								this.searchResult['results'][page][artIndex] = [];
							this.searchResult['results'][page][artIndex] = new Object({ 'summary': summary, 'title': title });
							++totalHits;
						}
						parent = n.parentNode;
					}
				}
				catch(ex) {
					if( window.console )
						console.log(ex);
					return false;
				}
	        }
			this.searchResult['totalHits'] = totalHits;
			this.searchResult['query'] = str;
	    }
		return this.searchResult;
	}
}

function papers(xml, xslt) {
	this.editions = [];

	// set base constructor
	this.constructor( xml, xslt );
	
	if(xml)
		this.xmlDoc = this.loadXmlDoc(arguments[0]);
	if(xslt)
		this.xslt = this.loadXmlDoc(arguments[1]);
		
	var xpath = 'Papers/Paper';
	var nodes = this.getNodes( xpath, null, false );
	
	if( window.ActiveXObject ) {
		for( var n = 0, l = nodes.length; n < l; n++ ) {
			var edition = { 'name' : nodes[n].getAttribute('name'), 'alias' : nodes[n].getAttribute('alias') };
			var date = [];
			for( var c = 0, cl = nodes[n].childNodes[0].childNodes.length; c < cl; c++ ) {
				date.push( nodes[n].childNodes[0].childNodes[c].getAttribute('date') );
			}
			edition['date'] = date;
			this.editions.push( edition );
		}
	}
	
	else {
		while( n = nodes.iterateNext() ) {
			var edition = { 'name' : n.getAttribute('name'), 'alias' : n.getAttribute('alias') };
			var date = [];
			
			elm = n.firstElementChild.firstElementChild;
			do {
				date.push( elm.getAttribute('date') );
			}
			while( elm = elm.nextElementSibling );
			
			edition['date'] = date;
			this.editions.push( edition );
		}
	}
}

papers.prototype = new xmlObj;
epaper.prototype = new xmlObj;
