/*
 *	Keep this file sparse with only widely-reusable functions
 *	requires jQuery, static/js_constants and mochi_compat
 */
var slide = slide || {};

slide.controls = {};
slide.controls.defaults = {};
slide.controls.debug = false;

slide.controls.createCheckGrid = function(persons, prefix, callback) {
	prefix = prefix || 'slide_ig_';
	var count = 0;
	var _p = DIV(null);
	persons.each(function (person) {
		var personId = slide.user.getId(person);
		var _i = null;
		var _n = DIV({'class' : 'selector_item'}, LABEL({'id':prefix + '_label_' + personId, 'class' : 'selector_label', 'for' : prefix + personId},
						_i = INPUT({'class' : 'selector_checkbox', 'type':'checkbox', 'id':prefix + personId, 'name':prefix + personId}),
						SPAN(null, friendName(person))));
		if (typeof(callback) == 'function')
			$(_i).click(function() { return callback(prefix + personId, personId ); });
		_p.appendChild(_n);
		count++;
	});
	return _p;
}

slide.controls.successDialog = function(message, optional_fadeout, optional_callback) {
	$('.ig_success_dialog').remove();
	var node_id = 'success_dialog_' + Math.random();
	var _n = DIV({'style' : 'background: #FFF9D7 none repeat scroll 0%; border: 2px solid #E2C822; padding: 8px; margin: 10px 5px; font-size: 14px;', 'id' : node_id, 'class' : 'ig_success_dialog'},
				STRONG(null, message));
	if (optional_fadeout)
		setTimeout(function() { $('.ig_success_dialog').fadeOut('slow', optional_callback); }, optional_fadeout);
	return _n;
}

slide.controls.errorDialog = function(message, optional_fadeout, optional_callback) {
	$('.ig_error_dialog').remove();
	var node_id = 'error_dialog_' + Math.random();
	var _n = DIV({'style' : 'background: #FFEBE8 none repeat scroll 0%; border: 2px solid #DD3C10; padding: 8px; margin: 10px 5px; font-size: 14px;', 'id' : node_id, 'class' : 'ig_error_dialog'},
				STRONG(null, message));
	if (optional_fadeout)
		setTimeout(function() { $('.ig_error_dialog').fadeOut('slow', optional_callback); }, optional_fadeout);
	return _n;
}

slide.controls.closeDialog = function(opt_callback) {
	$('.ig_dialog').slideUp('slow', opt_callback);
	return false;
}

slide.controls.dialog = function(dialog_type, msg, opt_fadeout, opt_callback, opt_permanent) {
	$('.ig_dialog').remove();

	var d_props = null;
	switch(dialog_type) {
		case 'info':
			d_props = { 'style' : 'color: #527491; background: #e5efff url(' + Serdes.make_static_url('/images/superpoke/opensocial/info_icon.gif') + ') no-repeat 10px 20px; border: 2px solid #3778c3;', 'border_color' : '#3778c3' }
			break;
		case 'error':
			d_props = { 'style' : 'background: #ffebe8 url(' + Serdes.make_static_url('/images/superpoke/opensocial/error_icon.gif') + ') no-repeat 10px 20px; border: 2px solid #dd3c10;', 'border_color' : '#dd3c10' }
			break;
		case 'success':
			d_props = { 'style' : 'color: #2b572a; background: #eaffcd url(' + Serdes.make_static_url('/images/superpoke/opensocial/success_icon.gif') + ') no-repeat 10px 20px; border: 2px solid #53a31e;', 'border_color' : '#53a31e' }
			break;
		case 'warning':
			d_props = { 'style' : 'background: #ffefcd url(' + Serdes.make_static_url('/images/superpoke/opensocial/warn_icon.gif') + ') no-repeat 10px 20px; border: 2px solid #e2c822;', 'border_color' : '#e2c822' }
			break;
	}

	if (typeof(msg) == 'string') {
		msg = H2(null, msg)
	}

	var close_link = (opt_fadeout || opt_permanent) ? SPAN()
								 : A({ href : "#", onclick : function() { return slide.controls.closeDialog(opt_callback) }, style : 'color: ' + d_props.border_color + '; text-decoration: none; font-weight: bold; display: block; float: right; margin: 5px;' }, 'X');

	var _n = DIV({ 'class' : 'ig_dialog', 'style' : d_props.style }, close_link, msg);
	if (opt_fadeout)
		setTimeout(function() { $('.ig_dialog').slideUp('slow', opt_callback); }, opt_fadeout);

	return _n;
}

slide.controls.preloader = function(target_div, height, width, opt_centered) {
	if(typeof(target_div) == "string") {
		var first_char = target_div.substring(0,1);
		if(first_char != "#" && first_char != ".") {
			target_div = "#" + target_div;
		}
	}
	var container = $(target_div);

	if(opt_centered == true) {
		container = $(CENTER());
		$(target_div).html("").append(container);
	}

	/* Always use the DOM contructors (DIV()), this is the rare exception where innerHTML is "acceptable" */
	height = height || 100
	width = width || 100
	var node_id = 'preloader_' + (Math.random() + 100000);
	var preloader = new FlashObject(Serdes.make_static_url('/images/preloader2.swf'),node_id,width,height,'8','');
	preloader.addParam("align", "middle");
	try {
		container.html(container.html() + preloader);
		for(var j=0; j<container.length; j++) {
			preloader.write(container[j]);
		}
	} catch (ex) {
		//	We're in IE and inserting the preloader (block-element) into a non-block element
		if (slide.controls.debug)
			alert('Failed to append the preloader to "' + target_div + '" because IE cannot insert a block element into a non-block element');
		return '';
	}
	return node_id;
}

/*******************/
/*   LinkSelector  */
/*******************/
slide.controls.LinkSelector = function(options, onselect, container, opt_separator) {
	//options: e.g. [{"name":"link 1 name", "value":value1}, {...}, ...]
	//onselect: a function to call with the value of a link that's selected
	this.options = options;
	this.onselect = onselect;

	this.container = container;

	this.selected_class = "linkselector_selected";
	this.unselected_class = "linkselector_unselected";
	this.separator = opt_separator==null?"|":opt_separator;

	this.selected_index = -1;
}

slide.controls.LinkSelector.prototype.render_to = function(jquery_obj) {
	if(jquery_obj) {
		this.container = jquery_obj;
	}
	this.container.empty();

	for(var i=0; i<this.options.length; i++) {
		if(i > 0) {
			this.container.append(DIV({"class":"linkselector_separator"}, this.separator));
		}
		if(i == this.selected_index) {
			this.container.append(DIV({"class":this.selected_class},
				this.options[i]["name"]
			));
		} else {
			var this_obj = this;
			var onclick = function(this_obj, option_index) {
				return function() {
					this_obj.select.apply(this_obj, [option_index]);
				}
			}(this_obj, i);
			this.container.append(DIV({"class":this.unselected_class, "style":"cursor:pointer", "onclick":onclick},
				SPAN({"style":"color:#3B5998;"}, this.options[i]["name"])
			));
		}
	}
	this.container.append(DIV({"style":"clear:both;"}));
}

slide.controls.LinkSelector.prototype.select = function(option_index) {
	this.selected_index = option_index;
	this.render_to(this.container);
	this.onselect(this.options[option_index]["value"], this.options[option_index]["name"]);
}

slide.controls.LinkSelector.prototype.select_by_value = function(value) {
	this.select(this.indexOf(value));
}

slide.controls.LinkSelector.prototype.set = function(option_index) {
	this.selected_index = option_index;
	this.render_to(this.container);
}

slide.controls.LinkSelector.prototype.set_by_value = function(value) {
	this.set(this.indexOf(value));
}

slide.controls.LinkSelector.prototype.indexOf = function(value) {
	for(var i=0; i<this.options.length; i++) {
		if(this.options[i]["value"] == value) {
			return i;
		}
	}
}

/********************/
/*     PAGINATOR    */
/********************/
slide.controls.Paginator = function(ids, verbose, show_pagination, num_of_page_links, per_page) {
	//ids is an array of strings specifying DOM element IDs, and the paginator will render into all of them
	//	ids may also be a string specifying a single DOM element ID,
	//  or a JQuery object
	//verbose: true if you want it to say "page x of y"
	//show_pagination: true if you want control to be visible
	//num_of_page_links: max number of page links to show, e.g. if it's 5 and you're on page 8 of 20, you'll see << 6 - 7 - *8* - 9 - 10 >>

	if(ids == undefined) {
		ids = [];
	} else if(typeof(ids) == "string") {
		this.id = ids;
		ids = [ids];
	} else if(!ids.length) {
		ids = [$(ids)];
	}
	for(var i=0; i<ids.length; i++) {
		if(typeof(ids[i]) == "string") {
			ids[i] = $("#" + ids[i]);
		} else {
			ids[i] = $(ids[i]);
		}
	}

	if(!num_of_page_links) {
		num_of_page_links = 5;
	}

	this.ids = ids; //An array of JQuery objects
	this.currentPage=0;
	this.itemsPerPage=per_page ? per_page : 10;
	this.shown_pages = num_of_page_links;
	this.verbose = (typeof(verbose) == 'undefined' ? true : verbose);
	this.show_pagination = (typeof(show_pagination) == 'undefined' ? true : show_pagination);
	this.total = null;

	this.unselected_class = "page";
	this.selected_class = "sel_page";
}

slide.controls.Paginator.prototype.update = function(total, page, per, callback) {
	if(total)
		this.total = total;
	else
		total = this.total;
	if (page)
	   this.currentPage = page;
	else {
		if(this.currentPage == undefined) this.currentPage=0;
		page=this.currentPage;
		}
	if (per)
	   this.itemsPerPage = per;
	else
		per=this.itemsPerPage
		
	var start = (page * per) + 1;
	if( total == 0 )
		start = 0;

	var end = (page * per) + per;

	if (end > total)
	   end=total;

	for(var j=0; j<this.ids.length; j++) {
		var container = this.ids[j];

		var header = SPAN({ 'class' : 'item_count'}, 'Items ' + start + ' - ' + end + ' of  ' + total);
		var links = DIV({
			'class' : 'controls_paginator_div',
			'id':'controls_paginator_div' //Might cause multiple divs with same IDs, but left in for backward compatibility
		});

		if (page > 0)
		   this.createLink(links, 'Prev', page-1, callback, false);

		var total_pages = Math.ceil(total/per);
		var half_shown_pages = parseInt(this.shown_pages/2)
		if (total_pages > 1) {
			var start_page = (total_pages > this.shown_pages && page > half_shown_pages) ? page - half_shown_pages : 0;
			var shown_pages = (total_pages > this.shown_pages) ? this.shown_pages : total_pages;
			if (page + half_shown_pages > total_pages && total_pages > this.shown_pages)
			   start_page = total_pages - this.shown_pages;
			for (var i = start_page; i < (start_page + shown_pages); ++i) {
				if (i < total_pages) { // Don't show more than maximum pages because of hardcoded shown_pages
					this.createLink(links, (i+1), i, callback, (i == page) );
				}
			}
		}

		if (end < total)
		   this.createLink(links, 'Next', page+1, callback, false);

		container.empty();
		if (this.show_pagination)
			container.append(links);
		if (this.verbose)
			container.append(header);
	}
}

slide.controls.Paginator.prototype.createLink = function(container, text, page, callback, selected) {
	var _t = this;
	var _n = SPAN({'style' : 'padding-left: 2px; padding-right: 2px; cursor: pointer;'},
				A({'class' : (selected ? this.selected_class : this.unselected_class), 'onclick' : function() { _t.setCurrentPage(page); callback(page); return false;}}, text));
	container.appendChild(_n);
}

slide.controls.Paginator.prototype.clear = function(opt_id) {
	if(opt_id) {
		//Old functionality of the clear function, for backwards compatibility
		$('#' + opt_id).empty();
	}
	else {
		for(var j=0; j<this.ids.length; j++) {
			this.ids[j].empty();
		}
	}
	this.currentPage = 0;
}
slide.controls.Paginator.prototype.setCurrentPage = function(page) { this.currentPage = page; }
slide.controls.Paginator.prototype.getCurrentPage = function() { return this.currentPage; }
slide.controls.Paginator.prototype.getItemsPerPage = function() { return this.itemsPerPage; }
slide.controls.Paginator.prototype.setItemsPerPage = function(per) { this.itemsPerPage = per; }


slide.controls.Paginator.prototype.renderPage = function(page) {
	var per = this.getItemsPerPage();
	var max = this.my_data.length;
	var target = $(this.my_target).html('');
	
	for(var i = page * per ; ( (i<max) && (i< (page+1)*per) ) ; i++) {
		target.append( this.callback(this.my_data[i]));
	}
	
	var _t=this;
	this.update(false, page, false, function(page) {
			_t.renderPage(page);
		});
}

slide.controls.Paginator.prototype.paginateThis = function(target, datas, callback) {
	this.total=datas.length;
	this.my_data=datas;
	this.my_target=target;
	this.callback=callback;
	this.renderPage(0);
}



/********************/
/* ALPHA PAGINATOR  */
/********************/

slide.controls.AlphaPaginator = function(id, id2, verbose) {
	//id can also be a JQuery object
	if(typeof(id)=="string" && id2 && typeof(id2)=="string") {
		id = [$("#" + id), $("#" + id2)];
	}

	slide.controls.Paginator.call(this, id, verbose);
	this._alpha_collection = null;
	this._alpha_index = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ'
	this._alpha_page_index = null;
	this.preload_container=null;
}
slide.controls.AlphaPaginator.prototype = new slide.controls.Paginator();
/*
slide.controls.AlphaPaginator.prototype.initAlphaIndex = function(alpha_collection) {
	slide.console.log("initAlphaIndex start");
	this._alpha_collection = alpha_collection;

	this._alpha_page_index = new Array()

	// initialize the pagecounts to 0
	for (var i = 0; i < this._alpha_index.length; i++)
		this._alpha_page_index[i] = 0

	slide.console.log("initAlphaIndex step");
	for (var i = 0; i < this._alpha_collection.length; i++) {
		var current_alpha_index = this._alpha_index.indexOf((this._alpha_collection[i].getDisplayName() || '#').charAt(0).toUpperCase())
		if (current_alpha_index == -1) current_alpha_index = 0
		this._alpha_page_index[current_alpha_index] += 1

	}
	slide.console.log("initAlphaIndex end");
}*/

slide.controls.AlphaPaginator.prototype.update = function( letter, page, total, per, alpha_callback) {
	var msg="AlphaPaginator.update(" + letter + "," + page + "," + total + "," + per + ") start";
	slide.console.log(msg);
	this.current_letter = letter;

	this.currentPage = page;

	this.itemsPerPage = per;

	var total; // ?????????


	if (!isNaN(this.currentPage)) {
		var start = (this.currentPage * per) + 1;
		if( total == 0 )
			start = 0;

		var end = (this.currentPage * per) + per;

		if (end > total)
		   end=total;
	} else {
		var alpha_num = this._alpha_page_index[(this._alpha_index.indexOf(this.currentPage) == -1) ? 0 : this._alpha_index.indexOf(this.currentPage)]
		var start = alpha_num == 0 ? 0 : 1
		var end = alpha_num
		total = end
	}

	if (this.verbose)
		var itemized = SPAN({ 'class' : 'item_count'}, 'Listing ' + start + ' - ' + end + '&nbsp;&nbsp;of&nbsp;&nbsp;' + total + '&nbsp;&nbsp;&nbsp;&nbsp;');
	var links = DIV({ 'style' : ' padding: 5px;'});
	var links2 = DIV({ 'style' : ' padding: 5px;'});

	if (!isNaN(this.currentPage) && this.currentPage > 0) {
	   this.createLink(links , '&#171; Prev &nbsp;',this.current_letter,  this.currentPage-1, alpha_callback, false);
	   this.createLink(links2 , '&#171; Prev &nbsp;',this.current_letter,  this.currentPage-1, alpha_callback, false);
	   }


	var alpha_links  = DIV({'style' : 'padding: 5px;'});
	var alpha_links2 = DIV({'style' : 'padding: 5px;'});
	this.createLink(alpha_links , 'All Friends',null, 0, alpha_callback, (this.current_letter==null && this.current_letter!="search" ? true : false));
	this.createLink(alpha_links2, 'All Friends',null, 0, alpha_callback, (this.current_letter==null && this.current_letter!="search" ? true : false));
	$(alpha_links ).add(alpha_links2).append(SPAN(null, '&nbsp;&nbsp;|&nbsp;&nbsp;'));

	if(this.preload_complete)
	{
		var letter_is_selected, this_letter;
		for (var i = 0; i < this._alpha_index.length; i++) {
			this_letter = this._alpha_index.charAt(i);
			letter_is_selected = (this.current_letter == this_letter);

			this.createAlphaLink(alpha_links , this_letter, this_letter, 0, alpha_callback, letter_is_selected);
			this.createAlphaLink(alpha_links2, this_letter, this_letter, 0, alpha_callback, letter_is_selected);
		}

	} else {

		var preloader = '<embed width="15" height="15" align="bottom" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" src="'+Serdes.make_static_url('/images/preloader2.swf')+'" />';

		alpha_links.appendChild(SPAN({'style' : 'padding: 0 3px; font-weight: bold;color: rgb(137, 137, 137);'},
			preloader+" &nbsp; Loading friends list..."));
		alpha_links2.appendChild(SPAN({'style' : 'padding: 0 3px; font-weight: bold;color: rgb(137, 137, 137);'},
			preloader+" &nbsp; Loading friends list..."));
	}

	var total_pages = Math.ceil(total/per);
	if (total_pages > 1) {
		var start_page = (total_pages > 5 && page > 2) ? this.currentPage - 2 : 0;
		var shown_pages = (total_pages > 5) ? 5 : total_pages;
		if (this.currentPage + 2 > total_pages && total_pages > 5)
		   start_page = total_pages - 5;
		for (var i = start_page; i < (start_page + shown_pages); ++i) {
			if (i < total_pages) { // Don't show more than maximum pages because of hardcoded shown_pages
				this.createLink(links ,  (i+1), this.current_letter, i, alpha_callback, (i == this.currentPage) );
				this.createLink(links2 ,  (i+1), this.current_letter, i, alpha_callback, (i == this.currentPage) );
			}
		}
	}

	if (!isNaN(this.currentPage) && end < total) {
		this.createLink(links, '&nbsp; Next &#187;', this.current_letter, this.currentPage+1, alpha_callback, false);
		this.createLink(links2, '&nbsp; Next &#187;', this.current_letter, this.currentPage+1, alpha_callback, false);
		}
	
	if(this.verbose) {
		$(links).prepend(itemized);
		$(links2).prepend(itemized);
	}
	var containers = $([]);
	
	for(var i=0; i<this.ids.length; i++) {
		try {
			if(i==0) {
				$(this.ids[i]).empty().append( alpha_links );
			} else if(i==1) {
				$(this.ids[i]).empty().append( alpha_links2);
			} else {
				$(this.ids[i]).empty().append( $(alpha_links).clone(true));
			}
		} catch(ex) {
			// IE always throws an unknown error that normally terminates the thread
			// That's why this catch block is needed. (Or we could figure out what the error is.)
			// -Liron
		}
		if(i==0) {
			$(this.ids[i]).append(DIV({"style":"border-top: 1px solid #dbdbdb;"}, links ));
		} else if(i==1) {
			$(this.ids[i]).append(DIV({"style":"border-top: 1px solid #dbdbdb;"}, links2 ));
		} else {
			$(this.ids[i]).append(DIV({"style":"border-top: 1px solid #dbdbdb;"}, $(links).clone(true)));
		}
		
	}

	delete links,links2,alpha_links,alpha_links2;
}
slide.controls.Paginator.prototype.setCurrentPage = function(letter,page) { this.current_letter = letter; this.currentPage = page; }

slide.controls.AlphaPaginator.alphalinkcounter = 0;
slide.controls.AlphaPaginator.prototype.createAlphaLink = function(container, text, letter, page, callback, selected) {
	var _t = this;
	slide.controls.AlphaPaginator.alphalinkcounter++;
	var _id = 'alphapaginator_alphalink_' + slide.controls.AlphaPaginator.alphalinkcounter;
	var _n = SPAN({'class' : 'selector_span'},
				A({'id': _id, 'class' : (selected ? this.selected_class : this.unselected_class)}, text));
	container.appendChild(_n);
	setTimeout(function() { jQuery('#' + _id).click(function() { _t.setCurrentPage(text); callback(letter, page); return false;}); }, 0);
}


slide.controls.AlphaPaginator.linkcounter = 0;
slide.controls.AlphaPaginator.prototype.createLink = function(container, text, letter, page, callback, selected) {
	var _t = this;
	slide.controls.AlphaPaginator.linkcounter++;
	var _id = "alphapaginator_link_" + slide.controls.AlphaPaginator.linkcounter;
	var _n = SPAN({'class' : 'selector_span'},
				A({'id': _id, 'class' : (selected ? this.selected_class : this.unselected_class)}, text));
	container.appendChild(_n);
	setTimeout(function() { jQuery('#' + _id).click(function() { _t.setCurrentPage(page); callback(letter, page); return false;}); }, 0);
}

/*******************/
/* Icon scroller   */
/*******************/
var _HORIZONTAL = 1;
var _VERTICAL = 2;
slide.controls.IconScroller = function( container, icons, extractor, callback, icon_width, icon_height, cont_width, cont_height, orientation, rows_or_cols) {
  /*
    | Provides a scrollable div with icons inside. 'icons' should be a collection of data, not necessarily the actual image files. extractor is a function to get the image from the data.
    | Callback is a function called when an icon is clicked on, passed the original data object. rows_or_cols is the fixed row or column number; vertical is fixed columns, horizontal is fixed rows.
    | Arrows are provided if necessary.
  */

  this.setContainer(container);
  this.icons = icons;

  this.extractor = ( extractor ? extractor : function (item) { return item; } );
  this.callback = (callback ? callback : function (item) { slide.console.log("No callback for "+$.toJSON(item)); } );
  
  if (orientation == _VERTICAL) {
    this.orientation = _VERTICAL;
    this.show_cols = rows_or_cols;
    this.show_rows = -1;
    this.arrow_height = 7;
    this.arrow_width = 14;
  } else {
    this.orientation = _HORIZONTAL;
    this.show_cols = -1;
    this.show_rows = rows_or_cols;
    this.arrow_height = 64;
    this.arrow_width = 7;
  }


  this.icon_width = ( icon_width ? icon_width : 50);
  this.icon_height = ( icon_height ? icon_height : 50);
  this._scroll_speed = "slow";
  this._up_img="/images/interface/arrow_up.gif";
  this._down_img="/images/interface/arrow_down.gif";
  this._left_img="/images/interface/arrow_left.gif";
  this._right_img="/images/interface/arrow_right.gif";
  this.container_width = cont_width;
  this.container_height = cont_height;
}

slide.controls.IconScroller.prototype.setContainer = function(container) {
  if(container == undefined || container == null )
    this.container = undefined;
  else if( typeof(container) == "string") {
    var first_char = container.substring(0,1);
    if(first_char != "#" && first_char != ".") {
      container = "#" + container;
    }
  }
  this.container = $(container)[0];
}

slide.controls.IconScroller.prototype.render = function() {
  var _t = this; // this is required for scoping.
  $(this.container).html("");

  this.scroller = DIV({"style":"position:absolute; overflow:hidden; left:0px; top:2px"});

  if ($(this.container).css("position")!="absolute") {
    $(this.container).css("position","relative");
  }

  if (! this.container_width) {
    this.container_width = parseInt($(this.container).width(),10);
  }
  if (! this.container_height) {
    this.container_height = parseInt($(this.container).height(),10);
  }
  
  if (this.orientation == _HORIZONTAL) {
    this.scroller_height = Math.max((this.icon_height*this.show_rows + (this.show_rows-1) * 2), this.arrow_height); // 2px padding between icons
    this.icon_cols = Math.ceil(this.icons.length/this.show_rows);
    this.icon_rows = this.show_rows;
    this.onscreen_cols = Math.floor(this.container_width/this.icon_width);
    this.scroller_width = this.icon_cols * this.icon_width + (this.icon_cols-1) * 2; // 2px padding between icons
    $(this.scroller).css({"height":this.scroller_height, "width":this.scroller_width, "margin-left":(this.arrow_width+4), "margin-right":(this.arrow_width+4)});
    $(this.container).css({"height":this.scroller_height, "width":this.container_width, "overflow":"hidden"});
  } else { // vertical
//     $(this.scroller).css("top", (this.arrow_height+2) + "px");
    this.scroller_width = this.icon_width*this.show_cols + (this.show_cols-1) * 2; // 2px padding between icons
    this.icon_rows = Math.ceil(this.icons.length/this.show_cols);
    this.icon_cols = this.show_cols;
    this.onscreen_rows = Math.floor(this.container_height/this.icon_height);
    this.scroller_height = this.icon_rows * this.icon_height + (this.icon_rows-1) * 2; // 2px padding between icons
    $(this.scroller).css({"height":this.scroller_height, "width":this.scroller_width, "margin-right":(this.arrow_width+4)});
    $(this.container).css({"height":Math.min(this.container_height, this.scroller_height)+this.arrow_height*2+6, "width":null, "overflow":"hidden", "margin-right": "12px"}); // arrows are displayed on top and bottom
  }
  $.each(this.icons, function(i, val) {
      var x, y;
      if (_t.orientation == _HORIZONTAL) {
	y = i % _t.show_rows;
	x = Math.ceil((i+1)/_t.show_rows)-1;
      } else {
	x = i % _t.show_cols;
	y = Math.ceil((i+1)/_t.show_cols)-1;
      }
      
      var imgElement = IMG({
	  "id": 'scrolledIcon_' + (Math.random() + 100000),
	    "src":Serdes.make_static_url(_t.extractor(val)),
	    "style":"cursor:pointer;margin:0px;padding:0px;position:absolute;",
	    "width":_t.icon_width,
	    "height":_t.icon_height,
	    "onclick":function(e) {
	    _t.callback(val,e); return false;
	  }
	}
	);
      $(imgElement).css("top", (y*_t.icon_height + y*2));
      $(imgElement).css("left", (x*_t.icon_width + x*2));
      _t.scroller.appendChild(imgElement);
    });
 
  if (this.orientation == _HORIZONTAL) {
    if ((this.scroller_width-this.container_width) > 0) {
      this.container.appendChild(
				 DIV({"style":"background:white;position:absolute;left:0px;padding:2px;top:2px;"},
				     A({"href":"#", "onclick": function(){_t.scrollUp(_t.icon_cols, _t.onscreen_cols); return false;} },
				       IMG({"src":Serdes.make_static_url(this._left_img)}))
				     )
				 );

      this.container.appendChild(
				 DIV({"style":"background:white;position:absolute;padding:2px;right:0px;top:2px;"},
				     A({"href":"#", "onclick": function(){_t.scrollDown(_t.icon_cols, _t.onscreen_cols);return false;} },
				       IMG({"src":Serdes.make_static_url(this._right_img)}))
				     )
				 );
    }
  }
  else {
    if ((this.scroller_height-this.container_height) > 0) {
      this.container.appendChild(
				 DIV({"style":"background:white;position:absolute;left:" + (this.scroller_width/2) + "px;top:0px;"},
				     A({"href":"#", "onclick": function(){_t.scrollUp(_t.icon_rows, _t.onscreen_rows); return false;} },
				       IMG({"src":Serdes.make_static_url(this._up_img)}))
				     )
				 );

      this.container.appendChild(
				DIV({"style":"background:white;position:absolute;left:" + (this.scroller_width/2) + "px;top:" + (this.container_height + this.arrow_height+6) + "px;"},
				    A({"href":"#", "onclick": function(){_t.scrollDown(_t.icon_rows, _t.onscreen_rows);return false;} },
				       IMG({"src":Serdes.make_static_url(this._down_img)}))
				     )
				 );
    }

  }

  if (this.orientation == _VERTICAL) {
    var scroller_container = DIV({}, "&nbsp;");
    $(scroller_container).css({"height":Math.min(this.container_height, this.scroller_height), "width":this.scroller_width, "overflow":"hidden", "top": (this.arrow_height+4)+"px", "position":"absolute"});
    $(this.scroller).css("top", "0px");
    scroller_container.appendChild(this.scroller);
    this.container.appendChild(scroller_container);
  } else {
    this.container.appendChild(this.scroller);
  }

  this.scrolledTo = 0; // Currently 1st icon displayed

  return this.container;
}



slide.controls.IconScroller.prototype.scrollUp = function(unit_count, onscreen) {

  unit_count -= onscreen; // we need to be zero-indexed
  if(this.scrolledTo > 0 ) {
    this.scrolledTo--;
    slide.console.log("scrollUp: up we go! ("+this.scrolledTo+"/"+unit_count+")");
    if(this.orientation == _HORIZONTAL) {
      $(this.scroller).animate({marginLeft: "+=" + (this.icon_width+2) + "px"},this._scroll_speed)
	} else {			
      $(this.scroller).animate({marginTop: "+=" + (this.icon_width+2) + "px"},this._scroll_speed)
	}
  } else slide.console.log("scrollUp: got to the limit! ("+this.scrolledTo+"/"+unit_count+")");
	
}


slide.controls.IconScroller.prototype.scrollDown = function(unit_count, onscreen) {

  unit_count -= onscreen; // we need to be zero-indexed
  if(this.scrolledTo < unit_count ) {
    this.scrolledTo++;
    slide.console.log("scrollDown: down we go! ("+this.scrolledTo+"/"+unit_count+")");
    if(this.orientation == _HORIZONTAL) {
      $(this.scroller).animate({marginLeft: "-=" + (this.icon_width+2) + "px"},this._scroll_speed)
	} else {			
      $(this.scroller).animate({marginTop: "-=" + (this.icon_width+2) + "px"},this._scroll_speed)
	}		
  } else slide.console.log("scrollDown: got to the limit! ("+this.scrolledTo+"/"+unit_count+")");
}
