function SSP(url) {
	if(url) this.load(url);
	}

$.extend(SSP.prototype, {
	'url' : null,
	'dom' : null,
	'onload' : null,
	'loaded' : false,
	'albums' : null,
	
	'load' : function(url) {
		this.url = url;
		var self = this;
		$.ajax({ 'url':url, 'complete':function(r,s) { self._finishLoad(r,s) } });
		},
	
	'_finishLoad' : function(r, success) {
		if(success != 'success' || !r.responseXML) {
			throw new Error('error loading '+this.url);
			}
		
		this.dom = r.responseXML;
		this.albums = $.map(
			$('album', this.dom),
			function(a) { return new SSP.Album(a) }
			);
		
		this.loaded = true;
		if(this.onload) this.onload();
		},
	
	'setOnload' : function(f) {
		if(this.onload == null && this.loaded) {
			this.onload = f;
			this.onload();
			}
		else {
			this.onload = f;
			}
		}

	});

$.extend(SSP, {
	'_makeAbs' : function(url, base) {
		if(!base) {
			var base = document.location.href;
			if (base.indexOf('?') != -1) base = base.substring(0, base.indexOf('?'));
			var baseTags = document.getElementsByTagName('base');
			if(baseTags.length && baseTags[0].getAttribute('href'))
				base = this._makeAbs(baseTags[0].getAttribute('href'), base);
			}
		if(!url) return base;
		if (url.indexOf('://') == -1 && url.charAt(0) != '/') url = base.substring(0, base.lastIndexOf('/')) + "/" + url;
		return url;
		},
	
	'_decodeEntities' : function(s) {
		if(s && $.browser.safari) {
			var matches = s.match(/&#\d+;?/g);
			if(matches) {
				for(var i = 0; i < matches.length; i++) {
					var replacement = String.fromCharCode((matches[i]).replace(/\D/g,""));
					s = s.replace(/&#\d+;?/,replacement);
					}
				}
			}
		return s;
		}
	
	});

/* --------------------------------------------------------------- */

SSP.Album = function(dom) {
	this.dom = $(dom);
	var d = this.dom;
	
	this.id = d.attr('id');
	this.title = SSP._decodeEntities(d.attr('title'));
	this.description = SSP._decodeEntities(d.attr('description'));
	this.tnPath = SSP._makeAbs(d.attr('tnPath'));
	this.lgPath = SSP._makeAbs(d.attr('lgPath'));
	this.tn = SSP._makeAbs(d.attr('tn'));
	
	var self = this;
	this.images = $.map(
		$('img', d[0]),
		function(i) { return new SSP.Image(i, self) }
		);
	}

$.extend(SSP.Album.prototype, {
	'dom' : null,
	'id' : null,
	'title' : null,
	'description' : null,
	'tnPath' : null,
	'lgPath' : null,
	'tn' : null,
	'images' : null
	});

/* --------------------------------------------------------------- */

SSP.Image = function(dom, album) {
	this.dom = $(dom);
	var d = this.dom.get(0);
	this.src = album.lgPath + d.getAttribute('src');
//	this.src = SSP._makeAbs(d.getAttribute('src'), album.lgPath);
	this.caption = SSP._decodeEntities(d.getAttribute('caption'));
	this.link = d.getAttribute('link');
	this.target = d.getAttribute('target');
	}

$.extend(SSP.Image.prototype, {
	'dom' : null,
	'src' : null,
	'caption' : null,
	'link' : null,
	'target' : null
	});

/* --------------------------------------------------------------- */

SSP.Viewer = function() {}

$.extend(SSP.Viewer.prototype, {
	'img' : null,
	'album' : null,
	'selected' : null,
	'preloaded' : null,
	
	'num' : function() {
		return this.album.images.length;
		},
	
	'select' : function(n) {
		this.selected = n;
		this.preload([n, n+1, n-1]);
		if(this.onchange) this.onchange();
		},
	
	'preload' : function(a) {
		this.preloaded = [];
		for(var i = 0; i < a.length; i++) {
			var n = a[i];
			if(n < 0) n += this.num();
			n = n % this.num();
			var img = new Image();
			img.src = this.album.images[n].src;
			this.preloaded.push(img);
			}
		},
	
	'next' : function(n) {
		var s = this.selected + (n || 1);
		if(s < 0) s += this.num();
		s = s  % this.num();
		this.select(s);
		},
	'previous' : function(n) { this.next( - (n || 1)) },
	
	'first' : function() { this.select(0) },
	'last' : function() { this.select(this.num()-1) },
	
	'setAlbum' : function(album, start) {
		this.album = album;
		this.select(start || 0);
		},
	
	'onchange' : function() {
		var image = $(this.img);
		if(image.length) {
			if(image.css('position') == 'absolute' || image.css('position') == 'relative') {
				var i2 = $(image).clone();
				i2.hide();
				i2.attr('src', this.album.images[this.selected].src);
				image.after(i2);
				image.fadeOut(100);
				i2.fadeIn(800, function() { image.show(); image.attr('src', i2.attr('src')); i2.remove() } );
				}
			else {
				image.attr('src', this.album.images[this.selected].src);
				}
			}
		}
	
	});
