// ii.js
// defines global namespace
// and utility functions


// global namespace of entire lib
// utility functions are direct descendents
ii = {};

ii.views = {}; // contains view constructors
ii.items = {}; // contains item constructors

//ii.log_to_console = window.ii_log_to_console;
//ii.log_to_div = window.ii_log_to_div;
ii.logger_paused = false;
ii.logger_queue = [];

ii.init = function()
{
	// store browser options
	ii.browser = {
		safari: (navigator.userAgent.indexOf("Safari")!==-1)? true:false,
		opera: (navigator.userAgent.indexOf("Opera")!==-1)? true:false,
		windows: (navigator.userAgent.indexOf('Windows')!==-1)? true:false,
		msie: (navigator.userAgent.indexOf('MSIE')!==-1)? true:false,
		msie7: (navigator.userAgent.indexOf('MSIE 7')!==-1)? true:false
	}
}

/* global settings */
ii.set = {
  show_feedback: false,
  use_css_clock_blink: true
}


ii.assert = function(arg)
{
	if (!arg)
	{
		ii.error('Assertion failed');
	}
}

ii.dir = function(l) {
	if (window.console && window.console.dir)
		console.dir(l);
}

ii.log = function(l) {

    if(!window.ii_log_to_console){
        return;
    }

    if(ii.logger_paused === true){
        ii.logger_queue.push(l);
        return;
    }

    if(window['console']){

        if(console.log.apply){
            while(ii.logger_queue.length > 0){
                console.log.apply(console, ii.logger_queue.shift());
            }

            console.log.apply(console, arguments);
        }
        else {
            // IE 8
            while(ii.logger_queue.length > 0){
                console.log(ii.logger_queue.shift()[0]);
            }

            console.log(arguments[0]);
        }

    }
    else if(window.ii_log_to_div ){

        var div_console = document.getElementById('div_console');

        if(div_console){

            while(ii.logger_queue.length > 0){
                div_console.innerHTML += ii.logger_queue.shift() + '<br>';
            }

            div_console.innerHTML += l + '<br>';
        }
        else {

            div_console = document.createElement('div');

            div_console.setAttribute('id', 'div_console');

            div_console.style.position = 'fixed';
            div_console.style.background = 'white';
            div_console.style.zIndex = '99999999';
            div_console.style.bottom = '0px';
            div_console.style.right = '0px';
            div_console.style.width = '400px';
            div_console.style.height = '150px';
            div_console.style.overflow = 'auto';
            div_console.style.border = '1px solid red';

            div_console.innerHTML = l;

            document.body.appendChild(div_console);

            var open_console_button = ii.elm('div', {
                style: {
                    position: 'fixed',
                    bottom: '0px',
                    left: '0px',
                    background: 'blue',
                    color: 'white',
                    display: 'none'
                },
                onclick: function(){
                    div_console.style.display = 'block';
                    close_console_button.style.display = 'block';
                    this.style.display = 'none';
                }
            }, 'open console');

            document.body.appendChild(open_console_button);

            var close_console_button = ii.elm('div', {
                style: {
                    position: 'fixed',
                    bottom: '0px',
                    left: '0px',
                    background: 'blue',
                    color: 'white'
                },
                onclick: function(){
                    div_console.style.display = 'none';
                    open_console_button.style.display = 'block';
                    this.style.display = 'none';
                }
            }, 'close console');

            document.body.appendChild(close_console_button);

            var pause_console_button = ii.elm('div', {
                style: {
                    position: 'fixed',
                    bottom: '0px',
                    left: '75px',
                    background: 'green',
                    color: 'white'
                },
                onclick: function(){
                    if (this.innerHTML == 'console paused') {
                        ii.logger_paused = false;

                        while(ii.logger_queue.length > 0){
                            div_console.innerHTML += ii.logger_queue.shift()
                                + '<br>';
                        }

                        this.style.background = 'green';
                        this.innerHTML = 'pause console';
                    }
                    else {
                        ii.logger_paused = true;

                        this.style.background = 'red';
                        this.innerHTML = 'console paused';
                    }

                }
            }, 'pause console');

            document.body.appendChild(pause_console_button);

        }
    }
}

ii.error = function(l){
    if (console.error) 
        console.error(l);
    else {
        ii.log('err: ' + l);
        throw l;
    }
}


// performs an ajax query and evals results.
// params are key/values
// key is attached
ii.get = function(url,callback, params) {
	url = '/srv/' + url + '.php?';
	params = params || {};
	if (ii.login && ii.login.key)
		params.key = ii.login.key;

	for(var k in params)
		url += encodeURIComponent(k) + '=' + encodeURIComponent(params[k]) + '&';

	var request = new XMLHttpRequest();
	request.open('GET', url);
    
	request.onreadystatechange = function()
	{
		if (request.readyState == 4 && request.status==200)
		{
			
			if (0 && window.JSON)
			{
				try {
					var resp = JSON.parse(request.responseText);
				}
				catch(Exception)
				{
					ii.error('PHP ERROR: '+request.responseText);
					return;
				}
			}
			else
			{
				
				try {
					eval('var resp = ' + request.responseText);
					}
				catch(Exception)
				{
					
					ii.error('PHP ERROR: '+request.responseText);
					return;
				}
			}
			callback(resp);
		}
	}

	request.send(null);
	return request;
}

// performs an ajax query and puts result in target elm.
ii.getHtml = function(url,target, callback)
{
	url = 'html/' + url + '.php';
	var request = new XMLHttpRequest();
	request.open('GET', url);
    ii.log('gethtml: '+url);


	request.onreadystatechange = function()
	{
		if (request.readyState == 4 && request.status==200)
		{
			target.innerHTML = request.responseText;
			if (callback)
				callback(target);
		}
	}
	request.send(null);
	return request;
}

// performs an ajax request and caches the result
ii.loadDriver = function(name)
{
	if (!ii.drivers) ii.drivers = {};
	if (!ii.drivers[name])
	{
		ii.drivers[name] = ii.elm('div', { className:'driver' });
		ii.getHtml('Drivers'+name,ii.drivers[name] );
	}
	return ii.drivers[name];
}


// default hover images have X in there name
ii.onmouseoverbtn = function()
{
	this.src = this.src.replace(/([^X])\.png/, '$1X.png');
}
ii.onmouseoutbtn = function()
{
	this.src = this.src.replace(/X\.png/, '.png');
}

// create "tomtomtom's" from "tomtomtom"
ii.appendS = function(name)
{
	if (name.substr(name.length-1,1)=='s')
		return name+'\'';
	else
		return name+'\'s';
}

// conversions from typename/typeletter/typelabels
ii.typeletter = {
	user: 'u',
	account: 'u',
	trip: 't',
	comment: 'c',
	spot: 's',
	group: 'g',
	album: 'a',
	photo: 'p',
	poi: 'p',
	video: 'v',
	feed: 'f',
	thread: 'h'
};

ii.typename = {
	u: 'user',
	p: 'photo',
	v: 'video',
	t: 'trip',
	c: 'comment',
	g: 'group',
	s: 'spot',
	a: 'album',
	f: 'feed',
	h: 'thread'
}

ii.typector = {
	u: 'User',
	p: 'Photo',
	v: 'Video',
	t: 'Trip',
	c: 'Comment',
	g: 'Group',
	s: 'Spot',
	a: 'Album',
	f: 'Feed',
	h: 'Thread'
}

ii.typeplural = {
	u: 'People',
	p: 'Photos',
	v: 'Videos',
	t: 'Trips',
	c: 'Comments',
	s: 'Spots',
	g: 'Groups',
	a: 'Albums',
	f: 'Feed'
}
ii.typesingle = {
	u: 'Person',
	p: 'Photo',
	v: 'Video',
	t: 'Trip',
	c: 'Comment',
	s: 'Spot',
	g: 'Group',
	a: 'Album',
	f: 'Feed',
	user: 'Person',
	photo: 'Photo',
	video: 'Video',
	trip: 'Trip',
	comment: 'Comment',
	spot: 'Spot',
	group: 'Group',
	album: 'Album',
	feed: 'Feed'
}



/* ii.elm
 * utility function to create a new html-element
 * first param is element-name (TAG)
 * next param are children depending on type:
 * - object param is attritbutes
 * - string param is text-node
 * - html-element is child element
 *
 * eg: ii.elm('div', {style:{display:'none'}}, 'sample textcontent')
*/
ii.elm = function(elmname)
{

	var setatts = function(elm, atts)
	{
		for (var n in atts) {
            if (atts[n] instanceof Object && !(atts[n] instanceof Function)){
                setatts(elm[n], atts[n]);
            }
            else {
                if (ii.browser.msie) {
                    switch (n) {
                        case 'cssFloat':
                            elm.setAttribute('styleFloat', atts[n]);
                            break;
                        default:
                            try {
                                elm[n] = atts[n];
                            }
                            catch(e){
                                ii.log('cant set ' + n + ' to ' + atts[n]);
                                throw e
                            }
                            break;
                    }
                }
                else {
                    elm[n] = atts[n];
                }
            }
        }
	}

	var newelm = document.createElement(elmname);
	var args = ii.elm.arguments;

	for(var n=1; n < args.length; n++)
	{
		if (args[n] == undefined)
			ii.error('invalid parameter '+n+' to ii.elm');
		else if (args[n].nodeType)
			newelm.appendChild(args[n])
		else if (typeof(args[n]) == 'string')
			newelm.appendChild(document.createTextNode(args[n]));
		else
			setatts(newelm, args[n]);

	}
	return newelm;
}

// returns an img elment with specific src and dimensions
ii.pngImage = function(img, w, h) {

	var elm = document.createElement('img');
	elm.style.width = w + 'px';
	elm.style.height = h + 'px';
	elm.src = 'media/'+img;
	return elm;
}

ii.userLink = function(id, name)
{
	if (name=='Anonymous')
		return ii.elm('a', {className:'user'}, name);
	else
		return ii.elm('a', {className:'user', href:'#rel&item=u.'+id}, name);
}

ii.videoLink = function(id, name)
{
	return ii.elm('a', {href:'#rel&item=v.'+id}, name);
}

ii.photoLink = ii.poiLink = function(id, name)
{
	return ii.elm('a', {href:'#rel&item=p.'+id}, name);
}
ii.tripLink = function(id, name)
{
	return ii.elm('a', {href:'#rel&item=t.'+id}, name);
}
ii.groupLink = function(id, name)
{
	return ii.elm('a', {href:'#rel&item=g.'+id}, name);
}
ii.spotLink = function(id, name)
{
	return ii.elm('a', {href:'#rel&item=s.'+id}, name);
}
ii.albumLink = function(id, name)
{
	return ii.elm('a', {href:'#rel&item=a.'+id}, name);
}

ii.setText = function(elm, newText)
{
	if (ii.browser.msie)
		elm.innerText = newText;
	else
		elm.textContent = newText;
}

ii.stopPropagation = function(ev) {

    if (ev) {
        // All incl. IE, will do nothing if browser doesn't support it.
        ev.cancelBubble = true;

        // Firefox and DOM specific.
        if (ev.stopPropagation) {
            ev.stopPropagation();
        }
    }
}

ii.formatDate = function(timestamp, format)
{
	var dt = new Date((parseInt(timestamp))*1000);
	return dt.format(format);
}

ii.formatDistance = function(dist)
{
	if (dist===undefined)
		return undefined;
	dist = parseInt(dist);
	return (dist < 2000 ? dist + ' m' : Math.round(dist/1000) + ' km');
}

ii.formatSpeed = function(s)
{
	if (s == undefined)
		return '';
	else
        // api returns values in m/s, so 1m/s * 1km/1000m * 3600s/h = 3.6km/h
		return Math.round(s * 3.6) + ' km/h';
}

ii.formatTimespan = function(t)
{
	if (t < 120)
		return t + ' secs';
	else if (t/60 < 240)
		return Math.round(t/60) + ' min';
	else
		return Math.round(t/3600) + ' hours';
}


ii.formatLocation = function(lat, lon, spotid, spotname, locname)
{
	if (spotname)
		return ii.elm('span',
				'@ ',
				spotLink(spotid, spotname),
				', ',
				ii.geoCode(lat, lon, locname)
			);
	else
		return ii.elm('span',
				'@ ',
				ii.geoCode(lat, lon, locname)
			);
}

ii.iframeDocument = function(iframe)
{
	if (iframe.contentDocument)     return iframe.contentDocument.documentElement;
	else if (iframe.contentWindow) return iframe.contentWindow.document.body;
	else if (iframe.document) return iframe.document;

}


/**
 * set a cookie to the given name and value for a period of days. if days is
 * less than zero, then cookie will be expired immediately, if it is 0 then it
 * will expire once the browser is exited. if days is not defined, it will be
 * set to 14 days.
 *
 * @param {Object} name  the name of the cookie
 * @param {Object} value the value of the named cookie
 * @param {Object} days  the number of days to expire the cookie in.
 */
ii.setCookie = function(name, value, days){

	var days = (days === undefined) ? 14 : days;
	var ms_in_day = 86400000; /* 24 * 60 * 60 * 1000 */

    if( days == 0 ){
        document.cookie = name+'='+value+'; path=/';
    }
    else {
        var cookie_expiration_date = new Date();
        cookie_expiration_date.setTime( cookie_expiration_date.getTime() + ( days * ms_in_day) );

        document.cookie = name+'='+value+'; expires='+cookie_expiration_date.toGMTString()+'; path=/';
    }
}

/**
 * get the value for the named cookie.
 *
 * @param {Object} name the name of the cookie to return the value of.
 */
ii.getCookieValue = function(name){
	// the return value
	var value = '';

	// make sure this document has cookies
	var cookies = document.cookie.split(';');
	if(cookies.length){
		var num_of_cookies = cookies.length;

		// loop through the cookies looking for the correct cookie name
		// 1. compare the names
		// 2. extract the value
		for(var i = 0; i < num_of_cookies; i++){
			var cookie = cookies[i];

			// 1.
			if( cookie.indexOf(name+'=') > -1 ){
				// 2.
				value = cookie.split(name+'=')[1];
				break;
			}
		}
	}

	return value;
}

/**
 * expire a cookie of a given name
 *
 * @param {Object} name the name of the cookie to expire
 */
ii.removeCookie = function(name){
	ii.setCookie(name,'',-1);
}

ii.selectItemBrowserTab = function(){

    if(ii.app.state.state.item && ii.app.state.state.item.indexOf('ME') > -1){
		document.getElementById('ii_menu_home').className = 'selected';
		document.getElementById('ii_menu_world').className = '';
    }
    else if (!ii.app.state.state.item)
	{
		document.getElementById('ii_menu_home').className = '';
		document.getElementById('ii_menu_world').className = 'selected';
    }
	else
	{
		document.getElementById('ii_menu_home').className = '';
		document.getElementById('ii_menu_world').className = '';
    }
}

/**
 * decode a javascript query string into a javascript object. eg:
 *
 * id=000001&name=andrew&action=add
 *
 * would return
 *
 * {id:'000001', name:'andrew', action:'add'}
 *
 * @param {Object} qs
 * @returns Object containing all params
 */
ii.decode_query_string = function(qs){
	var o = {};

	// trim the ? on the front if it exists.
	if(qs.substring(0,1).indexOf('?')>-1){
		qs = qs.substring(1);
	}

	// parse out the '&' and '='
	var qs_parts = qs.split('&');
	for(var i=0, len = qs_parts.length; i<len; i++){
		var kv = qs_parts[i].split('=');
		var k  = decodeURIComponent(kv[0]);
		var v  = decodeURIComponent(kv[1]);

		o[k] = v;
	}

	return o;
}

/**
 * encode a javascript object as query string in name=value pairs, without, the
 * '?' at the front.
 *
 * eg: {id:'000001', name:'andrew', action:'add'}
 *
 * would return
 *
 * id=000001&name=andrew&action=add
 *
 * @param {Object} qs_obj
 */
ii.encode_query_string = function(qs_obj){
	var qs = [];
	for(var k in qs_obj){
		qs.push(encodeURIComponent(k)+'='+encodeURIComponent(qs_obj[k]));
	}
	return qs.join('&');
}

// Sets a default text for an input or textarea
// that autohides on focus
ii.setDefaultText = function(elm, defaultText)
{
	if (!elm.hasFocus)
		elm.value = defaultText;
	elm.defaultText = defaultText;
	elm.style.color = '#707070';
	elm.onfocus = function()
	{
		if (this.value == defaultText)
			this.value = '';
		this.hasFocus = true;
	}

	elm.onblur = function()
	{
		if (this.value == '')
		{
			this.value = defaultText;
		}
		this.hasFocus = false;
	}
}

ii.getTextBoxValue = function(elm)
{
	if (!elm.defaultText || elm.value != elm.defaultText)
		return elm.value;
	else
		return '';
}

// use this to get an elm by cause ie7 doesn't support formelm.elmname
ii.getElmByName = function(form, name)
{
	if (false && !ii.browser.msie7)
		return form[name];
	else
	{
		for (var i=0;i<form.elements.length;i++)
		{
			var e = form.elements[i];
			if (e.getAttribute('name') == name)
				return e;
		}
	}

}

ii.createId = function() {
    return 'ii_id_'+Math.ceil(Math.random()*300000);
}

// transforms element (usually button)
// to a throbber
ii.startWaitButton = function(elm)
{
	elm.oldText = elm.value;
	elm.value = '  ';
	elm.className = (elm.className||'') + ' waiting';
	elm.blur();
	elm.disabled = true;
}


ii.endWaitButton = function(elm)
{
	elm.value = elm.oldText;
	elm.className = elm.className.replace('waiting','');
	elm.disabled = false;

}

ii.getMessageBox = function(options){
	// why no background-image?
    var message = options.message === undefined ? '' : options.message;
    var style = options.style === undefined ? {} : options.style;

    var message_box = ii.elm('div', {
            className: 'messagebox',
            style: style
        },
        ii.elm('span', message),
        ii.elm('img', {
            src: '/media/balloon_curve_SML.gif'
        })
    );

    return message_box;
}
ii.getMessageBox = function(options) {
    var message = options.message === undefined ? '' : options.message;
    var style = options.style === undefined ? {} : options.style;
	style.position = 'relative';
	style.maxWidth = '290px';
	style.marginTop = '86px';

    var message_box = ii.elm('div', {
            className: 'msgbox',
            style: style
        },
        ii.elm('div', message),
        ii.elm('img', {
            src: '/media/balloontip_discs.gif',
			style: {
				position: 'absolute',
				top: '-26px',
				left: '10px'
			}
        })
    );

    return message_box;
	//<div data-field="messagebox" data-editable="true" style="position:relative;" class="msgbox"><div>ddddsstestje test...sss</div><form style="display: none; "><textarea>ddddsstestje test...sss</textarea><input type="submit" value="Apply"><input type="reset" value="Cancel"></form><img src="/media/balloontip_discs.gif" style="position: absolute; top: -26px; left: 10px; "></div>
}

/**
 * perform actions that need done when the message box gain focus
 *   - replace the callout image.
 *
 * @param {Object} elm
 */
ii.handle_messagebox_focus = function(elm){

    elm.style.backgroundImage = 'none';
    elm.style.backgroundColor = 'white';

    var img_elm = elm.parentNode.getElementsByTagName('img')[0];
    img_elm.src = './media/balloon_curve_SMLX.gif';


    if (elm.setSelectionRange) {
        elm.setSelectionRange(0, elm.value.length);
    }
    else if(elm.createTextRange) {
        var range = elm.createTextRange();
        range.collapse(true);
        range.moveStart('character', 0);
        range.moveEnd('character', elm.value.length);
        range.select();
    }
}

/**
 * perform actions that need done when the message box loses focus:
 *   - replace the callout image.
 *
 * @param {Object} elm
 */
ii.handle_messagebox_blur = function(elm){

    elm.style.backgroundImage = 'url(media/tab_poi_bground.png)';
    elm.style.backgroundRepeat = 'repeat-x';

    var img_elm = elm.parentNode.getElementsByTagName('img')[0];
    img_elm.src = './media/balloon_curve_SML.gif';
}

/**
 * a function to handle adding event listeners to all browsers
 *
 * @param {Object} elm the element to have the listener attached to
 * @param {Object} type the type of event to listen for
 * @param {Object} fn the function to call when the event fires.
 */
ii.addEvent = function(elm, type, fn){
    // add an event listener to the elm depending on whether the browser
    // suports the dom[1], is internet explorer[2], or something else[3],
    // when the event fires the fn will be called.

    try {
        // 1.
        elm.addEventListener(type, fn, true);
    }
    catch(e){
        try {
            // 2.
            elm.attachEvent('on'+type, fn);
        }
        catch(e){
            // 3.
            elm['on'+type] = fn;
        }
    }
}

ii.autosizeTextArea = function()
{
   if ( this.scrollHeight > this.clientHeight )
         this.style.height = this.scrollHeight + "px";
}

/**
 * given a string then insert a href where necessary and append to the element
 * e and return resulting html. if e is undefined, then the resulting html is
 * returned, but not appended to the dom.
 *
 * the function recognized extern hrefs (http://google.com) and
 * internal hrefs (#item=u.9). For the internals, a name lookup is performed
 *
 * @param {String} s the string of text to insert href.
 * @param {Object} e the element to inser the string into.
 */
ii.text2href = function(s, e){
    var url_match = /https?:\/\/([-\w\.]+)+(:\d+)?(\/([\w\./_-]*(\?\S+)?(#\S+)?)?)?/;
    var intern_match = new RegExp("(?:https?:\\/\\/" + window.location.host + "\\/)?#(\\w+)=([\\w\\.%]*)(?:&(\\w+)=([\\w\\.%]*))*", "g");

    var elm = e || document.createElement('p');

	for(;;) {
		var url_m = url_match.exec(s);
		var int_m = intern_match.exec(s);

		// url match comes first?
		if (url_m!=null && (int_m == null || url_m.index < int_m.index))
		{
			// add the text before the url as text
			if (url_m.index > 0) {
				elm.appendChild(
						document.createTextNode(s.substr(0,url_m.index))
				);
			}
			// add the url as link
			elm.appendChild(ii.elm('a', {
					href: url_m[0],
					rel: 'nofollow',
					target: '_blank'
				},
				url_m[0]
			));
			s = s.substr(url_m.index + url_m[0].length);
		}
		// intern match comes first?
		else if (int_m!=null)
		{
			// add the text before the url as text
			if (int_m.index > 0) {
				elm.appendChild(
						document.createTextNode(s.substr(0,int_m.index))
				);
			}

			// we need to wrap this part in a function
			// to make link a local var, and allow it
			// to be used as closure in ii.get
			(function() {
				var link = ii.elm('a', { href: int_m[0] }, int_m[0]);

				var properNameFound =false;

				// if we have an item property, we're gonna find a proper name
				for (var n=1; n < int_m.length-1; n+=2)
				{
					if (int_m[n] == 'item')
					{
						ii.log('using item: ' + int_m[n+1]);
						var itm = int_m[n+1].split('.');
						if (itm.length!=2)
							break;
						var tp = ii.typename[itm[0]];
						var id = itm[1];
						ii.get('q-items-'+tp,
							function(resp) {
								if (resp.items.length==1) {
									ii.setText(link, resp.items[0].name);
									link.className = 'micro '+tp;
								}
							},
							{
								id: id,
								fields: 'basic'
							}
						);
						properNameFound = true;

					}
				}
				// if no name found, try "tab" param for name
				if (!properNameFound) {
					for (n=1; n < int_m.length; n+=2) {
						if (int_m[n] == 'tab') {
							ii.setText(link, int_m[n+1]);
						}
					}
				}
				// add the url as link
				elm.appendChild(link);
			})();


			s = s.substr(int_m.index + int_m[0].length);
		}
		else
			break; // no more matches
	}

    if(s){
        elm.appendChild(document.createTextNode(s));
    }

    return elm.innerHTML;
}


/**
 * removes leading and trailing white space from string s
 *
 * @param {Object} s
 */
ii.trim = function(s){
    if( typeof s == 'string'){
        s.replace('/^\s+|\s+$/g', '');
    }
    return s;
}


ii.obj2json = function(input) {
    if (input===undefined) return 'null'
    switch (input.constructor) {
      case String: return '"' + input + '"'
      case Number: return input.toString()
      case Array :
        var buf = []
        for (var i in input)
          buf.push(ii.obj2json(input[i]))
            return '[' + buf.join(',') + ']'
      case Object:
        var buf = []
        for (var k in input)
          buf.push('"'+ k + '":' + ii.obj2json(input[k]))
            return '{ ' + buf.join(',') + '} '
	  case Boolean:
		return input ? 'true' : 'false';
      default:
        return 'null'
    }
}

// pass the name of the parameter that will change
// default parameter is "page"
// You can also pass a function that will be invoked
// whenever the pagenr changes. The function param will
// be the pagenr
//
// Will create this.divs[0] and this.divs[1] containing pagers
ii.Pager = function(urlparam)
{
	if (urlparam instanceof Function)
		this.callback = urlparam;
	else
		this.urlparam = (urlparam || 'page');

	this.counter = ii.elm('span', {className: 'cnt'}, ' (...)');
	this.divs = [
	 	ii.elm('div', {className:'pager'}),
		ii.elm('div', {className:'pager'})
	];

}


// Callback function for ii.Query object that is invoked when the count
// changes. This will create/update the pager-divs
ii.Pager.prototype.countItems = function(start, count, total, pagesize)
{
	// set counter in header
	ii.setText(this.counter, ' ('+total+')');

	// get page nr and page range
	var page =   1+(start/pagesize);
	var pages = Math.ceil(total/pagesize);
	var p1 = Math.max(1,page - 5);
	var p2 = Math.min(pages,page + 5);
	if (p2 >= 10)
	{
		var p1 = Math.max(1,page - 4);
		var p2 = Math.min(pages,page + 4);
	}

	var that = this;
	function pagelink(pagenr, name)
	{
		var l = ii.elm('a', name);
		if (!that.urlparam)
		{
			l.href ='#rel';
			l.onclick = function() { that.callback(pagenr); };
		}
		else
			l.href = '#rel&'+that.urlparam+'='+pagenr;


		return l;
	}


	for(var t = 0; t < 2; t++)
	{
		var target = this.divs[t];
		while(target.firstChild)
			target.removeChild(target.firstChild);

		if (pages==1)
			continue;

		if (start > 0)
		{
			target.appendChild(pagelink(page-1, '<<'));
			target.appendChild(document.createTextNode(' | '));
		}
		for(var n=p1; n <= p2; n++)
		{
			if (page == n)
				target.appendChild(ii.elm('span', {className:'sel'}, n.toString()));
			else
				target.appendChild(pagelink(n,n.toString()));

			if (n<p2)
				target.appendChild(document.createTextNode(' | '));
		}
		if (start+count < total)
		{
			target.appendChild(document.createTextNode(' | '));
			target.appendChild(pagelink(1+page,'>>'));
		}

	}
}


