var vScroller = new Class({
    Extends: Scroller,

    options: {
        area: 20,
        velocity: 1,
        onChange: function(x, y) {
            this.element.scrollTo(x, y);
        },
        listener: null
    },

    // Extended with an option to specify a listener instead of the default element
    initialize: function(element, options) {
        this.setOptions(options);
        this.element = $(element);
        this.listener = this.options.listener;
        if (!this.listener) 
            this.listener = ($type(this.element) != 'element') ? $(this.element.getDocument().body) : this.element;
    },

    // Extended to ignore the y coordinate
    scroll: function() {
       var size = this.element.getSize(), scroll = this.element.getScroll(), pos = this.element.getPosition(), change = {'x': 0};
       if (this.page.x < (this.options.area + pos.x) && scroll.x != 0)
           change.x = (this.page.x - this.options.area - pos.x) * this.options.velocity;
       else if (this.page.x + this.options.area > (size.x + pos.x) && size.x + size.x != scroll.x)
           change.x = (this.page.x - size.x + this.options.area - pos.x) * this.options.velocity;
       if (change.x) this.fireEvent('onChange', [scroll.x + change.x]);
    }
});

var vCarousel = new Class({
    Implements: [Events, Options],

    options: {
        'slider': null,
        onProgress: $empty,
        onPreload: $empty,
        onComplete: $empty
    },

    reflect: function(asset, options) {
        options = $extend({
            'height': this.container.getSize().y.toInt() - asset.height,
            'opacity': '0.6'
        }, options || {});

        var canvas;
        if (Browser.Engine.trident) {
            canvas = new Element('img', {'src': asset.src, 'styles': {
                'width': asset.width,
                'filter': 'flipv progid:DXImageTransform.Microsoft.Alpha(opacity=' + (options.opacity * 100) + ', style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy=' + ((100 / asset.height) * options.height) + ')'
            }});
        } else {
           canvas = new Element('canvas', {'styles': {'width': asset.width, 'height': options.height}});
           if (!canvas.getContext) return;
        }

        if (Browser.Engine.trident) return canvas;

        var context = canvas.setProperties({'width': asset.width, 'height': options.height}).getContext('2d');
        context.save();
        context.translate(0, asset.height - 1);
        context.scale(1, -1);
        context.drawImage(asset, 0, 0, asset.width, asset.height);
        context.restore();
        context.globalCompositeOperation = 'destination-out';
        var gradient = context.createLinearGradient(0, 0, 0, options.height);
        gradient.addColorStop(0, 'rgba(255, 255, 255, '+ (1 - options.opacity ) + ')');
        gradient.addColorStop(1, 'rgba(255, 255, 255, 1.0)');
        context.fillStyle = gradient;
        context.rect(0, 0, asset.width, options.height);
        context.fill();

        return canvas
    },
    
    initialize: function(list, options) {
        this.setOptions(options);

        this.list = $(list);
        this.container = this.list.getParent();
        this.listener = this.container.getParent();
        
        this.container.setStyle('overflow', 'hidden').scrollTo(0, 0);
       
        var images = this.list.getElements('li img');
        var sources = images.map(function(image) { return image.src; });
                      images.each(function(image) { image.remove() });
        var items = this.list.getChildren();

        var t = this;
        var assets = Asset.images(sources, {
            onProgress: function(counter, index) {
                this.fireEvent('onProgress', [counter + 1, sources.length]);
            }.bind(t),
            onComplete: function() {
                assets.each(function (asset, index) {
                    var wrapper = new Element('div', {'class': 'image', 'styles': {'opacity': '0.0'}}).adopt(asset);
                    items[index].adopt(wrapper);
                    
                    var r = this.reflect(asset);
                    r.setStyles({
                        'position': 'absolute',
                        'top': asset.height,
                        'left': wrapper.getStyle('padding-left').toInt()
                    }); 
                    
                    if (images[index].getProperty('title')) {
                        asset.setProperty('title', images[index].getProperty('title')); // Prepended by an _ to prevent the browser from displaying it
                    };
                    

                    wrapper.setStyles({'overflow': 'hidden', 'height': this.container.getSize().y.toInt()}).adopt(r);
                }, this);

                this.fireEvent('onPreload');

                assets.each(function(asset) {
                    asset.getParent().fade('in', {'duration': 'long'});
                }); 

               
               var last = list.getLast();
               var size = last.getPosition(list).x + (last.getStyle('width').toInt() - last.getFirst().getStyle('padding-right').toInt());
               list.setStyle('width', size);

                this.scroller = new vScroller(this.container, {
                    'area': Math.floor(this.container.getSize().x / 6),
                    'velocity': 0.1,
                    'listener': this.listener,
                    onChange: function(x) {
                        this.container.scrollTo(x, 0);
                        if (this.slider)
                            this.slider.set(x);
                    }.bind(this)
                }, this);
                this.scroller.start();
                this.listener.addEvent('mouseenter', this.scroller.start.bind(this.scroller))
                             .addEvent('mouseleave', this.scroller.stop.bind(this.scroller));

                this.options.slider.options = $merge({
                    'steps': this.list.getSize().x - this.container.getSize().x,
                    onChange: function(x) { 
                        this.container.scrollTo(x);
                    }.bind(this)
                }, this.options.slider.options);
                if ($type(this.options.slider) != 'nothing')
                    this.slider = new Slider(this.options.slider.element, this.options.slider.knob, this.options.slider.options);

                this.fireEvent('onComplete');
            }.bind(t)
        });
    },

    scrollTo: function(x) {
        this.container.scrollTo(x, 0);
    },

    scrollPrevious: function() {
        // TODO
    }
});
