with (ScrollerNode = function(html) {
    this.html = html;
    ScrollerNode.nodes.push(this);
}) {
    prototype.html = '';
    prototype.displayed = false;
    prototype.domEl = null;
    prototype.extEl = null;
    prototype.id = null;

    prototype.showAt = function(domContainer, animate) {
        animate = typeof animate == 'undefined' ? true : animate;
        if (this.displayed) {
            return;
        }

        if (this.extEl) {
            if (this.displayed) {
                this.extEl.remove();
            }
            delete this.extEl;
        }

        if (!this.extEl && this.html) {
            this.extEl = Ext.get(domContainer).insertHtml('afterBegin', this.html, true);
            this.extEl.setStyle({
                display: 'none'
            });
            this.id = this.extEl.id;
            this.displayed = true;
        } else {
            return;
        }

        if (animate) {
            this.extEl.setStyle({
                visibility: 'hidden',
                height: 0,
                display: 'block'
            });

            var self = this;
            this.extEl.animate({
                height: {to: 150}
                },
                1,
                function() {
                    self.extEl.setStyle({
                        visibility: 'visible'
                    });
                    self.extEl.animate(
                        // animation control object
                        {
                            opacity: {to: 1, from: .1}
                        },
                        0.8,      // animation duration
                        null,      // callback
                        'easeOut', // easing method
                        'run'      // animation type ('run','color','motion','scroll')
                    );

                },
                'easeOut', // easing method
                'run'      // animation type ('run','color','motion','scroll')
            );
        } else {
            this.extEl.setStyle({
                display: 'block'
            });
        }
    }

    prototype.hideAt = function() {
        if (!this.displayed) {
            return;
        }

        if (this.extEl) {
            this.extEl.remove();
            this.displayed = false;
        }
    }
}

ScrollerNode.nodes = [];

ScrollerNode.getNode = function(domEl) {
    for (var i = 0; i < ScrollerNode.nodes.length; i++) {
        if (ScrollerNode.nodes[i].id == domEl.id) {
            return ScrollerNode.nodes[i];
        }
    }
    return null;
}

with (Scroller = function(element, data, size) {
    this.domEl = element;
    this.extEl = new Ext.Element(element);
    this.extEl.clean();
    this.scrollableElements = this.getNodes(data);
    this.scrollerSize = size;

}) {
    prototype.extEl = null;
    prototype.domEl = null;
    prototype.scrollableElements = null;
    prototype.currentElement = 0;
    prototype.scrollerSize = 10;
    prototype.startCount = 3; // element to show immediatelly

    prototype.getNodes = function(data) {
        var nodes = [];
        for (var i = 0; i < data.length; i++) {
            nodes.push(new ScrollerNode(data[i]));
        }

        return nodes;
    };

    prototype.showNode = function(n, animate) {
        animate = typeof animate == 'undefined' ? true : animate;
        if (this.domEl && this.scrollableElements[n]) {
            this.scrollableElements[n].showAt(this.domEl, animate);
        }
    };

    prototype.hideNode = function (animate) {
        animate = typeof animate == 'undefined' ? true : animate;
        var c = this.domEl.childNodes[this.domEl.childNodes.length - 1];
        var sn = ScrollerNode.getNode(c);
        if (sn) {
            var callback = function() {
                sn.hideAt();
            };
        } else {
            var self = this;
            var callback = function() {
                Ext.get(self.domEl).last().remove();
            }
        }
        if (animate) {
            Ext.get(this.domEl).last().animate(
                // animation control object
                {
                    opacity: {to: .1, from: 1}
                },
                0.8,      // animation duration
                callback,      // callback
                'easeOut', // easing method
                'run'      // animation type ('run','color','motion','scroll')
            );
        } else {
            callback(); // remove element without animation
        }
    }

    prototype.scrollNext = function(animate) {
        animate = typeof animate == 'undefined' ? true : animate;
        if (this.domEl.childNodes.length >= this.scrollerSize) {
            this.hideNode(animate);
        }
        this.showNode(this.currentElement++, animate);
        if (this.currentElement >= this.scrollableElements.length) {
            this.currentElement = 0;
        }
    };

    prototype.run = function() {
        for (var i = 0; i < this.startCount; i++) {
            this.scrollNext(false);
        }
        setInterval(this.scrollNext.createDelegate(this), 3000);
    }
}
