var $dom = YAHOO.util.Dom;
var $ = $dom.get;
var $class = $dom.getElementsByClassName;

// Function to automactially look for and start scrollers on
// the page.
var auto_scrollers = {
    init: function() {
	    this.scrollers = [];                                                                                                                                     
	    var containers = $class('scroll-container', 'div');
	    for(var i=0, item; item=containers[i]; i++) {
	        var alignment = 'horizontal';
	        if($dom.hasClass(item, 'vertical-scroller')) {
	            alignment = 'vertical';
	        }
	        this.scrollers[i] = new Scroller(item, alignment);
	        if (item.id) {
	            // The scroll layer has an Id so lets look for 
	            // controls for it.
	            
	            //Start and Stop Controls
	            var control = $(item.id+'-scroll-start')
	            if (control) {
         	        YAHOO.util.Event.addListener(control, 'click', function() {this.start();}, this.scrollers[i], true);
	            }
	            control = $(item.id+'-scroll-stop')
	            if (control) {
         	        YAHOO.util.Event.addListener(control, 'click', function() {this.stop();}, this.scrollers[i], true);
	            }
                
                if(alignment == 'vertical') {
    	            // Manual up and down Scrolls
    	            control = $(item.id+'-scroll-up')
    	            if (control) {
             	        YAHOO.util.Event.addListener(control, 'mouseover', function() {this.scroll_up();}, this.scrollers[i], true);
    	                YAHOO.util.Event.addListener(control, 'mouseout', function() {this.resume_original_scroll();}, this.scrollers[i], true);
    	                YAHOO.util.Event.addListener(control, 'click', function(e) {YAHOO.util.Event.preventDefault(e);});
    	            }
    	            control = $(item.id+'-scroll-down')
    	            if (control) {
             	        YAHOO.util.Event.addListener(control, 'mouseover', function() {this.scroll_down();}, this.scrollers[i], true);
    	                YAHOO.util.Event.addListener(control, 'mouseout', function() {this.resume_original_scroll();}, this.scrollers[i], true);
                        YAHOO.util.Event.addListener(control, 'click', function(e) {YAHOO.util.Event.preventDefault(e);});
    	            }                    
                } else {
    	            // Manual left and right Scrolls
    	            control = $(item.id+'-scroll-left')
    	            if (control) {
             	        YAHOO.util.Event.addListener(control, 'mouseover', function() {this.scroll_left();}, this.scrollers[i], true);
    	                YAHOO.util.Event.addListener(control, 'mouseout', function() {this.resume_original_scroll();}, this.scrollers[i], true);
    	                YAHOO.util.Event.addListener(control, 'click', function(e) {YAHOO.util.Event.preventDefault(e);});
    	            }
    	            control = $(item.id+'-scroll-right')
    	            if (control) {
             	        YAHOO.util.Event.addListener(control, 'mouseover', function() {this.scroll_right();}, this.scrollers[i], true);
    	                YAHOO.util.Event.addListener(control, 'mouseout', function() {this.resume_original_scroll();}, this.scrollers[i], true);
    	                YAHOO.util.Event.addListener(control, 'click', function(e) {YAHOO.util.Event.preventDefault(e);});
    	            }
    	        }
	        }
	    }
    }
};

Scroller = function(scroll_container, alignment, speed, pause) {
    if (scroll_container) {
        this.init(scroll_container, alignment, speed, pause); 
    }
};

// Main scroller object
Scroller.prototype = {  
    init: function(scroll_container, alignment, speed, pause) {
        // initial/default values for scroller
        var default_speed = -1;
        var default_alignment = 'horizontal'
        this.pause = pause || 20; // how long to pause between moves in milliseconds
        this.start_offset = 0; // should it start right at the edge of the container (the default) or offset
        this.pause_on_mouseover = true;
        
        
        this.set_alignment(alignment, default_alignment);
        this.set_speed(speed, default_speed);      
        this.container = scroll_container; 
        this.container_region = $dom.getRegion(this.container);
        this.scroller = $class('scroller', 'div', this.container)[0];
        this.run_scroller = true;
        
        this.set_dimensions_position();
        this.set_move_point();

        if (this.speed_positive) {
            //Starting the positioning at the right or bottom of the container
            this.current_placement = (this.container_position + this.container_dimension) - this.start_offset;
        } else {
            //Starting placement is at the left or top
            this.current_placement = this.container_position + this.start_offset;;
        } 
        
        this.initialize_scroller();

        this.manual_scroll_active = false;
        this.scroll(this.speed);
    },

    set_alignment: function(alignment, default_alignment) {
        if (alignment) {
            alignment = alignment.toLowerCase();
        } else {
            alignment = default_alignment;
        }
        
        if ( alignment == 'vertical') {
            this.horizontal = false;
        } else {
            this.horizontal = true;
        }
    },

    set_speed: function(speed, default_speed) {
        this.speed = speed || default_speed;
        if (this.speed > 0) {
            this.speed_positive = true;   
        } else {
            this.speed_positive = false;
        }
        this.normal_speed = this.speed;
    },
          
    set_dimensions_position: function() { 
        var scroller_region = $dom.getRegion(this.scroller);
	    if (this.horizontal) {
	        this.container_dimension = this.container_region['right'] - this.container_region['left'];
	        this.container_position = this.container_region['left'];
	        this.scroller_dimension = scroller_region['right'] - scroller_region['left'];
	        this.scroller_position = scroller_region['left'];
	    } else {
	        this.container_dimension = this.container_region['bottom'] - this.container_region['top'];
	        this.container_position = this.container_region['top'];
	        this.scroller_dimension = scroller_region['bottom'] - scroller_region['top'];
	        this.scroller_position = scroller_region['top'];
	    }
    },


    set_move_point: function() {
        if (this.horizontal) {
            //horizontal
            if (this.speed_positive) {
                this.move_point = this.container_region['right'];
            } else {
                this.move_point = this.container_region['left'];
            }   
        } else {
            // vertical alignment
            if (this.speed_positive) {
                this.move_point = this.container_region['bottom'];
            } else {
                this.move_point = this.container_region['top'];
            }
        }
    },
      
    initialize_scroller: function() {
        this.scroller_elements = [];
        this.scroller_order = [];
        var size = 0;
        var item_counter = 0;
        var dom_scroller_elements = $class('scroller-element', '',this.scroller);
        var this_obj = this;
        
        // If the scroll container is larger than all the scroll elements
        // start repeating scroll elements, this always runs through at 
        // least once unless the scroll container dimensions are 0    
        while (this.container_dimension > size) {
            // Checking to see if we've already been through the loop
            // once as we then need to copy the elements instead of 
            // just placing them
            if (item_counter > 0) {
                var copy_elements = true;
            } else {
                var copy_elements = false;
            }
           
            for(var i=0, scroll_element; scroll_element=dom_scroller_elements[i]; i++) {              
         	    var item;
         	    if (copy_elements) {
         	        item = scroll_element.cloneNode(true);
              	    $dom.insertAfter(item, this.scroller_elements[this.scroller_elements.length -1]['el'])         	        
         	    } else {
         	        item = scroll_element;
         	    }
         	    $dom.setStyle(item, 'position', 'absolute');
         	    
         	    if(this.pause_on_mouseover) {
         	        YAHOO.util.Event.addListener(item, 'mouseover', function() {this.stop();}, this_obj, true)
         	        YAHOO.util.Event.addListener(item, 'mouseout', function() {this.start();}, this_obj, true)
         	    }
         	    
         	    var region = $dom.getRegion(item);
                if (this.horizontal) {
        	        var dimension = region['right'] - region['left'];
                    //$dom.setStyle(item, 'width', dimension+'px');
                } else {
                    var dimension = region['bottom'] - region['top'];
        	        //$dom.setStyle(item, 'height', dimension);  
                }
                
                if (this.speed_positive) {
                    this.current_placement -=  dimension;
        	        if (this.horizontal) {
            	        $dom.setX(item, this.current_placement);
                    } else {
                        $dom.setY(item, this.current_placement);
                    }
                    this.scroller_order.unshift(item_counter);
                } else {
                    if (this.horizontal) {
            	        $dom.setX(item, this.current_placement);
                    } else {
                        $dom.setY(item, this.current_placement);
                    }
                    this.current_placement += dimension;
                    this.scroller_order.push(item_counter);
                }
    	        size += dimension;
    	        this.set_scroller_dimension(dimension)
    	        this.scroller_elements[item_counter] = {'el': item, 'dimension': dimension};
                $dom.setStyle(item, 'visibility', 'visible');
                item_counter++;
	        }
	    }
        this.scroller_element_count = this.scroller_elements.length;
	},

    set_scroller_dimension: function(size) {
	    this.scroller_dimension += size;
	    if (this.horizontal) {
	        $dom.setStyle(this.scroller, 'width', this.scroller_dimension+'px');
	    } else {
    	    $dom.setStyle(this.scroller, 'height', this.scroller_dimension+'px'); 
	    }        
    },
    
    scroll: function(speed) {
        var element_moved = false;
        //Checking to make sure we should be scrolling
        if(this.run_scroller) {
            this.scroller_position += speed;
            if(this.horizontal) {
                $dom.setX(this.scroller, this.scroller_position);
            } else {
                $dom.setY(this.scroller, this.scroller_position)
            }
            
            if (this.speed_positive) {
      	        var item = this.scroller_elements[this.scroller_order[this.scroller_element_count - 1]];
      	    } else {
      	        var item = this.scroller_elements[this.scroller_order[0]]
      	    }
            
            var position = this.get_position(item); 
            var element_moved = false;
            
            if (this.speed_positive) {
                if (position > this.move_point) {
                    this.positive_move(item);
                    element_moved = true;
                }
            } else {
                if (position < this.move_point) {
                    this.negative_move(item);
                    element_moved = true;
                }
      	    }
      	    
      	    // Setting the new scroll elements to check only if an scroll element
      	    // was moved
      	    if (element_moved) {
      	        if (this.speed_positive) {
      	            var j = this.scroller_order.pop();
      	            this.scroller_order.unshift(j);
      	        } else {
      	            var j = this.scroller_order.shift();
      	            this.scroller_order.push(j);
      	        }
      	    }
      	    
      	    if(!this.manual_scroll_active) {
                var thisObj = this; 
                setTimeout(function(){ thisObj.scroll(speed) }, this.pause);
            }
       }
    },

    get_position: function(item) {
        if (this.speed_positive) {
            if (this.horizontal) {
                return $dom.getX(item['el']);
            } else {
                return $dom.getY(item['el']);
            }
        } else {
            if (this.horizontal) {
                return $dom.getX(item['el']) + item['dimension'];
            } else {
                // for some reason have to add the height twice for safari to get it to 
                // move when the bottom of the item disappears
                return $dom.getY(item['el']) + item['dimension'] + item['dimension'];
            }
        }
    },

    positive_move: function(item) {
        // Del Is this even needed??
        this.set_scroller_dimension(item['dimension']);

        if (this.horizontal) {
		    var move_to = $dom.getX(this.scroller_elements[this.scroller_order[0]]['el']) - item['dimension'];
            $dom.setX(item['el'], move_to);
            //$dom.setStyle(item['el'], 'width', item['dimension']+'px');
        } else {
		    var move_to = $dom.getY(this.scroller_elements[this.scroller_order[0]]['el']) - item['dimension'];
            $dom.setY(item['el'], move_to);
            //$dom.setStyle(item['el'], 'height', item['dimension']);
        } 
    },

    negative_move: function(item) {
        // Del Is this even needed??
        this.set_scroller_dimension(item['dimension']);

        if (this.horizontal) {
		    var move_to = $dom.getX(this.scroller_elements[this.scroller_order[this.scroller_element_count - 1]]['el']) + this.scroller_elements[this.scroller_order[this.scroller_element_count - 1]]['dimension'];
            $dom.setX(item['el'], move_to);
            //$dom.setStyle(item['el'], 'width', item['dimension']);
        } else {
		    var move_to = $dom.getY(this.scroller_elements[this.scroller_order[this.scroller_element_count - 1]]['el']) + this.scroller_elements[this.scroller_order[this.scroller_element_count - 1]]['dimension'];
            $dom.setY(item['el'], move_to);
            //$dom.setStyle(item['el'], 'height', item['dimension']);
        }    
    },

    scroll_up: function(speed) { 
        this.scroll_left(speed);    
    },
    
    scroll_down: function(speed) { 
        this.scroll_right(speed);    
    },
        
    scroll_left: function(speed) {
        this.manual_scroll_active = true;
        speed = speed || this.speed * 3;
        speed = Math.abs(speed) * -1;
        this.change_speed(speed);
        this.manual_scroll(speed);
    },

    scroll_right: function(speed) {
        this.manual_scroll_active = true;
        speed = speed || this.speed * 3;
        speed = Math.abs(speed);
        this.change_speed(speed);
        this.manual_scroll(speed);       
    },

    change_speed: function(speed) {
        speed = speed || this.normal_speed;
        // Checking for a change in direction
        var direction_change = false;
        if ((this.speed < 0 && speed > 0) || (this.speed > 0 && speed < 0) ) {
            direction_change = true;
        }
        this.speed = speed;
        if (this.speed > 0) {
            this.speed_positive = true;   
        } else {
            this.speed_positive = false;
        } 
        if (direction_change) {
            this.change_direction();
        }       
    },
    
    change_direction: function() {
        //Setting the move point for the new direction
        this.set_move_point();
        var original_order = this.scroller_order.slice();
        
        if (this.speed_positive) {
            // switching from a negative speed to a positive speed
            for(var i=(this.scroller_element_count - 1); i >= 0; i--) {
                var item = this.scroller_elements[original_order[i]]
                var position = this.get_position(item); 

                if (position > this.move_point) {
                    this.positive_move(item);
                    var moved_item = this.scroller_order.pop();
                    this.scroller_order.unshift(moved_item)
                }
            }
        } else {
            // switching from a positive speed to a negative speed
            for(var i= 0; i < this.scroller_element_count; i++) {
                var item = this.scroller_elements[original_order[i]]
                var position = this.get_position(item); 
                
                if (position < this.move_point) {
                    this.negative_move(item);
                    var moved_item = this.scroller_order.shift();
                    this.scroller_order.push(moved_item)
                    
                }
      	    }
        }
    },
    
    manual_scroll: function(speed) {
        if(this.manual_scroll_active) {
            if(speed == this.speed) {
                // Checking to make sure the direction hasn't changed since
                // this was called with the setTimeout method last.
                this.scroll(speed);
                var thisObj = this; 
                setTimeout(function(){ thisObj.manual_scroll(speed) }, this.pause);
            }
        }
    },
    
    resume_original_scroll: function() {
        this.manual_scroll_active = false;
        this.change_speed(); //setting the speed and direction back to the original values
        this.scroll(this.normal_speed);
    },
    
    stop: function() {
        this.run_scroller = false;
    },

    start: function() {
        if (! this.run_scroller) {
            // Only need to run these if the scroller is stopped
            this.run_scroller = true;
            this.scroll(this.normal_speed);
        }
    }
};
YAHOO.util.Event.addListener(window, 'load', auto_scrollers.init);
 