var ssg = {};

ssg.Scroller = new Class({
    Implements: [Options,Events],

    options: {
        addMouseEvents:true,
        scrollSpeed:30,
        pauseBetween:false,
        pauseBetweenLength: 1000
        /*onStart:$empty()*/
    },

    timer: null,
    running: false,

    initialize: function (scrollerContainer, direction, options) {
        this.setOptions(options);
        this.scrollerContainer = $(scrollerContainer);

        if (!this.scrollerContainer) {
            return;
        }

        this.scrollerContainer.setStyles({'left':'0','top':'0'});

        if (direction === 'horizontal') {
            this.direction = 'left';
        } else {
            this.direction = 'top'
        }

        if (this.options.addMouseEvents) {
            this.scrollerContainer.addEvents({
                'mouseover':this.mouseStop.bind(this),
                'mouseout':this.mouseStart.bind(this)
            });
        }

        /*
        absolutely position the children means that can use block level elements in the scroller
        run through all the children and reset the direction value
        */
        var totalElementSize = this.setElementPositions();

        /*
        if for some reason the scroller container is larger than the elements
        inside then clone the elements so that it loops and doesnt look like a marquee
        */
        if (totalElementSize < (this.direction == 'left' ? this.scrollerContainer.getWidth():this.scrollerContainer.getHeight())) {
            this.cloneScrollElements();
        }

        this.fireEvent('start');
        
        this.start();
    },

    setElementPositions: function() {
        var currentPosition = 0;
        this.scrollerContainer.getChildren().each(function(el) {
            el.setStyle(this.direction,currentPosition);
            currentPosition += this.getRealSize(el);
        }, this);
        return currentPosition;
    },

    cloneScrollElements: function() {
        this.scrollerContainer.getChildren().each(function(el) {
            el.clone().inject(this.scrollerContainer, 'bottom');            
        }, this);

        // set the new positioning on the children and see if we need anymore
        if (this.setElementPositions() < (this.direction == 'left' ? this.scrollerContainer.getWidth():this.scrollerContainer.getHeight())) {
            this.cloneScrollElements();
        }        
    },

    start: function() {
        if (!this.running) {
            $clear(this.timer);
            this.running = true;
            this.timer = this.scroll.periodical(this.options.scrollSpeed, this);
        }
    },

    stop: function() {
        $clear(this.timer);
        this.running = false;
    },

    mouseStop: function() {
        this.stop();
    },

    mouseStart: function() {
        this.start();    
    },

    toggleOnOff: function() {
        if (this.running) {
            this.stop();
        } else {
            this.start();
        }
    },

    scroll: function() {
        // the first element is the current one being moved out of view so get first child and work out size
        var currentElement = this.scrollerContainer.getFirst();
        var currentElementSize = this.getRealSize(currentElement);

        /*
         if the container has a - position value that is the same size as the first element inside
         then the element is out of view so take it and move it to the end and carry on scrolling
         else scroll the container by 1px
        */
        if (this.scrollerContainer.getStyle(this.direction).toInt() === (0 - currentElementSize)) {
            var pos = 0;

            /*
             need to reset all the position values of all the children.
             each child will need to have the size of the element at the front that has
             just gone out of view - from its current position value

             the element going out of view will be moved to the bottom of the container and
             its position value set to the total of all the children in front
            */
            this.scrollerContainer.getChildren().each(function(el) {
                if (el !== currentElement) {
                    el.setStyle(this.direction, (el.getStyle(this.direction).toInt() - currentElementSize));
                    pos += this.getRealSize(el);
                }
            }, this);

            // move element just gone out of view to bottom of container
            currentElement.inject(this.scrollerContainer, 'bottom');
            currentElement.setStyle(this.direction,pos);

            // reset the controller position to 0 and start moving the next element out of view
            this.scrollerContainer.setStyle(this.direction,'0');

            if (this.options.pauseBetween) {
                this.stop();
                this.timer = this.start.delay(this.options.pauseBetweenLength, this);
            }
        } else {
            // first element still in view so just move the container out by 1px
            this.scrollerContainer.setStyle(this.direction,(this.scrollerContainer.getStyle(this.direction).toInt() - 1));
        }
    },

    // will return the size + any margin on a child element that is to be scrolled
    getRealSize: function(el) {
        if (this.direction === 'left') {
            return el.getWidth() + el.getStyle('margin-right').toInt();
        } else {
            return el.getHeight() + el.getStyle('margin-bottom').toInt();
        }
    }
})