String.prototype.truncate = function(l)
{
	if (this.length > l) {
	    return this.substr(0,l) + '...';
	} else {
		return this;
	}
}

Scroller = Class.create();
Scroller.prototype = {
	initialize: function(preload_data) {		
		this.sets = $H();
		this.current_set = 0; // When first created there should be 5 sets provided in the preload_data, the current set will be 0, the center one.
		this.other_set = null;
		this.ajax_reqs = [];
		this.selected_bookmark = null;
		
		this.scroll_direction = null;
		this.playing = false; // Why two modes? Well if we goto set whilst in continuous we need go back to that mode. The same goes if we're paused first.
		this.scroll_mode = 'paused'; // 'set', 'continuous' or 'paused'
		this.played = false;
		this.paused = false;
		this.scroll_interval = null;
		this.scroll_distance = 0;
		
		this.scroll_speed = $H({"set" : 50, "continuous" : 20});
		this.scroll_pixels_each_movement =  $H({"set" : 40, "continuous" : 1});
		this.pixels_for_movement = null;
		
		// These values could be fetched from the css
		this.set_width = 550;
		this.item_width = this.set_width / 10
		this.left_side = 0; // This is the left value in pixels which would position a set in the center of the viewport
		
		this.total_sets = 50;
		this.preload_num_sets = 2;
		this.source_url = '/main/scroller/'
		
		this.set_event_handlers();
		this.parse_preload_data(preload_data);
	},
		
	parse_preload_data: function(preload_data) {
		preload_data.each(function(set_data) {
			this.create_set(set_data[0], set_data[1]);
		}.bind(this));
		// Set position of current set
		this.sets[0].set_position(this.left_side);
	},
	
	parse_set_data: function(req) {
		var set_data = eval(req.responseText);
		this.create_set(set_data[0], set_data[1]);
		this.ajax_reqs[set_data[0]] = null;
		if(set_data[0] > this.current_set){
            $('scroller_spinner_next').style.display = 'none';
        }else{
            $('scroller_spinner_previous').style.display = 'none';
        }
	},
	
	set_event_handlers: function() {
		//Event.observe('scroller_controls', 'click', this.toggle_play.bindAsEventListener(this));
        
		Event.observe('scroller_next', 'click', this.next_set.bindAsEventListener(this));
		Event.observe('scroller_previous', 'click', this.prev_set.bindAsEventListener(this));
		
		// The little opwards facing arrow will follow the cursor along the x axis
		//Event.observe('scroller_viewport', 'mousemove', this.stalk_cursor.bindAsEventListener(this));
		//Event.observe('scroller_viewport', 'mouseover', this.over_viewport.bindAsEventListener(this));
		//Event.observe('scroller_viewport', 'mouseout', this.off_viewport.bindAsEventListener(this));
	},
	
	// Create a new scroller set, then set the correct positition for it
	create_set: function(set_id, set_data) {
		this.sets[set_id] = new ScrollerSet(set_id, set_data);
		$('scroller_viewport').appendChild(this.sets[set_id].ul);
		//this.sets[set_id].set_event_handlers();
	},
	
	// Callbacks for events
	
	next_set: function() {
		this.scroll_conveyor_belt('left', this.set_width);
	},
	
	prev_set: function() {
		this.scroll_conveyor_belt('right', this.set_width);
	},
	
//	toggle_play : function(){
//	    if (this.scroll_mode == 'paused') {
//            this.play_mode();
//            $('scroller_controls').className = 'playing';
//        }else{
//            this.pause_button();
//            $('scroller_controls').className = 'paused';
//        }
//	},
	
//	play_button: function() {
//		this.play_mode();
//	},
	
//	pause_button: function() {
//		var distance = this.item_width - Math.abs(this.sets[this.current_set].xpos)%this.item_width;
//		this.playing = false;
//		this.scroll_conveyor_belt('left', distance);
//	},
	
/*	
	play_mode: function() {
		if (this.scroll_mode == 'paused') {
			// Only go if there's a set preloaded
			if (this.sets[this.other_set_id('next', this.current_set)] != undefined) {
				this.display_center_bookmark_details();
			
				if ((this.scroll_direction == 'right') && (this.played == true)) {
					this.swap_sets();
				}
				
				this.played = true;	
				this.playing = true;
				this.scroll_mode = 'continuous';
				this.scroll_direction = 'left';
				this.preload_sets();
				this.start_animation();
			}
		}
	},
	
	pause_mode: function() {
		// Only pause if we're currently moving
		if (this.scroll_mode == 'continuous') {
			this.stop_animaiton();
			this.playing = false;
			this.scroll_mode = 'paused';
		}
	},
*/
	
//	over_viewport: function() {
//		this.paused = this.playing;
//		this.pause_mode();
//	},
	
//	off_viewport: function() {
//		if (this.paused == true) {
//			this.play_mode();
//		}
//	},

	// Stalk the cursor and position the little up arrow on the same x axis as it
//	stalk_cursor: function(event) {
//		$('scroller_current').style.left = (Event.pointerX(event) - this.get_x_pos($('scroller_items'))) + 'px';
//	},	
	//
/*	
	set_selected_bookmark: function(bmark) {
		if (bmark) {
			if (this.selected_bookmark != null) {
				this.selected_bookmark.className = "";
			}
		
			bmark.className = 'current';
			this.selected_bookmark = bmark;
		}
	},
	
	display_center_bookmark_details: function() {
		var center_point = this.set_width / 2;
		
		var center_set = this.sets[this.current_set];
		
		if (this.scroll_direction == 'left') {
			if ((this.set_width + center_set.xpos) <= center_point) {
				var center_set = this.sets[this.other_set];
			}
		} else {
			if (center_set.xpos >= center_point) {
				var center_set = this.sets[this.other_set];
			}
		}
		
		var center_bmark_id = Math.floor((Math.abs(center_set.xpos - center_point)) / this.item_width)
		
		// Show it's selected
		this.set_selected_bookmark($('bmark_' + center_set.set_id + '_' + center_bmark_id));
		// Dispaly its details
		center_set.show_bookmark_details(center_bmark_id);
		// Put the current arrow in the center
		$('scroller_current').style.left = '50%';
	},
*/	
	
	swap_sets: function() {
		var tmp_set = this.current_set;
		this.current_set = this.other_set;
		this.other_set = tmp_set;
	},
	
	other_set_id: function(direction, cur_set) {
		if ((direction == 'next') || (direction == 'left')) {
			if (cur_set >= this.total_sets) {
				return 0;
			} else {
				return cur_set + 1;
			}
		} else {
			if (cur_set == 0) {
				return this.total_sets;
			} else {
				return cur_set - 1;
			}
		}
	},

	// Fetch data for a set if it doesn't exist
	fetch_data_for_set: function(set_id) {
		if ((this.sets[set_id] == undefined) && (this.ajax_reqs[set_id] == null)) {
//		    if(this.scroll_direction == "left"){
//                $('scroller_spinner_next').style.display = 'block';
//            }else{
//                $('scroller_spinner_previous').style.display = 'block';
//            }
			this.ajax_reqs[set_id] = new Ajax.Request(this.source_url + set_id, { method: 'get', onSuccess: this.parse_set_data.bind(this) });
		}
	},
	
	// Ensure there are at least two sets preloaded in the current direction
	preload_sets: function() {
		var set_id = this.current_set;
		// Here we check there are this.preload_num_sets worth of preloaded sets in the current direction of movement. We add 1 to this thought because the current set will be the old one, not he one we're about to move too.
		for(var i = 0; i < (this.preload_num_sets + 2); i++) {
			this.fetch_data_for_set(set_id);
			set_id = this.other_set_id(this.scroll_direction, set_id);
		}
	},
	
	sufficient_preloaded_sets: function() {
		if ((this.sets[this.other_set_id('next', this.current_set)] == undefined) || (this.sets[this.other_set_id('prev', this.current_set)] == undefined)) {
			return false;
		} else {
			return true;
		}
	},
	
	scroll_conveyor_belt: function(direction, distance) {

		// Check there's a set preloaded and we're not already doing an inimation
		if (this.scroll_mode != 'set') {
			var do_scroll = true;
			
			// There needs to be a set to scroll on screen
			if (this.sets[this.other_set_id(direction, this.current_set)] != undefined) {				
				// Stop the current movement before we make a new interval
				this.stop_animaiton();
				
				// Here we should check if we were previously moving a different way, and if so, swap the current and other set ids around
				if ((this.scroll_direction != null) && (this.scroll_direction != direction) && (this.other_set != null)) {
					if (this.played == true) {
						this.swap_sets();
					}
				}
				
				this.scroll_distance = distance;
				this.scroll_direction = direction;
				this.scroll_mode = 'set';
				
				this.preload_sets();
		
				this.start_animation();
			}else{
					
			
				/*this.scroll_distance = 2200;
				this.scroll_direction = "right";
				this.scroll_mode = 'set';
				
				this.preload_sets();
		
				this.start_animation();*/
				//this.set_position(0);

			    /*$('scroller_loading').innerHTML = "Loading";                
                Element.setOpacity('scroller_loading', 0.0);
                $('scroller_loading').style.display = 'block';*/
				//alert("end");
			    /*new Effect.Fade('scroller_loading', {from : 0.0, to : 1.0, duration : 1.0, queue : {position : 'front', scope : 'loading'}});
			    new Effect.Fade('scroller_loading', {from : 1.0, to : 0.0, duration : 2.0, queue : {position : 'end', scope : 'loading'}}); */
			    
			}
		}
	},

	stop_animaiton: function() {
		clearInterval(this.scroll_interval);
		this.scroll_interval = null;
	},
	
	start_animation: function() {
		this.pixels_for_movement = this.scroll_pixels_each_movement[this.scroll_mode];
		this.scroll_interval = setInterval(this.animation_movement.bind(this), this.scroll_speed[this.scroll_mode]);
	},
	
	animation_movement: function() {
		if (this.sets[this.current_set] == undefined) {
			this.preload_sets();
		} else {
			var cur_new_pos = this.sets[this.current_set].xpos;
			var oth_new_pos = null;
			var end_set_scroll = false;
			var end_of_set = false;
		
			if (this.other_set == null) {
				this.other_set = this.other_set_id(this.scroll_direction, this.current_set);
			}
			
			// Calcular distance to move
		
			if ((this.scroll_mode == 'set') && ((this.scroll_distance - this.pixels_for_movement) <= 0)) {
				// If this movement will put us beyond the desired distance, work out exactly how many pixels to move to end up exactly at the desired scroll_distance
				this.pixels_for_movement = this.scroll_distance;
				this.scroll_distance = 0;
				end_set_scroll = true;
			}
		
			// Calculate new positions
		
			if (this.scroll_direction == 'left') {
				cur_new_pos = cur_new_pos - this.pixels_for_movement;
				oth_new_pos = cur_new_pos + 550;
				
				if (oth_new_pos <= 0) {
					end_of_set = true;
				}
			} else {	
				cur_new_pos = cur_new_pos + this.pixels_for_movement;
				oth_new_pos = cur_new_pos - 550;
				
				if (oth_new_pos >= 0) {
					end_of_set = true;
				}
			}

			if (this.sets[this.other_set_id(this.scroll_direction, this.current_set)] != undefined) {
				this.sets[this.current_set].set_position(cur_new_pos);
				this.sets[this.other_set].set_position(oth_new_pos);

				if (this.scroll_distance > 0 && this.scroll_mode == 'set') {
					this.scroll_distance -= this.pixels_for_movement;
				}
			}

			if (end_of_set == true) {
				this.sets[this.current_set].hide_me();
				this.current_set = this.other_set;
				this.other_set = null;

				// Preload some more sets now one has gone out of view
				this.preload_sets();
			}
			
			if (cur_new_pos%110 == -58) {
				// If we're in continuous mode, every time we move the distance of an item, we should recalculate the center one and display its details
				//this.display_center_bookmark_details();
			}
	
			// Stop if we've reached the end of the distance and are in set mode
			if (end_set_scroll == true) {
				this.stop_animaiton();
				
				//this.display_center_bookmark_details();
	        
				// If the scroller was playing before we did the set animation, set it moving again.
				this.scroll_mode = 'paused';
				if (this.playing == true) {
					this.play_mode();
				}
			}
		}
		
		return true;
	},
	
	get_x_pos: function (obj)
	{
		var curleft = 0;
		if (obj.offsetParent)
		{
			while (obj.offsetParent)
			{
				curleft += obj.offsetLeft
				obj = obj.offsetParent;
			}
		}
		else if (obj.x)
			curleft += obj.x;
		return curleft;
	}
}

ScrollerSet = Class.create();
ScrollerSet.prototype = {
	initialize: function(set_id, set_data) {
		this.tags_url = '/tags/';
		this.avatar_url = '';
		this.people_url = '/people/';
	
		this.xpos = null;
		this.bookmarks = $A(set_data);
		this.set_id = set_id;
		this.ul_id = 'set_' + this.set_id;
		this.ul = null;
		
		this.build_ul();
	},
	
	// Build the the ul of screenshots.
	build_ul: function() {
		// Check that the ul doesn't already exist in the dom.
		if ($(this.ul_id)) {
			// If it does, use it
			this.ul = $(this.ul_id);
		} else {
			// Otherwise build one
			var ul = document.createElement('ul');
			ul.setAttribute('id', this.ul_id);
			ul.setAttribute('class', 'first_set');
			ul.style.display = 'none';
		
			this.bookmarks.each(function(bmark, index) {
				var li = document.createElement('li');
				li.innerHTML = bmark.Image;
				/*var a = document.createElement('a');
				a.setAttribute('href', bmark.url);
				var span = document.createElement('div');
				div.setAttribute('id', this.li_id(index));
				div.setAttribute('class', 'menuitem');
				div.innerHTML = bmark.Image;
				//div.innerHTML = '<img src="../Images/products/prodDkChoc_on.jpg">';
				a.appendChild(div);
				li.appendChild(a);*/
				ul.appendChild(li);
			}.bind(this));
			
			this.ul = ul;
		}
	},
	
//	set_event_handlers: function() {
//		this.bookmarks.each(function(bmark, index) {
//			Event.observe(this.li_id(index), 'mouseover', this.hover_over_bookmark.bindAsEventListener(this));
//			Event.observe(this.li_id(index), 'mouseout', this.hover_off_bookmark.bindAsEventListener(this));
//			Event.observe(this.li_id(index), 'click', this.click_bookmark.bindAsEventListener(this));
//		}.bind(this));
//	},
	
//	click_bookmark: function(event) {
//		Event.element(event).blur();
//		theScroller.set_selected_bookmark(Event.element(event));
		// Pause the scroller when clicking a link
//		theScroller.paused = false;
//		theScroller.pause_mode();
//	},
	
//	hover_off_bookmark: function(event) {
//		Event.element(event).style.border = 'solid 1px #fff';
//	},

//	hover_over_bookmark: function(event) {
//		var li = Event.element(event);
//		li.style.border = 'solid 1px #c36520';
//		this.show_bookmark_details(li.id.split('_')[2]*1);
//	},
	
/*	show_bookmark_details: function(bmark_id) {
		// Set the h3 link title and href
		var a = $('scroller_status').getElementsByTagName('h3')[0].firstChild;
		a.innerHTML = this.bookmarks[bmark_id]["title"].truncate(60);
		a.href = this.bookmarks[bmark_id]["url"];
		
		// Set tags
		var tags_html = "";
		this.bookmarks[bmark_id]["tags"].each(function(tag, index) {
			tags_html += "<a href=\"" + this.tags_url + tag.gsub(' ', '+') + "\">" + tag + "</a>";
            switch (this.bookmarks[bmark_id]["tags"].length - index){
                case 1 : 
                break
                case 2 :
                    tags_html += " or ";
                break
                case 3 :
                    tags_html += ", ";
                break
            }
		}.bind(this));
		
		if(this.bookmarks[bmark_id]["tags"].length > 0){		
    		$('scroller_tags').innerHTML =  "Find more about <span>" + tags_html + "</span>";
		}else{
		    $('scroller_tags').innerHTML = "";
		}
		// Author details
		$('last_linker').innerHTML = "<a href=\"" + this.people_url + this.bookmarks[bmark_id]["screen_name"] + "\" title=\"" + this.bookmarks[bmark_id]["owner"] + "\">" + this.bookmarks[bmark_id]["owner"] + "</a>";
	},
*/	
	// Move the set to a new location (by changing its ul left attribute), also display the ul if this is the first time set_position has been called.
	set_position: function(new_pos) {
		this.ul.style.left = new_pos + 'px';
	
		if (this.xpos == null) {
			Element.show(this.ul);
		}
		
		this.xpos = new_pos;
	},
	
	hide_me: function() {
		this.xpos = null;
		Element.hide(this.ul);
	},
	
	li_id: function(index) {
		return 'bmark_' + this.set_id + '_' + index
	}
}